Commit | Line | Data |
---|---|---|
43aa3132 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
68a2d20b HZ |
2 | /* |
3 | * Copyright (c) 2012, Microsoft Corporation. | |
4 | * | |
5 | * Author: | |
6 | * Haiyang Zhang <haiyangz@microsoft.com> | |
68a2d20b HZ |
7 | */ |
8 | ||
9 | /* | |
10 | * Hyper-V Synthetic Video Frame Buffer Driver | |
11 | * | |
12 | * This is the driver for the Hyper-V Synthetic Video, which supports | |
13 | * screen resolution up to Full HD 1920x1080 with 32 bit color on Windows | |
14 | * Server 2012, and 1600x1200 with 16 bit color on Windows Server 2008 R2 | |
15 | * or earlier. | |
16 | * | |
17 | * It also solves the double mouse cursor issue of the emulated video mode. | |
18 | * | |
19 | * The default screen resolution is 1152x864, which may be changed by a | |
20 | * kernel parameter: | |
21 | * video=hyperv_fb:<width>x<height> | |
22 | * For example: video=hyperv_fb:1280x1024 | |
23 | * | |
24 | * Portrait orientation is also supported: | |
25 | * For example: video=hyperv_fb:864x1152 | |
67e7cdb4 WH |
26 | * |
27 | * When a Windows 10 RS5+ host is used, the virtual machine screen | |
28 | * resolution is obtained from the host. The "video=hyperv_fb" option is | |
29 | * not needed, but still can be used to overwrite what the host specifies. | |
30 | * The VM resolution on the host could be set by executing the powershell | |
31 | * "set-vmvideo" command. For example | |
32 | * set-vmvideo -vmname name -horizontalresolution:1920 \ | |
33 | * -verticalresolution:1200 -resolutiontype single | |
3a6fb6c4 WH |
34 | * |
35 | * Gen 1 VMs also support direct using VM's physical memory for framebuffer. | |
36 | * It could improve the efficiency and performance for framebuffer and VM. | |
37 | * This requires to allocate contiguous physical memory from Linux kernel's | |
38 | * CMA memory allocator. To enable this, supply a kernel parameter to give | |
39 | * enough memory space to CMA allocator for framebuffer. For example: | |
40 | * cma=130m | |
41 | * This gives 130MB memory to CMA allocator that can be allocated to | |
42 | * framebuffer. For reference, 8K resolution (7680x4320) takes about | |
43 | * 127MB memory. | |
68a2d20b HZ |
44 | */ |
45 | ||
46 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
47 | ||
8d69d008 | 48 | #include <linux/aperture.h> |
68a2d20b HZ |
49 | #include <linux/module.h> |
50 | #include <linux/kernel.h> | |
34a28083 | 51 | #include <linux/vmalloc.h> |
68a2d20b HZ |
52 | #include <linux/init.h> |
53 | #include <linux/completion.h> | |
54 | #include <linux/fb.h> | |
55 | #include <linux/pci.h> | |
f39650de | 56 | #include <linux/panic_notifier.h> |
9069fd54 | 57 | #include <linux/efi.h> |
1ecf3020 | 58 | #include <linux/console.h> |
68a2d20b HZ |
59 | |
60 | #include <linux/hyperv.h> | |
61 | ||
62 | ||
63 | /* Hyper-V Synthetic Video Protocol definitions and structures */ | |
64 | #define MAX_VMBUS_PKT_SIZE 0x4000 | |
65 | ||
66 | #define SYNTHVID_VERSION(major, minor) ((minor) << 16 | (major)) | |
b0cce4f6 | 67 | /* Support for VERSION_WIN7 is removed. #define is retained for reference. */ |
68a2d20b HZ |
68 | #define SYNTHVID_VERSION_WIN7 SYNTHVID_VERSION(3, 0) |
69 | #define SYNTHVID_VERSION_WIN8 SYNTHVID_VERSION(3, 2) | |
67e7cdb4 WH |
70 | #define SYNTHVID_VERSION_WIN10 SYNTHVID_VERSION(3, 5) |
71 | ||
72 | #define SYNTHVID_VER_GET_MAJOR(ver) (ver & 0x0000ffff) | |
73 | #define SYNTHVID_VER_GET_MINOR(ver) ((ver & 0xffff0000) >> 16) | |
68a2d20b | 74 | |
68a2d20b | 75 | #define SYNTHVID_DEPTH_WIN8 32 |
68a2d20b HZ |
76 | #define SYNTHVID_FB_SIZE_WIN8 (8 * 1024 * 1024) |
77 | ||
78 | #define PCI_VENDOR_ID_MICROSOFT 0x1414 | |
79 | #define PCI_DEVICE_ID_HYPERV_VIDEO 0x5353 | |
80 | ||
81 | ||
82 | enum pipe_msg_type { | |
83 | PIPE_MSG_INVALID, | |
84 | PIPE_MSG_DATA, | |
85 | PIPE_MSG_MAX | |
86 | }; | |
87 | ||
88 | struct pipe_msg_hdr { | |
89 | u32 type; | |
90 | u32 size; /* size of message after this field */ | |
91 | } __packed; | |
92 | ||
93 | ||
94 | enum synthvid_msg_type { | |
95 | SYNTHVID_ERROR = 0, | |
96 | SYNTHVID_VERSION_REQUEST = 1, | |
97 | SYNTHVID_VERSION_RESPONSE = 2, | |
98 | SYNTHVID_VRAM_LOCATION = 3, | |
99 | SYNTHVID_VRAM_LOCATION_ACK = 4, | |
100 | SYNTHVID_SITUATION_UPDATE = 5, | |
101 | SYNTHVID_SITUATION_UPDATE_ACK = 6, | |
102 | SYNTHVID_POINTER_POSITION = 7, | |
103 | SYNTHVID_POINTER_SHAPE = 8, | |
104 | SYNTHVID_FEATURE_CHANGE = 9, | |
105 | SYNTHVID_DIRT = 10, | |
67e7cdb4 WH |
106 | SYNTHVID_RESOLUTION_REQUEST = 13, |
107 | SYNTHVID_RESOLUTION_RESPONSE = 14, | |
68a2d20b | 108 | |
67e7cdb4 | 109 | SYNTHVID_MAX = 15 |
68a2d20b HZ |
110 | }; |
111 | ||
67e7cdb4 WH |
112 | #define SYNTHVID_EDID_BLOCK_SIZE 128 |
113 | #define SYNTHVID_MAX_RESOLUTION_COUNT 64 | |
114 | ||
115 | struct hvd_screen_info { | |
116 | u16 width; | |
117 | u16 height; | |
118 | } __packed; | |
119 | ||
68a2d20b HZ |
120 | struct synthvid_msg_hdr { |
121 | u32 type; | |
122 | u32 size; /* size of this header + payload after this field*/ | |
123 | } __packed; | |
124 | ||
68a2d20b HZ |
125 | struct synthvid_version_req { |
126 | u32 version; | |
127 | } __packed; | |
128 | ||
129 | struct synthvid_version_resp { | |
130 | u32 version; | |
131 | u8 is_accepted; | |
132 | u8 max_video_outputs; | |
133 | } __packed; | |
134 | ||
67e7cdb4 WH |
135 | struct synthvid_supported_resolution_req { |
136 | u8 maximum_resolution_count; | |
137 | } __packed; | |
138 | ||
139 | struct synthvid_supported_resolution_resp { | |
140 | u8 edid_block[SYNTHVID_EDID_BLOCK_SIZE]; | |
141 | u8 resolution_count; | |
142 | u8 default_resolution_index; | |
143 | u8 is_standard; | |
144 | struct hvd_screen_info | |
145 | supported_resolution[SYNTHVID_MAX_RESOLUTION_COUNT]; | |
146 | } __packed; | |
147 | ||
68a2d20b HZ |
148 | struct synthvid_vram_location { |
149 | u64 user_ctx; | |
150 | u8 is_vram_gpa_specified; | |
151 | u64 vram_gpa; | |
152 | } __packed; | |
153 | ||
154 | struct synthvid_vram_location_ack { | |
155 | u64 user_ctx; | |
156 | } __packed; | |
157 | ||
158 | struct video_output_situation { | |
159 | u8 active; | |
160 | u32 vram_offset; | |
161 | u8 depth_bits; | |
162 | u32 width_pixels; | |
163 | u32 height_pixels; | |
164 | u32 pitch_bytes; | |
165 | } __packed; | |
166 | ||
167 | struct synthvid_situation_update { | |
168 | u64 user_ctx; | |
169 | u8 video_output_count; | |
170 | struct video_output_situation video_output[1]; | |
171 | } __packed; | |
172 | ||
173 | struct synthvid_situation_update_ack { | |
174 | u64 user_ctx; | |
175 | } __packed; | |
176 | ||
177 | struct synthvid_pointer_position { | |
178 | u8 is_visible; | |
179 | u8 video_output; | |
180 | s32 image_x; | |
181 | s32 image_y; | |
182 | } __packed; | |
183 | ||
184 | ||
185 | #define CURSOR_MAX_X 96 | |
186 | #define CURSOR_MAX_Y 96 | |
187 | #define CURSOR_ARGB_PIXEL_SIZE 4 | |
188 | #define CURSOR_MAX_SIZE (CURSOR_MAX_X * CURSOR_MAX_Y * CURSOR_ARGB_PIXEL_SIZE) | |
189 | #define CURSOR_COMPLETE (-1) | |
190 | ||
191 | struct synthvid_pointer_shape { | |
192 | u8 part_idx; | |
193 | u8 is_argb; | |
194 | u32 width; /* CURSOR_MAX_X at most */ | |
195 | u32 height; /* CURSOR_MAX_Y at most */ | |
196 | u32 hot_x; /* hotspot relative to upper-left of pointer image */ | |
197 | u32 hot_y; | |
198 | u8 data[4]; | |
199 | } __packed; | |
200 | ||
201 | struct synthvid_feature_change { | |
202 | u8 is_dirt_needed; | |
203 | u8 is_ptr_pos_needed; | |
204 | u8 is_ptr_shape_needed; | |
205 | u8 is_situ_needed; | |
206 | } __packed; | |
207 | ||
208 | struct rect { | |
209 | s32 x1, y1; /* top left corner */ | |
210 | s32 x2, y2; /* bottom right corner, exclusive */ | |
211 | } __packed; | |
212 | ||
213 | struct synthvid_dirt { | |
214 | u8 video_output; | |
215 | u8 dirt_count; | |
216 | struct rect rect[1]; | |
217 | } __packed; | |
218 | ||
219 | struct synthvid_msg { | |
220 | struct pipe_msg_hdr pipe_hdr; | |
221 | struct synthvid_msg_hdr vid_hdr; | |
222 | union { | |
223 | struct synthvid_version_req ver_req; | |
224 | struct synthvid_version_resp ver_resp; | |
225 | struct synthvid_vram_location vram; | |
226 | struct synthvid_vram_location_ack vram_ack; | |
227 | struct synthvid_situation_update situ; | |
228 | struct synthvid_situation_update_ack situ_ack; | |
229 | struct synthvid_pointer_position ptr_pos; | |
230 | struct synthvid_pointer_shape ptr_shape; | |
231 | struct synthvid_feature_change feature_chg; | |
232 | struct synthvid_dirt dirt; | |
67e7cdb4 WH |
233 | struct synthvid_supported_resolution_req resolution_req; |
234 | struct synthvid_supported_resolution_resp resolution_resp; | |
68a2d20b HZ |
235 | }; |
236 | } __packed; | |
237 | ||
238 | ||
68a2d20b HZ |
239 | /* FB driver definitions and structures */ |
240 | #define HVFB_WIDTH 1152 /* default screen width */ | |
241 | #define HVFB_HEIGHT 864 /* default screen height */ | |
242 | #define HVFB_WIDTH_MIN 640 | |
243 | #define HVFB_HEIGHT_MIN 480 | |
244 | ||
245 | #define RING_BUFSIZE (256 * 1024) | |
246 | #define VSP_TIMEOUT (10 * HZ) | |
247 | #define HVFB_UPDATE_DELAY (HZ / 20) | |
d21987d7 | 248 | #define HVFB_ONDEMAND_THROTTLE (HZ / 20) |
68a2d20b HZ |
249 | |
250 | struct hvfb_par { | |
251 | struct fb_info *info; | |
35464483 | 252 | struct resource *mem; |
68a2d20b HZ |
253 | bool fb_ready; /* fb device is ready */ |
254 | struct completion wait; | |
255 | u32 synthvid_version; | |
256 | ||
257 | struct delayed_work dwork; | |
258 | bool update; | |
1ecf3020 | 259 | bool update_saved; /* The value of 'update' before hibernation */ |
68a2d20b HZ |
260 | |
261 | u32 pseudo_palette[16]; | |
262 | u8 init_buf[MAX_VMBUS_PKT_SIZE]; | |
263 | u8 recv_buf[MAX_VMBUS_PKT_SIZE]; | |
3686fe96 DC |
264 | |
265 | /* If true, the VSC notifies the VSP on every framebuffer change */ | |
266 | bool synchronous_fb; | |
267 | ||
3a6fb6c4 WH |
268 | /* If true, need to copy from deferred IO mem to framebuffer mem */ |
269 | bool need_docopy; | |
270 | ||
3686fe96 | 271 | struct notifier_block hvfb_panic_nb; |
d21987d7 WH |
272 | |
273 | /* Memory for deferred IO and frame buffer itself */ | |
274 | unsigned char *dio_vp; | |
275 | unsigned char *mmio_vp; | |
3a6fb6c4 | 276 | phys_addr_t mmio_pp; |
d21987d7 WH |
277 | |
278 | /* Dirty rectangle, protected by delayed_refresh_lock */ | |
279 | int x1, y1, x2, y2; | |
280 | bool delayed_refresh; | |
281 | spinlock_t delayed_refresh_lock; | |
68a2d20b HZ |
282 | }; |
283 | ||
284 | static uint screen_width = HVFB_WIDTH; | |
285 | static uint screen_height = HVFB_HEIGHT; | |
286 | static uint screen_depth; | |
287 | static uint screen_fb_size; | |
d21987d7 | 288 | static uint dio_fb_size; /* FB size for deferred IO */ |
68a2d20b HZ |
289 | |
290 | /* Send message to Hyper-V host */ | |
291 | static inline int synthvid_send(struct hv_device *hdev, | |
292 | struct synthvid_msg *msg) | |
293 | { | |
294 | static atomic64_t request_id = ATOMIC64_INIT(0); | |
295 | int ret; | |
296 | ||
297 | msg->pipe_hdr.type = PIPE_MSG_DATA; | |
298 | msg->pipe_hdr.size = msg->vid_hdr.size; | |
299 | ||
300 | ret = vmbus_sendpacket(hdev->channel, msg, | |
301 | msg->vid_hdr.size + sizeof(struct pipe_msg_hdr), | |
302 | atomic64_inc_return(&request_id), | |
303 | VM_PKT_DATA_INBAND, 0); | |
304 | ||
305 | if (ret) | |
aa5b7d11 | 306 | pr_err_ratelimited("Unable to send packet via vmbus; error %d\n", ret); |
68a2d20b HZ |
307 | |
308 | return ret; | |
309 | } | |
310 | ||
311 | ||
312 | /* Send screen resolution info to host */ | |
313 | static int synthvid_send_situ(struct hv_device *hdev) | |
314 | { | |
315 | struct fb_info *info = hv_get_drvdata(hdev); | |
316 | struct synthvid_msg msg; | |
317 | ||
318 | if (!info) | |
319 | return -ENODEV; | |
320 | ||
321 | memset(&msg, 0, sizeof(struct synthvid_msg)); | |
322 | ||
323 | msg.vid_hdr.type = SYNTHVID_SITUATION_UPDATE; | |
324 | msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) + | |
325 | sizeof(struct synthvid_situation_update); | |
326 | msg.situ.user_ctx = 0; | |
327 | msg.situ.video_output_count = 1; | |
328 | msg.situ.video_output[0].active = 1; | |
329 | msg.situ.video_output[0].vram_offset = 0; | |
330 | msg.situ.video_output[0].depth_bits = info->var.bits_per_pixel; | |
331 | msg.situ.video_output[0].width_pixels = info->var.xres; | |
332 | msg.situ.video_output[0].height_pixels = info->var.yres; | |
333 | msg.situ.video_output[0].pitch_bytes = info->fix.line_length; | |
334 | ||
335 | synthvid_send(hdev, &msg); | |
336 | ||
337 | return 0; | |
338 | } | |
339 | ||
340 | /* Send mouse pointer info to host */ | |
341 | static int synthvid_send_ptr(struct hv_device *hdev) | |
342 | { | |
343 | struct synthvid_msg msg; | |
344 | ||
345 | memset(&msg, 0, sizeof(struct synthvid_msg)); | |
346 | msg.vid_hdr.type = SYNTHVID_POINTER_POSITION; | |
347 | msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) + | |
348 | sizeof(struct synthvid_pointer_position); | |
349 | msg.ptr_pos.is_visible = 1; | |
350 | msg.ptr_pos.video_output = 0; | |
351 | msg.ptr_pos.image_x = 0; | |
352 | msg.ptr_pos.image_y = 0; | |
353 | synthvid_send(hdev, &msg); | |
354 | ||
355 | memset(&msg, 0, sizeof(struct synthvid_msg)); | |
356 | msg.vid_hdr.type = SYNTHVID_POINTER_SHAPE; | |
357 | msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) + | |
358 | sizeof(struct synthvid_pointer_shape); | |
359 | msg.ptr_shape.part_idx = CURSOR_COMPLETE; | |
360 | msg.ptr_shape.is_argb = 1; | |
361 | msg.ptr_shape.width = 1; | |
362 | msg.ptr_shape.height = 1; | |
363 | msg.ptr_shape.hot_x = 0; | |
364 | msg.ptr_shape.hot_y = 0; | |
365 | msg.ptr_shape.data[0] = 0; | |
366 | msg.ptr_shape.data[1] = 1; | |
367 | msg.ptr_shape.data[2] = 1; | |
368 | msg.ptr_shape.data[3] = 1; | |
369 | synthvid_send(hdev, &msg); | |
370 | ||
371 | return 0; | |
372 | } | |
373 | ||
374 | /* Send updated screen area (dirty rectangle) location to host */ | |
d21987d7 WH |
375 | static int |
376 | synthvid_update(struct fb_info *info, int x1, int y1, int x2, int y2) | |
68a2d20b HZ |
377 | { |
378 | struct hv_device *hdev = device_to_hv_device(info->device); | |
379 | struct synthvid_msg msg; | |
380 | ||
381 | memset(&msg, 0, sizeof(struct synthvid_msg)); | |
d21987d7 WH |
382 | if (x2 == INT_MAX) |
383 | x2 = info->var.xres; | |
384 | if (y2 == INT_MAX) | |
385 | y2 = info->var.yres; | |
68a2d20b HZ |
386 | |
387 | msg.vid_hdr.type = SYNTHVID_DIRT; | |
388 | msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) + | |
389 | sizeof(struct synthvid_dirt); | |
390 | msg.dirt.video_output = 0; | |
391 | msg.dirt.dirt_count = 1; | |
d21987d7 WH |
392 | msg.dirt.rect[0].x1 = (x1 > x2) ? 0 : x1; |
393 | msg.dirt.rect[0].y1 = (y1 > y2) ? 0 : y1; | |
394 | msg.dirt.rect[0].x2 = | |
395 | (x2 < x1 || x2 > info->var.xres) ? info->var.xres : x2; | |
396 | msg.dirt.rect[0].y2 = | |
397 | (y2 < y1 || y2 > info->var.yres) ? info->var.yres : y2; | |
68a2d20b HZ |
398 | |
399 | synthvid_send(hdev, &msg); | |
400 | ||
401 | return 0; | |
402 | } | |
403 | ||
d21987d7 WH |
404 | static void hvfb_docopy(struct hvfb_par *par, |
405 | unsigned long offset, | |
406 | unsigned long size) | |
407 | { | |
408 | if (!par || !par->mmio_vp || !par->dio_vp || !par->fb_ready || | |
409 | size == 0 || offset >= dio_fb_size) | |
410 | return; | |
411 | ||
412 | if (offset + size > dio_fb_size) | |
413 | size = dio_fb_size - offset; | |
414 | ||
415 | memcpy(par->mmio_vp + offset, par->dio_vp + offset, size); | |
416 | } | |
417 | ||
418 | /* Deferred IO callback */ | |
e80eec1b | 419 | static void synthvid_deferred_io(struct fb_info *p, struct list_head *pagereflist) |
d21987d7 WH |
420 | { |
421 | struct hvfb_par *par = p->par; | |
56c134f7 | 422 | struct fb_deferred_io_pageref *pageref; |
d21987d7 WH |
423 | unsigned long start, end; |
424 | int y1, y2, miny, maxy; | |
425 | ||
426 | miny = INT_MAX; | |
427 | maxy = 0; | |
428 | ||
429 | /* | |
430 | * Merge dirty pages. It is possible that last page cross | |
431 | * over the end of frame buffer row yres. This is taken care of | |
432 | * in synthvid_update function by clamping the y2 | |
433 | * value to yres. | |
434 | */ | |
e80eec1b | 435 | list_for_each_entry(pageref, pagereflist, list) { |
e2d8b428 | 436 | start = pageref->offset; |
d21987d7 WH |
437 | end = start + PAGE_SIZE - 1; |
438 | y1 = start / p->fix.line_length; | |
439 | y2 = end / p->fix.line_length; | |
440 | miny = min_t(int, miny, y1); | |
441 | maxy = max_t(int, maxy, y2); | |
442 | ||
443 | /* Copy from dio space to mmio address */ | |
3a6fb6c4 | 444 | if (par->fb_ready && par->need_docopy) |
d21987d7 WH |
445 | hvfb_docopy(par, start, PAGE_SIZE); |
446 | } | |
447 | ||
448 | if (par->fb_ready && par->update) | |
449 | synthvid_update(p, 0, miny, p->var.xres, maxy + 1); | |
450 | } | |
451 | ||
452 | static struct fb_deferred_io synthvid_defio = { | |
453 | .delay = HZ / 20, | |
454 | .deferred_io = synthvid_deferred_io, | |
455 | }; | |
68a2d20b HZ |
456 | |
457 | /* | |
458 | * Actions on received messages from host: | |
459 | * Complete the wait event. | |
460 | * Or, reply with screen and cursor info. | |
461 | */ | |
462 | static void synthvid_recv_sub(struct hv_device *hdev) | |
463 | { | |
464 | struct fb_info *info = hv_get_drvdata(hdev); | |
465 | struct hvfb_par *par; | |
466 | struct synthvid_msg *msg; | |
467 | ||
468 | if (!info) | |
469 | return; | |
470 | ||
471 | par = info->par; | |
472 | msg = (struct synthvid_msg *)par->recv_buf; | |
473 | ||
474 | /* Complete the wait event */ | |
475 | if (msg->vid_hdr.type == SYNTHVID_VERSION_RESPONSE || | |
67e7cdb4 | 476 | msg->vid_hdr.type == SYNTHVID_RESOLUTION_RESPONSE || |
68a2d20b HZ |
477 | msg->vid_hdr.type == SYNTHVID_VRAM_LOCATION_ACK) { |
478 | memcpy(par->init_buf, msg, MAX_VMBUS_PKT_SIZE); | |
479 | complete(&par->wait); | |
480 | return; | |
481 | } | |
482 | ||
483 | /* Reply with screen and cursor info */ | |
484 | if (msg->vid_hdr.type == SYNTHVID_FEATURE_CHANGE) { | |
485 | if (par->fb_ready) { | |
486 | synthvid_send_ptr(hdev); | |
487 | synthvid_send_situ(hdev); | |
488 | } | |
489 | ||
490 | par->update = msg->feature_chg.is_dirt_needed; | |
491 | if (par->update) | |
492 | schedule_delayed_work(&par->dwork, HVFB_UPDATE_DELAY); | |
493 | } | |
494 | } | |
495 | ||
496 | /* Receive callback for messages from the host */ | |
497 | static void synthvid_receive(void *ctx) | |
498 | { | |
499 | struct hv_device *hdev = ctx; | |
500 | struct fb_info *info = hv_get_drvdata(hdev); | |
501 | struct hvfb_par *par; | |
502 | struct synthvid_msg *recv_buf; | |
503 | u32 bytes_recvd; | |
504 | u64 req_id; | |
505 | int ret; | |
506 | ||
507 | if (!info) | |
508 | return; | |
509 | ||
510 | par = info->par; | |
511 | recv_buf = (struct synthvid_msg *)par->recv_buf; | |
512 | ||
513 | do { | |
514 | ret = vmbus_recvpacket(hdev->channel, recv_buf, | |
515 | MAX_VMBUS_PKT_SIZE, | |
516 | &bytes_recvd, &req_id); | |
517 | if (bytes_recvd > 0 && | |
518 | recv_buf->pipe_hdr.type == PIPE_MSG_DATA) | |
519 | synthvid_recv_sub(hdev); | |
520 | } while (bytes_recvd > 0 && ret == 0); | |
521 | } | |
522 | ||
67e7cdb4 WH |
523 | /* Check if the ver1 version is equal or greater than ver2 */ |
524 | static inline bool synthvid_ver_ge(u32 ver1, u32 ver2) | |
525 | { | |
526 | if (SYNTHVID_VER_GET_MAJOR(ver1) > SYNTHVID_VER_GET_MAJOR(ver2) || | |
527 | (SYNTHVID_VER_GET_MAJOR(ver1) == SYNTHVID_VER_GET_MAJOR(ver2) && | |
528 | SYNTHVID_VER_GET_MINOR(ver1) >= SYNTHVID_VER_GET_MINOR(ver2))) | |
529 | return true; | |
530 | ||
531 | return false; | |
532 | } | |
533 | ||
68a2d20b HZ |
534 | /* Check synthetic video protocol version with the host */ |
535 | static int synthvid_negotiate_ver(struct hv_device *hdev, u32 ver) | |
536 | { | |
537 | struct fb_info *info = hv_get_drvdata(hdev); | |
538 | struct hvfb_par *par = info->par; | |
539 | struct synthvid_msg *msg = (struct synthvid_msg *)par->init_buf; | |
7dea97e0 NMG |
540 | int ret = 0; |
541 | unsigned long t; | |
68a2d20b HZ |
542 | |
543 | memset(msg, 0, sizeof(struct synthvid_msg)); | |
544 | msg->vid_hdr.type = SYNTHVID_VERSION_REQUEST; | |
545 | msg->vid_hdr.size = sizeof(struct synthvid_msg_hdr) + | |
546 | sizeof(struct synthvid_version_req); | |
547 | msg->ver_req.version = ver; | |
548 | synthvid_send(hdev, msg); | |
549 | ||
550 | t = wait_for_completion_timeout(&par->wait, VSP_TIMEOUT); | |
551 | if (!t) { | |
552 | pr_err("Time out on waiting version response\n"); | |
553 | ret = -ETIMEDOUT; | |
554 | goto out; | |
555 | } | |
556 | if (!msg->ver_resp.is_accepted) { | |
557 | ret = -ENODEV; | |
558 | goto out; | |
559 | } | |
560 | ||
561 | par->synthvid_version = ver; | |
67e7cdb4 WH |
562 | pr_info("Synthvid Version major %d, minor %d\n", |
563 | SYNTHVID_VER_GET_MAJOR(ver), SYNTHVID_VER_GET_MINOR(ver)); | |
564 | ||
565 | out: | |
566 | return ret; | |
567 | } | |
568 | ||
569 | /* Get current resolution from the host */ | |
570 | static int synthvid_get_supported_resolution(struct hv_device *hdev) | |
571 | { | |
572 | struct fb_info *info = hv_get_drvdata(hdev); | |
573 | struct hvfb_par *par = info->par; | |
574 | struct synthvid_msg *msg = (struct synthvid_msg *)par->init_buf; | |
575 | int ret = 0; | |
576 | unsigned long t; | |
577 | u8 index; | |
67e7cdb4 WH |
578 | |
579 | memset(msg, 0, sizeof(struct synthvid_msg)); | |
580 | msg->vid_hdr.type = SYNTHVID_RESOLUTION_REQUEST; | |
581 | msg->vid_hdr.size = sizeof(struct synthvid_msg_hdr) + | |
582 | sizeof(struct synthvid_supported_resolution_req); | |
583 | ||
584 | msg->resolution_req.maximum_resolution_count = | |
585 | SYNTHVID_MAX_RESOLUTION_COUNT; | |
586 | synthvid_send(hdev, msg); | |
587 | ||
588 | t = wait_for_completion_timeout(&par->wait, VSP_TIMEOUT); | |
589 | if (!t) { | |
590 | pr_err("Time out on waiting resolution response\n"); | |
366c5aa1 CIK |
591 | ret = -ETIMEDOUT; |
592 | goto out; | |
67e7cdb4 WH |
593 | } |
594 | ||
595 | if (msg->resolution_resp.resolution_count == 0) { | |
596 | pr_err("No supported resolutions\n"); | |
597 | ret = -ENODEV; | |
598 | goto out; | |
599 | } | |
600 | ||
601 | index = msg->resolution_resp.default_resolution_index; | |
602 | if (index >= msg->resolution_resp.resolution_count) { | |
603 | pr_err("Invalid resolution index: %d\n", index); | |
604 | ret = -ENODEV; | |
605 | goto out; | |
606 | } | |
607 | ||
67e7cdb4 WH |
608 | screen_width = |
609 | msg->resolution_resp.supported_resolution[index].width; | |
610 | screen_height = | |
611 | msg->resolution_resp.supported_resolution[index].height; | |
68a2d20b HZ |
612 | |
613 | out: | |
614 | return ret; | |
615 | } | |
616 | ||
617 | /* Connect to VSP (Virtual Service Provider) on host */ | |
618 | static int synthvid_connect_vsp(struct hv_device *hdev) | |
619 | { | |
620 | struct fb_info *info = hv_get_drvdata(hdev); | |
621 | struct hvfb_par *par = info->par; | |
622 | int ret; | |
623 | ||
624 | ret = vmbus_open(hdev->channel, RING_BUFSIZE, RING_BUFSIZE, | |
625 | NULL, 0, synthvid_receive, hdev); | |
626 | if (ret) { | |
627 | pr_err("Unable to open vmbus channel\n"); | |
628 | return ret; | |
629 | } | |
630 | ||
631 | /* Negotiate the protocol version with host */ | |
67e7cdb4 WH |
632 | switch (vmbus_proto_version) { |
633 | case VERSION_WIN10: | |
634 | case VERSION_WIN10_V5: | |
635 | ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN10); | |
636 | if (!ret) | |
637 | break; | |
df561f66 | 638 | fallthrough; |
67e7cdb4 WH |
639 | case VERSION_WIN8: |
640 | case VERSION_WIN8_1: | |
68a2d20b | 641 | ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN8); |
67e7cdb4 WH |
642 | break; |
643 | default: | |
644 | ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN10); | |
645 | break; | |
646 | } | |
68a2d20b HZ |
647 | |
648 | if (ret) { | |
649 | pr_err("Synthetic video device version not accepted\n"); | |
650 | goto error; | |
651 | } | |
652 | ||
b0cce4f6 | 653 | screen_depth = SYNTHVID_DEPTH_WIN8; |
67e7cdb4 WH |
654 | if (synthvid_ver_ge(par->synthvid_version, SYNTHVID_VERSION_WIN10)) { |
655 | ret = synthvid_get_supported_resolution(hdev); | |
656 | if (ret) | |
657 | pr_info("Failed to get supported resolution from host, use default\n"); | |
658 | } | |
659 | ||
9069fd54 GH |
660 | screen_fb_size = hdev->channel->offermsg.offer. |
661 | mmio_megabytes * 1024 * 1024; | |
68a2d20b HZ |
662 | |
663 | return 0; | |
664 | ||
665 | error: | |
666 | vmbus_close(hdev->channel); | |
667 | return ret; | |
668 | } | |
669 | ||
670 | /* Send VRAM and Situation messages to the host */ | |
671 | static int synthvid_send_config(struct hv_device *hdev) | |
672 | { | |
673 | struct fb_info *info = hv_get_drvdata(hdev); | |
674 | struct hvfb_par *par = info->par; | |
675 | struct synthvid_msg *msg = (struct synthvid_msg *)par->init_buf; | |
7dea97e0 NMG |
676 | int ret = 0; |
677 | unsigned long t; | |
68a2d20b HZ |
678 | |
679 | /* Send VRAM location */ | |
680 | memset(msg, 0, sizeof(struct synthvid_msg)); | |
681 | msg->vid_hdr.type = SYNTHVID_VRAM_LOCATION; | |
682 | msg->vid_hdr.size = sizeof(struct synthvid_msg_hdr) + | |
683 | sizeof(struct synthvid_vram_location); | |
d21987d7 | 684 | msg->vram.user_ctx = msg->vram.vram_gpa = par->mmio_pp; |
68a2d20b HZ |
685 | msg->vram.is_vram_gpa_specified = 1; |
686 | synthvid_send(hdev, msg); | |
687 | ||
688 | t = wait_for_completion_timeout(&par->wait, VSP_TIMEOUT); | |
689 | if (!t) { | |
690 | pr_err("Time out on waiting vram location ack\n"); | |
691 | ret = -ETIMEDOUT; | |
692 | goto out; | |
693 | } | |
d21987d7 | 694 | if (msg->vram_ack.user_ctx != par->mmio_pp) { |
68a2d20b HZ |
695 | pr_err("Unable to set VRAM location\n"); |
696 | ret = -ENODEV; | |
697 | goto out; | |
698 | } | |
699 | ||
700 | /* Send pointer and situation update */ | |
701 | synthvid_send_ptr(hdev); | |
702 | synthvid_send_situ(hdev); | |
703 | ||
704 | out: | |
705 | return ret; | |
706 | } | |
707 | ||
708 | ||
709 | /* | |
710 | * Delayed work callback: | |
d21987d7 WH |
711 | * It is scheduled to call whenever update request is received and it has |
712 | * not been called in last HVFB_ONDEMAND_THROTTLE time interval. | |
68a2d20b HZ |
713 | */ |
714 | static void hvfb_update_work(struct work_struct *w) | |
715 | { | |
716 | struct hvfb_par *par = container_of(w, struct hvfb_par, dwork.work); | |
717 | struct fb_info *info = par->info; | |
d21987d7 WH |
718 | unsigned long flags; |
719 | int x1, x2, y1, y2; | |
720 | int j; | |
721 | ||
722 | spin_lock_irqsave(&par->delayed_refresh_lock, flags); | |
723 | /* Reset the request flag */ | |
724 | par->delayed_refresh = false; | |
725 | ||
726 | /* Store the dirty rectangle to local variables */ | |
727 | x1 = par->x1; | |
728 | x2 = par->x2; | |
729 | y1 = par->y1; | |
730 | y2 = par->y2; | |
731 | ||
732 | /* Clear dirty rectangle */ | |
733 | par->x1 = par->y1 = INT_MAX; | |
734 | par->x2 = par->y2 = 0; | |
735 | ||
736 | spin_unlock_irqrestore(&par->delayed_refresh_lock, flags); | |
737 | ||
738 | if (x1 > info->var.xres || x2 > info->var.xres || | |
739 | y1 > info->var.yres || y2 > info->var.yres || x2 <= x1) | |
740 | return; | |
741 | ||
742 | /* Copy the dirty rectangle to frame buffer memory */ | |
3a6fb6c4 WH |
743 | if (par->need_docopy) |
744 | for (j = y1; j < y2; j++) | |
745 | hvfb_docopy(par, | |
746 | j * info->fix.line_length + | |
747 | (x1 * screen_depth / 8), | |
748 | (x2 - x1) * screen_depth / 8); | |
d21987d7 WH |
749 | |
750 | /* Refresh */ | |
751 | if (par->fb_ready && par->update) | |
752 | synthvid_update(info, x1, y1, x2, y2); | |
753 | } | |
68a2d20b | 754 | |
d21987d7 WH |
755 | /* |
756 | * Control the on-demand refresh frequency. It schedules a delayed | |
757 | * screen update if it has not yet. | |
758 | */ | |
759 | static void hvfb_ondemand_refresh_throttle(struct hvfb_par *par, | |
760 | int x1, int y1, int w, int h) | |
761 | { | |
762 | unsigned long flags; | |
763 | int x2 = x1 + w; | |
764 | int y2 = y1 + h; | |
765 | ||
766 | spin_lock_irqsave(&par->delayed_refresh_lock, flags); | |
767 | ||
768 | /* Merge dirty rectangle */ | |
769 | par->x1 = min_t(int, par->x1, x1); | |
770 | par->y1 = min_t(int, par->y1, y1); | |
771 | par->x2 = max_t(int, par->x2, x2); | |
772 | par->y2 = max_t(int, par->y2, y2); | |
773 | ||
774 | /* Schedule a delayed screen update if not yet */ | |
775 | if (par->delayed_refresh == false) { | |
776 | schedule_delayed_work(&par->dwork, | |
777 | HVFB_ONDEMAND_THROTTLE); | |
778 | par->delayed_refresh = true; | |
779 | } | |
68a2d20b | 780 | |
d21987d7 | 781 | spin_unlock_irqrestore(&par->delayed_refresh_lock, flags); |
68a2d20b HZ |
782 | } |
783 | ||
3686fe96 DC |
784 | static int hvfb_on_panic(struct notifier_block *nb, |
785 | unsigned long e, void *p) | |
786 | { | |
787 | struct hvfb_par *par; | |
788 | struct fb_info *info; | |
789 | ||
790 | par = container_of(nb, struct hvfb_par, hvfb_panic_nb); | |
791 | par->synchronous_fb = true; | |
792 | info = par->info; | |
3a6fb6c4 WH |
793 | if (par->need_docopy) |
794 | hvfb_docopy(par, 0, dio_fb_size); | |
d21987d7 | 795 | synthvid_update(info, 0, 0, INT_MAX, INT_MAX); |
3686fe96 DC |
796 | |
797 | return NOTIFY_DONE; | |
798 | } | |
68a2d20b HZ |
799 | |
800 | /* Framebuffer operation handlers */ | |
801 | ||
802 | static int hvfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | |
803 | { | |
804 | if (var->xres < HVFB_WIDTH_MIN || var->yres < HVFB_HEIGHT_MIN || | |
805 | var->xres > screen_width || var->yres > screen_height || | |
806 | var->bits_per_pixel != screen_depth) | |
807 | return -EINVAL; | |
808 | ||
809 | var->xres_virtual = var->xres; | |
810 | var->yres_virtual = var->yres; | |
811 | ||
812 | return 0; | |
813 | } | |
814 | ||
815 | static int hvfb_set_par(struct fb_info *info) | |
816 | { | |
817 | struct hv_device *hdev = device_to_hv_device(info->device); | |
818 | ||
819 | return synthvid_send_situ(hdev); | |
820 | } | |
821 | ||
822 | ||
823 | static inline u32 chan_to_field(u32 chan, struct fb_bitfield *bf) | |
824 | { | |
825 | return ((chan & 0xffff) >> (16 - bf->length)) << bf->offset; | |
826 | } | |
827 | ||
828 | static int hvfb_setcolreg(unsigned regno, unsigned red, unsigned green, | |
829 | unsigned blue, unsigned transp, struct fb_info *info) | |
830 | { | |
831 | u32 *pal = info->pseudo_palette; | |
832 | ||
833 | if (regno > 15) | |
834 | return -EINVAL; | |
835 | ||
836 | pal[regno] = chan_to_field(red, &info->var.red) | |
837 | | chan_to_field(green, &info->var.green) | |
838 | | chan_to_field(blue, &info->var.blue) | |
839 | | chan_to_field(transp, &info->var.transp); | |
840 | ||
841 | return 0; | |
842 | } | |
843 | ||
9b5254b4 GH |
844 | static int hvfb_blank(int blank, struct fb_info *info) |
845 | { | |
846 | return 1; /* get fb_blank to set the colormap to all black */ | |
847 | } | |
68a2d20b | 848 | |
3686fe96 DC |
849 | static void hvfb_cfb_fillrect(struct fb_info *p, |
850 | const struct fb_fillrect *rect) | |
851 | { | |
852 | struct hvfb_par *par = p->par; | |
853 | ||
854 | cfb_fillrect(p, rect); | |
855 | if (par->synchronous_fb) | |
d21987d7 WH |
856 | synthvid_update(p, 0, 0, INT_MAX, INT_MAX); |
857 | else | |
858 | hvfb_ondemand_refresh_throttle(par, rect->dx, rect->dy, | |
859 | rect->width, rect->height); | |
3686fe96 DC |
860 | } |
861 | ||
862 | static void hvfb_cfb_copyarea(struct fb_info *p, | |
863 | const struct fb_copyarea *area) | |
864 | { | |
865 | struct hvfb_par *par = p->par; | |
866 | ||
867 | cfb_copyarea(p, area); | |
868 | if (par->synchronous_fb) | |
d21987d7 WH |
869 | synthvid_update(p, 0, 0, INT_MAX, INT_MAX); |
870 | else | |
871 | hvfb_ondemand_refresh_throttle(par, area->dx, area->dy, | |
872 | area->width, area->height); | |
3686fe96 DC |
873 | } |
874 | ||
875 | static void hvfb_cfb_imageblit(struct fb_info *p, | |
876 | const struct fb_image *image) | |
877 | { | |
878 | struct hvfb_par *par = p->par; | |
879 | ||
880 | cfb_imageblit(p, image); | |
881 | if (par->synchronous_fb) | |
d21987d7 WH |
882 | synthvid_update(p, 0, 0, INT_MAX, INT_MAX); |
883 | else | |
884 | hvfb_ondemand_refresh_throttle(par, image->dx, image->dy, | |
885 | image->width, image->height); | |
3686fe96 DC |
886 | } |
887 | ||
8a48ac33 | 888 | static const struct fb_ops hvfb_ops = { |
68a2d20b HZ |
889 | .owner = THIS_MODULE, |
890 | .fb_check_var = hvfb_check_var, | |
891 | .fb_set_par = hvfb_set_par, | |
892 | .fb_setcolreg = hvfb_setcolreg, | |
3686fe96 DC |
893 | .fb_fillrect = hvfb_cfb_fillrect, |
894 | .fb_copyarea = hvfb_cfb_copyarea, | |
895 | .fb_imageblit = hvfb_cfb_imageblit, | |
9b5254b4 | 896 | .fb_blank = hvfb_blank, |
59055851 | 897 | .fb_mmap = fb_deferred_io_mmap, |
68a2d20b HZ |
898 | }; |
899 | ||
900 | ||
901 | /* Get options from kernel paramenter "video=" */ | |
902 | static void hvfb_get_option(struct fb_info *info) | |
903 | { | |
904 | struct hvfb_par *par = info->par; | |
905 | char *opt = NULL, *p; | |
906 | uint x = 0, y = 0; | |
907 | ||
908 | if (fb_get_options(KBUILD_MODNAME, &opt) || !opt || !*opt) | |
909 | return; | |
910 | ||
911 | p = strsep(&opt, "x"); | |
912 | if (!*p || kstrtouint(p, 0, &x) || | |
913 | !opt || !*opt || kstrtouint(opt, 0, &y)) { | |
914 | pr_err("Screen option is invalid: skipped\n"); | |
915 | return; | |
916 | } | |
917 | ||
918 | if (x < HVFB_WIDTH_MIN || y < HVFB_HEIGHT_MIN || | |
67e7cdb4 | 919 | (synthvid_ver_ge(par->synthvid_version, SYNTHVID_VERSION_WIN10) && |
9ff5549b | 920 | (x * y * screen_depth / 8 > screen_fb_size)) || |
68a2d20b | 921 | (par->synthvid_version == SYNTHVID_VERSION_WIN8 && |
b0cce4f6 | 922 | x * y * screen_depth / 8 > SYNTHVID_FB_SIZE_WIN8)) { |
68a2d20b HZ |
923 | pr_err("Screen resolution option is out of range: skipped\n"); |
924 | return; | |
925 | } | |
926 | ||
927 | screen_width = x; | |
928 | screen_height = y; | |
929 | return; | |
930 | } | |
931 | ||
3a6fb6c4 WH |
932 | /* |
933 | * Allocate enough contiguous physical memory. | |
934 | * Return physical address if succeeded or -1 if failed. | |
935 | */ | |
936 | static phys_addr_t hvfb_get_phymem(struct hv_device *hdev, | |
937 | unsigned int request_size) | |
938 | { | |
939 | struct page *page = NULL; | |
940 | dma_addr_t dma_handle; | |
941 | void *vmem; | |
942 | phys_addr_t paddr = 0; | |
943 | unsigned int order = get_order(request_size); | |
944 | ||
945 | if (request_size == 0) | |
946 | return -1; | |
947 | ||
948 | if (order < MAX_ORDER) { | |
949 | /* Call alloc_pages if the size is less than 2^MAX_ORDER */ | |
950 | page = alloc_pages(GFP_KERNEL | __GFP_ZERO, order); | |
951 | if (!page) | |
952 | return -1; | |
953 | ||
954 | paddr = (page_to_pfn(page) << PAGE_SHIFT); | |
955 | } else { | |
956 | /* Allocate from CMA */ | |
957 | hdev->device.coherent_dma_mask = DMA_BIT_MASK(64); | |
958 | ||
959 | vmem = dma_alloc_coherent(&hdev->device, | |
960 | round_up(request_size, PAGE_SIZE), | |
961 | &dma_handle, | |
962 | GFP_KERNEL | __GFP_NOWARN); | |
963 | ||
964 | if (!vmem) | |
965 | return -1; | |
966 | ||
967 | paddr = virt_to_phys(vmem); | |
968 | } | |
969 | ||
970 | return paddr; | |
971 | } | |
972 | ||
973 | /* Release contiguous physical memory */ | |
974 | static void hvfb_release_phymem(struct hv_device *hdev, | |
975 | phys_addr_t paddr, unsigned int size) | |
976 | { | |
977 | unsigned int order = get_order(size); | |
978 | ||
979 | if (order < MAX_ORDER) | |
980 | __free_pages(pfn_to_page(paddr >> PAGE_SHIFT), order); | |
981 | else | |
982 | dma_free_coherent(&hdev->device, | |
983 | round_up(size, PAGE_SIZE), | |
984 | phys_to_virt(paddr), | |
985 | paddr); | |
986 | } | |
987 | ||
68a2d20b HZ |
988 | |
989 | /* Get framebuffer memory from Hyper-V video pci space */ | |
35464483 | 990 | static int hvfb_getmem(struct hv_device *hdev, struct fb_info *info) |
68a2d20b | 991 | { |
9069fd54 GH |
992 | struct hvfb_par *par = info->par; |
993 | struct pci_dev *pdev = NULL; | |
68a2d20b | 994 | void __iomem *fb_virt; |
9069fd54 | 995 | int gen2vm = efi_enabled(EFI_BOOT); |
3a6fb6c4 | 996 | phys_addr_t paddr; |
9069fd54 | 997 | int ret; |
68a2d20b | 998 | |
3a6fb6c4 WH |
999 | info->apertures = alloc_apertures(1); |
1000 | if (!info->apertures) | |
1001 | return -ENOMEM; | |
d21987d7 | 1002 | |
3a6fb6c4 | 1003 | if (!gen2vm) { |
9069fd54 | 1004 | pdev = pci_get_device(PCI_VENDOR_ID_MICROSOFT, |
3a6fb6c4 | 1005 | PCI_DEVICE_ID_HYPERV_VIDEO, NULL); |
9069fd54 GH |
1006 | if (!pdev) { |
1007 | pr_err("Unable to find PCI Hyper-V video\n"); | |
1008 | return -ENODEV; | |
1009 | } | |
68a2d20b | 1010 | |
3a6fb6c4 WH |
1011 | info->apertures->ranges[0].base = pci_resource_start(pdev, 0); |
1012 | info->apertures->ranges[0].size = pci_resource_len(pdev, 0); | |
1013 | ||
1014 | /* | |
1015 | * For Gen 1 VM, we can directly use the contiguous memory | |
1016 | * from VM. If we succeed, deferred IO happens directly | |
1017 | * on this allocated framebuffer memory, avoiding extra | |
1018 | * memory copy. | |
1019 | */ | |
1020 | paddr = hvfb_get_phymem(hdev, screen_fb_size); | |
1021 | if (paddr != (phys_addr_t) -1) { | |
1022 | par->mmio_pp = paddr; | |
1023 | par->mmio_vp = par->dio_vp = __va(paddr); | |
1024 | ||
1025 | info->fix.smem_start = paddr; | |
1026 | info->fix.smem_len = screen_fb_size; | |
1027 | info->screen_base = par->mmio_vp; | |
1028 | info->screen_size = screen_fb_size; | |
1029 | ||
1030 | par->need_docopy = false; | |
1031 | goto getmem_done; | |
1032 | } | |
1033 | pr_info("Unable to allocate enough contiguous physical memory on Gen 1 VM. Using MMIO instead.\n"); | |
1034 | } else { | |
1035 | info->apertures->ranges[0].base = screen_info.lfb_base; | |
1036 | info->apertures->ranges[0].size = screen_info.lfb_size; | |
1037 | } | |
1038 | ||
1039 | /* | |
1040 | * Cannot use the contiguous physical memory. | |
1041 | * Allocate mmio space for framebuffer. | |
1042 | */ | |
1043 | dio_fb_size = | |
1044 | screen_width * screen_height * screen_depth / 8; | |
1045 | ||
c4b4d704 | 1046 | ret = vmbus_allocate_mmio(&par->mem, hdev, 0, -1, |
35464483 JO |
1047 | screen_fb_size, 0x100000, true); |
1048 | if (ret != 0) { | |
1049 | pr_err("Unable to allocate framebuffer memory\n"); | |
1050 | goto err1; | |
9069fd54 | 1051 | } |
68a2d20b | 1052 | |
5f1251a4 DC |
1053 | /* |
1054 | * Map the VRAM cacheable for performance. This is also required for | |
1055 | * VM Connect to display properly for ARM64 Linux VM, as the host also | |
1056 | * maps the VRAM cacheable. | |
1057 | */ | |
1058 | fb_virt = ioremap_cache(par->mem->start, screen_fb_size); | |
68a2d20b HZ |
1059 | if (!fb_virt) |
1060 | goto err2; | |
1061 | ||
d21987d7 WH |
1062 | /* Allocate memory for deferred IO */ |
1063 | par->dio_vp = vzalloc(round_up(dio_fb_size, PAGE_SIZE)); | |
1064 | if (par->dio_vp == NULL) | |
1065 | goto err3; | |
1066 | ||
d21987d7 WH |
1067 | /* Physical address of FB device */ |
1068 | par->mmio_pp = par->mem->start; | |
1069 | /* Virtual address of FB device */ | |
1070 | par->mmio_vp = (unsigned char *) fb_virt; | |
1071 | ||
35464483 | 1072 | info->fix.smem_start = par->mem->start; |
d21987d7 WH |
1073 | info->fix.smem_len = dio_fb_size; |
1074 | info->screen_base = par->dio_vp; | |
1075 | info->screen_size = dio_fb_size; | |
68a2d20b | 1076 | |
3a6fb6c4 | 1077 | getmem_done: |
8d69d008 TZ |
1078 | aperture_remove_conflicting_devices(info->apertures->ranges[0].base, |
1079 | info->apertures->ranges[0].size, | |
1080 | KBUILD_MODNAME, false); | |
3cb73bc3 KS |
1081 | |
1082 | if (gen2vm) { | |
1083 | /* framebuffer is reallocated, clear screen_info to avoid misuse from kexec */ | |
1084 | screen_info.lfb_size = 0; | |
1085 | screen_info.lfb_base = 0; | |
1086 | screen_info.orig_video_isVGA = 0; | |
1087 | } else { | |
9069fd54 | 1088 | pci_dev_put(pdev); |
3cb73bc3 | 1089 | } |
9069fd54 | 1090 | |
68a2d20b HZ |
1091 | return 0; |
1092 | ||
1093 | err3: | |
1094 | iounmap(fb_virt); | |
1095 | err2: | |
696ca5e8 | 1096 | vmbus_free_mmio(par->mem->start, screen_fb_size); |
35464483 | 1097 | par->mem = NULL; |
68a2d20b | 1098 | err1: |
9069fd54 GH |
1099 | if (!gen2vm) |
1100 | pci_dev_put(pdev); | |
1101 | ||
68a2d20b HZ |
1102 | return -ENOMEM; |
1103 | } | |
1104 | ||
1105 | /* Release the framebuffer */ | |
3a6fb6c4 | 1106 | static void hvfb_putmem(struct hv_device *hdev, struct fb_info *info) |
68a2d20b | 1107 | { |
9069fd54 GH |
1108 | struct hvfb_par *par = info->par; |
1109 | ||
3a6fb6c4 WH |
1110 | if (par->need_docopy) { |
1111 | vfree(par->dio_vp); | |
1112 | iounmap(info->screen_base); | |
1113 | vmbus_free_mmio(par->mem->start, screen_fb_size); | |
1114 | } else { | |
1115 | hvfb_release_phymem(hdev, info->fix.smem_start, | |
1116 | screen_fb_size); | |
1117 | } | |
1118 | ||
35464483 | 1119 | par->mem = NULL; |
68a2d20b HZ |
1120 | } |
1121 | ||
1122 | ||
1123 | static int hvfb_probe(struct hv_device *hdev, | |
1124 | const struct hv_vmbus_device_id *dev_id) | |
1125 | { | |
1126 | struct fb_info *info; | |
1127 | struct hvfb_par *par; | |
1128 | int ret; | |
1129 | ||
1130 | info = framebuffer_alloc(sizeof(struct hvfb_par), &hdev->device); | |
0adcdbcb | 1131 | if (!info) |
68a2d20b | 1132 | return -ENOMEM; |
68a2d20b HZ |
1133 | |
1134 | par = info->par; | |
1135 | par->info = info; | |
1136 | par->fb_ready = false; | |
3a6fb6c4 | 1137 | par->need_docopy = true; |
68a2d20b HZ |
1138 | init_completion(&par->wait); |
1139 | INIT_DELAYED_WORK(&par->dwork, hvfb_update_work); | |
1140 | ||
d21987d7 WH |
1141 | par->delayed_refresh = false; |
1142 | spin_lock_init(&par->delayed_refresh_lock); | |
1143 | par->x1 = par->y1 = INT_MAX; | |
1144 | par->x2 = par->y2 = 0; | |
1145 | ||
68a2d20b HZ |
1146 | /* Connect to VSP */ |
1147 | hv_set_drvdata(hdev, info); | |
1148 | ret = synthvid_connect_vsp(hdev); | |
1149 | if (ret) { | |
1150 | pr_err("Unable to connect to VSP\n"); | |
1151 | goto error1; | |
1152 | } | |
1153 | ||
67e7cdb4 | 1154 | hvfb_get_option(info); |
9ff5549b MK |
1155 | pr_info("Screen resolution: %dx%d, Color depth: %d, Frame buffer size: %d\n", |
1156 | screen_width, screen_height, screen_depth, screen_fb_size); | |
67e7cdb4 | 1157 | |
35464483 | 1158 | ret = hvfb_getmem(hdev, info); |
68a2d20b HZ |
1159 | if (ret) { |
1160 | pr_err("No memory for framebuffer\n"); | |
1161 | goto error2; | |
1162 | } | |
1163 | ||
68a2d20b HZ |
1164 | /* Set up fb_info */ |
1165 | info->flags = FBINFO_DEFAULT; | |
1166 | ||
1167 | info->var.xres_virtual = info->var.xres = screen_width; | |
1168 | info->var.yres_virtual = info->var.yres = screen_height; | |
1169 | info->var.bits_per_pixel = screen_depth; | |
1170 | ||
1171 | if (info->var.bits_per_pixel == 16) { | |
1172 | info->var.red = (struct fb_bitfield){11, 5, 0}; | |
1173 | info->var.green = (struct fb_bitfield){5, 6, 0}; | |
1174 | info->var.blue = (struct fb_bitfield){0, 5, 0}; | |
1175 | info->var.transp = (struct fb_bitfield){0, 0, 0}; | |
1176 | } else { | |
1177 | info->var.red = (struct fb_bitfield){16, 8, 0}; | |
1178 | info->var.green = (struct fb_bitfield){8, 8, 0}; | |
1179 | info->var.blue = (struct fb_bitfield){0, 8, 0}; | |
1180 | info->var.transp = (struct fb_bitfield){24, 8, 0}; | |
1181 | } | |
1182 | ||
1183 | info->var.activate = FB_ACTIVATE_NOW; | |
1184 | info->var.height = -1; | |
1185 | info->var.width = -1; | |
1186 | info->var.vmode = FB_VMODE_NONINTERLACED; | |
1187 | ||
1188 | strcpy(info->fix.id, KBUILD_MODNAME); | |
1189 | info->fix.type = FB_TYPE_PACKED_PIXELS; | |
1190 | info->fix.visual = FB_VISUAL_TRUECOLOR; | |
1191 | info->fix.line_length = screen_width * screen_depth / 8; | |
1192 | info->fix.accel = FB_ACCEL_NONE; | |
1193 | ||
1194 | info->fbops = &hvfb_ops; | |
1195 | info->pseudo_palette = par->pseudo_palette; | |
1196 | ||
d21987d7 WH |
1197 | /* Initialize deferred IO */ |
1198 | info->fbdefio = &synthvid_defio; | |
1199 | fb_deferred_io_init(info); | |
1200 | ||
68a2d20b HZ |
1201 | /* Send config to host */ |
1202 | ret = synthvid_send_config(hdev); | |
1203 | if (ret) | |
1204 | goto error; | |
1205 | ||
1206 | ret = register_framebuffer(info); | |
1207 | if (ret) { | |
1208 | pr_err("Unable to register framebuffer\n"); | |
1209 | goto error; | |
1210 | } | |
1211 | ||
1212 | par->fb_ready = true; | |
1213 | ||
3686fe96 DC |
1214 | par->synchronous_fb = false; |
1215 | par->hvfb_panic_nb.notifier_call = hvfb_on_panic; | |
1216 | atomic_notifier_chain_register(&panic_notifier_list, | |
1217 | &par->hvfb_panic_nb); | |
1218 | ||
68a2d20b HZ |
1219 | return 0; |
1220 | ||
1221 | error: | |
d21987d7 | 1222 | fb_deferred_io_cleanup(info); |
3a6fb6c4 | 1223 | hvfb_putmem(hdev, info); |
68a2d20b HZ |
1224 | error2: |
1225 | vmbus_close(hdev->channel); | |
1226 | error1: | |
1227 | cancel_delayed_work_sync(&par->dwork); | |
1228 | hv_set_drvdata(hdev, NULL); | |
1229 | framebuffer_release(info); | |
1230 | return ret; | |
1231 | } | |
1232 | ||
1233 | ||
1234 | static int hvfb_remove(struct hv_device *hdev) | |
1235 | { | |
1236 | struct fb_info *info = hv_get_drvdata(hdev); | |
1237 | struct hvfb_par *par = info->par; | |
1238 | ||
3686fe96 DC |
1239 | atomic_notifier_chain_unregister(&panic_notifier_list, |
1240 | &par->hvfb_panic_nb); | |
1241 | ||
68a2d20b HZ |
1242 | par->update = false; |
1243 | par->fb_ready = false; | |
1244 | ||
d21987d7 WH |
1245 | fb_deferred_io_cleanup(info); |
1246 | ||
68a2d20b HZ |
1247 | unregister_framebuffer(info); |
1248 | cancel_delayed_work_sync(&par->dwork); | |
1249 | ||
1250 | vmbus_close(hdev->channel); | |
1251 | hv_set_drvdata(hdev, NULL); | |
1252 | ||
3a6fb6c4 | 1253 | hvfb_putmem(hdev, info); |
68a2d20b HZ |
1254 | framebuffer_release(info); |
1255 | ||
1256 | return 0; | |
1257 | } | |
1258 | ||
1ecf3020 DC |
1259 | static int hvfb_suspend(struct hv_device *hdev) |
1260 | { | |
1261 | struct fb_info *info = hv_get_drvdata(hdev); | |
1262 | struct hvfb_par *par = info->par; | |
1263 | ||
1264 | console_lock(); | |
1265 | ||
1266 | /* 1 means do suspend */ | |
1267 | fb_set_suspend(info, 1); | |
1268 | ||
1269 | cancel_delayed_work_sync(&par->dwork); | |
382a4622 | 1270 | cancel_delayed_work_sync(&info->deferred_work); |
1ecf3020 DC |
1271 | |
1272 | par->update_saved = par->update; | |
1273 | par->update = false; | |
1274 | par->fb_ready = false; | |
1275 | ||
1276 | vmbus_close(hdev->channel); | |
1277 | ||
1278 | console_unlock(); | |
1279 | ||
1280 | return 0; | |
1281 | } | |
1282 | ||
1283 | static int hvfb_resume(struct hv_device *hdev) | |
1284 | { | |
1285 | struct fb_info *info = hv_get_drvdata(hdev); | |
1286 | struct hvfb_par *par = info->par; | |
1287 | int ret; | |
1288 | ||
1289 | console_lock(); | |
1290 | ||
1291 | ret = synthvid_connect_vsp(hdev); | |
1292 | if (ret != 0) | |
1293 | goto out; | |
1294 | ||
1295 | ret = synthvid_send_config(hdev); | |
1296 | if (ret != 0) { | |
1297 | vmbus_close(hdev->channel); | |
1298 | goto out; | |
1299 | } | |
1300 | ||
1301 | par->fb_ready = true; | |
1302 | par->update = par->update_saved; | |
1303 | ||
382a4622 | 1304 | schedule_delayed_work(&info->deferred_work, info->fbdefio->delay); |
1ecf3020 DC |
1305 | schedule_delayed_work(&par->dwork, HVFB_UPDATE_DELAY); |
1306 | ||
1307 | /* 0 means do resume */ | |
1308 | fb_set_suspend(info, 0); | |
1309 | ||
1310 | out: | |
1311 | console_unlock(); | |
1312 | ||
1313 | return ret; | |
1314 | } | |
1315 | ||
68a2d20b | 1316 | |
9baa3c34 | 1317 | static const struct pci_device_id pci_stub_id_table[] = { |
7ad96847 GH |
1318 | { |
1319 | .vendor = PCI_VENDOR_ID_MICROSOFT, | |
1320 | .device = PCI_DEVICE_ID_HYPERV_VIDEO, | |
1321 | }, | |
1322 | { /* end of list */ } | |
1323 | }; | |
1324 | ||
68a2d20b HZ |
1325 | static const struct hv_vmbus_device_id id_table[] = { |
1326 | /* Synthetic Video Device GUID */ | |
1327 | {HV_SYNTHVID_GUID}, | |
1328 | {} | |
1329 | }; | |
1330 | ||
7ad96847 | 1331 | MODULE_DEVICE_TABLE(pci, pci_stub_id_table); |
68a2d20b HZ |
1332 | MODULE_DEVICE_TABLE(vmbus, id_table); |
1333 | ||
1334 | static struct hv_driver hvfb_drv = { | |
1335 | .name = KBUILD_MODNAME, | |
1336 | .id_table = id_table, | |
1337 | .probe = hvfb_probe, | |
1338 | .remove = hvfb_remove, | |
1ecf3020 DC |
1339 | .suspend = hvfb_suspend, |
1340 | .resume = hvfb_resume, | |
af0a5646 AV |
1341 | .driver = { |
1342 | .probe_type = PROBE_PREFER_ASYNCHRONOUS, | |
1343 | }, | |
68a2d20b HZ |
1344 | }; |
1345 | ||
7ad96847 GH |
1346 | static int hvfb_pci_stub_probe(struct pci_dev *pdev, |
1347 | const struct pci_device_id *ent) | |
1348 | { | |
1349 | return 0; | |
1350 | } | |
1351 | ||
1352 | static void hvfb_pci_stub_remove(struct pci_dev *pdev) | |
1353 | { | |
1354 | } | |
1355 | ||
1356 | static struct pci_driver hvfb_pci_stub_driver = { | |
1357 | .name = KBUILD_MODNAME, | |
1358 | .id_table = pci_stub_id_table, | |
1359 | .probe = hvfb_pci_stub_probe, | |
1360 | .remove = hvfb_pci_stub_remove, | |
af0a5646 AV |
1361 | .driver = { |
1362 | .probe_type = PROBE_PREFER_ASYNCHRONOUS, | |
1363 | } | |
7ad96847 | 1364 | }; |
68a2d20b HZ |
1365 | |
1366 | static int __init hvfb_drv_init(void) | |
1367 | { | |
7ad96847 GH |
1368 | int ret; |
1369 | ||
1370 | ret = vmbus_driver_register(&hvfb_drv); | |
1371 | if (ret != 0) | |
1372 | return ret; | |
1373 | ||
1374 | ret = pci_register_driver(&hvfb_pci_stub_driver); | |
1375 | if (ret != 0) { | |
1376 | vmbus_driver_unregister(&hvfb_drv); | |
1377 | return ret; | |
1378 | } | |
1379 | ||
1380 | return 0; | |
68a2d20b HZ |
1381 | } |
1382 | ||
1383 | static void __exit hvfb_drv_exit(void) | |
1384 | { | |
7ad96847 | 1385 | pci_unregister_driver(&hvfb_pci_stub_driver); |
68a2d20b HZ |
1386 | vmbus_driver_unregister(&hvfb_drv); |
1387 | } | |
1388 | ||
1389 | module_init(hvfb_drv_init); | |
1390 | module_exit(hvfb_drv_exit); | |
1391 | ||
1392 | MODULE_LICENSE("GPL"); | |
68a2d20b | 1393 | MODULE_DESCRIPTION("Microsoft Hyper-V Synthetic Video Frame Buffer Driver"); |