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