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