]>
git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - drivers/staging/vboxvideo/vbva_base.c
2 * Copyright (C) 2006-2017 Oracle Corporation
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
25 #include "vboxvideo_guest.h"
26 #include "hgsmi_channels.h"
29 * There is a hardware ring buffer in the graphics device video RAM, formerly
30 * in the VBox VMMDev PCI memory space.
31 * All graphics commands go there serialized by vbva_buffer_begin_update.
32 * and vbva_buffer_end_update.
34 * free_offset is writing position. data_offset is reading position.
35 * free_offset == data_offset means buffer is empty.
36 * There must be always gap between data_offset and free_offset when data
38 * Guest only changes free_offset, host changes data_offset.
41 static u32
vbva_buffer_available(const struct vbva_buffer
*vbva
)
43 s32 diff
= vbva
->data_offset
- vbva
->free_offset
;
45 return diff
> 0 ? diff
: vbva
->data_len
+ diff
;
48 static void vbva_buffer_place_data_at(struct vbva_buf_ctx
*vbva_ctx
,
49 const void *p
, u32 len
, u32 offset
)
51 struct vbva_buffer
*vbva
= vbva_ctx
->vbva
;
52 u32 bytes_till_boundary
= vbva
->data_len
- offset
;
53 u8
*dst
= &vbva
->data
[offset
];
54 s32 diff
= len
- bytes_till_boundary
;
57 /* Chunk will not cross buffer boundary. */
60 /* Chunk crosses buffer boundary. */
61 memcpy(dst
, p
, bytes_till_boundary
);
62 memcpy(&vbva
->data
[0], (u8
*)p
+ bytes_till_boundary
, diff
);
66 static void vbva_buffer_flush(struct gen_pool
*ctx
)
70 p
= hgsmi_buffer_alloc(ctx
, sizeof(*p
), HGSMI_CH_VBVA
, VBVA_FLUSH
);
76 hgsmi_buffer_submit(ctx
, p
);
77 hgsmi_buffer_free(ctx
, p
);
80 bool vbva_write(struct vbva_buf_ctx
*vbva_ctx
, struct gen_pool
*ctx
,
81 const void *p
, u32 len
)
83 struct vbva_record
*record
;
84 struct vbva_buffer
*vbva
;
87 vbva
= vbva_ctx
->vbva
;
88 record
= vbva_ctx
->record
;
90 if (!vbva
|| vbva_ctx
->buffer_overflow
||
91 !record
|| !(record
->len_and_flags
& VBVA_F_RECORD_PARTIAL
))
94 available
= vbva_buffer_available(vbva
);
99 if (chunk
>= available
) {
100 vbva_buffer_flush(ctx
);
101 available
= vbva_buffer_available(vbva
);
104 if (chunk
>= available
) {
105 if (WARN_ON(available
<= vbva
->partial_write_tresh
)) {
106 vbva_ctx
->buffer_overflow
= true;
109 chunk
= available
- vbva
->partial_write_tresh
;
112 vbva_buffer_place_data_at(vbva_ctx
, p
, chunk
,
115 vbva
->free_offset
= (vbva
->free_offset
+ chunk
) %
117 record
->len_and_flags
+= chunk
;
126 static bool vbva_inform_host(struct vbva_buf_ctx
*vbva_ctx
,
127 struct gen_pool
*ctx
, s32 screen
, bool enable
)
129 struct vbva_enable_ex
*p
;
132 p
= hgsmi_buffer_alloc(ctx
, sizeof(*p
), HGSMI_CH_VBVA
, VBVA_ENABLE
);
136 p
->base
.flags
= enable
? VBVA_F_ENABLE
: VBVA_F_DISABLE
;
137 p
->base
.offset
= vbva_ctx
->buffer_offset
;
138 p
->base
.result
= VERR_NOT_SUPPORTED
;
140 p
->base
.flags
|= VBVA_F_EXTENDED
| VBVA_F_ABSOFFSET
;
141 p
->screen_id
= screen
;
144 hgsmi_buffer_submit(ctx
, p
);
147 ret
= RT_SUCCESS(p
->base
.result
);
151 hgsmi_buffer_free(ctx
, p
);
156 bool vbva_enable(struct vbva_buf_ctx
*vbva_ctx
, struct gen_pool
*ctx
,
157 struct vbva_buffer
*vbva
, s32 screen
)
161 memset(vbva
, 0, sizeof(*vbva
));
162 vbva
->partial_write_tresh
= 256;
163 vbva
->data_len
= vbva_ctx
->buffer_length
- sizeof(struct vbva_buffer
);
164 vbva_ctx
->vbva
= vbva
;
166 ret
= vbva_inform_host(vbva_ctx
, ctx
, screen
, true);
168 vbva_disable(vbva_ctx
, ctx
, screen
);
173 void vbva_disable(struct vbva_buf_ctx
*vbva_ctx
, struct gen_pool
*ctx
,
176 vbva_ctx
->buffer_overflow
= false;
177 vbva_ctx
->record
= NULL
;
178 vbva_ctx
->vbva
= NULL
;
180 vbva_inform_host(vbva_ctx
, ctx
, screen
, false);
183 bool vbva_buffer_begin_update(struct vbva_buf_ctx
*vbva_ctx
,
184 struct gen_pool
*ctx
)
186 struct vbva_record
*record
;
189 if (!vbva_ctx
->vbva
||
190 !(vbva_ctx
->vbva
->host_flags
.host_events
& VBVA_F_MODE_ENABLED
))
193 WARN_ON(vbva_ctx
->buffer_overflow
|| vbva_ctx
->record
);
195 next
= (vbva_ctx
->vbva
->record_free_index
+ 1) % VBVA_MAX_RECORDS
;
197 /* Flush if all slots in the records queue are used */
198 if (next
== vbva_ctx
->vbva
->record_first_index
)
199 vbva_buffer_flush(ctx
);
201 /* If even after flush there is no place then fail the request */
202 if (next
== vbva_ctx
->vbva
->record_first_index
)
205 record
= &vbva_ctx
->vbva
->records
[vbva_ctx
->vbva
->record_free_index
];
206 record
->len_and_flags
= VBVA_F_RECORD_PARTIAL
;
207 vbva_ctx
->vbva
->record_free_index
= next
;
208 /* Remember which record we are using. */
209 vbva_ctx
->record
= record
;
214 void vbva_buffer_end_update(struct vbva_buf_ctx
*vbva_ctx
)
216 struct vbva_record
*record
= vbva_ctx
->record
;
218 WARN_ON(!vbva_ctx
->vbva
|| !record
||
219 !(record
->len_and_flags
& VBVA_F_RECORD_PARTIAL
));
221 /* Mark the record completed. */
222 record
->len_and_flags
&= ~VBVA_F_RECORD_PARTIAL
;
224 vbva_ctx
->buffer_overflow
= false;
225 vbva_ctx
->record
= NULL
;
228 void vbva_setup_buffer_context(struct vbva_buf_ctx
*vbva_ctx
,
229 u32 buffer_offset
, u32 buffer_length
)
231 vbva_ctx
->buffer_offset
= buffer_offset
;
232 vbva_ctx
->buffer_length
= buffer_length
;