1 | /* SPDX-License-Identifier: GPL-2.0 OR MIT */ |
2 | /************************************************************************** |
3 | * |
4 | * Copyright 2021 VMware, Inc., Palo Alto, CA., USA |
5 | * |
6 | * Permission is hereby granted, free of charge, to any person obtaining a |
7 | * copy of this software and associated documentation files (the |
8 | * "Software"), to deal in the Software without restriction, including |
9 | * without limitation the rights to use, copy, modify, merge, publish, |
10 | * distribute, sub license, and/or sell copies of the Software, and to |
11 | * permit persons to whom the Software is furnished to do so, subject to |
12 | * the following conditions: |
13 | * |
14 | * The above copyright notice and this permission notice (including the |
15 | * next paragraph) shall be included in all copies or substantial portions |
16 | * of the Software. |
17 | * |
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL |
21 | * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, |
22 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
23 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE |
24 | * USE OR OTHER DEALINGS IN THE SOFTWARE. |
25 | * |
26 | **************************************************************************/ |
27 | |
28 | #include "vmwgfx_devcaps.h" |
29 | |
30 | #include "vmwgfx_drv.h" |
31 | |
32 | |
33 | struct svga_3d_compat_cap { |
34 | SVGA3dFifoCapsRecordHeader ; |
35 | SVGA3dFifoCapPair pairs[SVGA3D_DEVCAP_MAX]; |
36 | }; |
37 | |
38 | |
39 | static u32 vmw_mask_legacy_multisample(unsigned int cap, u32 fmt_value) |
40 | { |
41 | /* |
42 | * A version of user-space exists which use MULTISAMPLE_MASKABLESAMPLES |
43 | * to check the sample count supported by virtual device. Since there |
44 | * never was support for multisample count for backing MOB return 0. |
45 | * |
46 | * MULTISAMPLE_MASKABLESAMPLES devcap is marked as deprecated by virtual |
47 | * device. |
48 | */ |
49 | if (cap == SVGA3D_DEVCAP_DEAD5) |
50 | return 0; |
51 | |
52 | return fmt_value; |
53 | } |
54 | |
55 | static int vmw_fill_compat_cap(struct vmw_private *dev_priv, void *bounce, |
56 | size_t size) |
57 | { |
58 | struct svga_3d_compat_cap *compat_cap = |
59 | (struct svga_3d_compat_cap *) bounce; |
60 | unsigned int i; |
61 | size_t pair_offset = offsetof(struct svga_3d_compat_cap, pairs); |
62 | unsigned int max_size; |
63 | |
64 | if (size < pair_offset) |
65 | return -EINVAL; |
66 | |
67 | max_size = (size - pair_offset) / sizeof(SVGA3dFifoCapPair); |
68 | |
69 | if (max_size > SVGA3D_DEVCAP_MAX) |
70 | max_size = SVGA3D_DEVCAP_MAX; |
71 | |
72 | compat_cap->header.length = |
73 | (pair_offset + max_size * sizeof(SVGA3dFifoCapPair)) / sizeof(u32); |
74 | compat_cap->header.type = SVGA3D_FIFO_CAPS_RECORD_DEVCAPS; |
75 | |
76 | for (i = 0; i < max_size; ++i) { |
77 | compat_cap->pairs[i][0] = i; |
78 | compat_cap->pairs[i][1] = vmw_mask_legacy_multisample |
79 | (cap: i, fmt_value: dev_priv->devcaps[i]); |
80 | } |
81 | |
82 | return 0; |
83 | } |
84 | |
85 | int vmw_devcaps_create(struct vmw_private *vmw) |
86 | { |
87 | bool gb_objects = !!(vmw->capabilities & SVGA_CAP_GBOBJECTS); |
88 | uint32_t i; |
89 | |
90 | if (gb_objects) { |
91 | vmw->devcaps = vzalloc(size: sizeof(uint32_t) * SVGA3D_DEVCAP_MAX); |
92 | if (!vmw->devcaps) |
93 | return -ENOMEM; |
94 | for (i = 0; i < SVGA3D_DEVCAP_MAX; ++i) { |
95 | vmw_write(dev_priv: vmw, offset: SVGA_REG_DEV_CAP, value: i); |
96 | vmw->devcaps[i] = vmw_read(dev_priv: vmw, offset: SVGA_REG_DEV_CAP); |
97 | } |
98 | } |
99 | return 0; |
100 | } |
101 | |
102 | void vmw_devcaps_destroy(struct vmw_private *vmw) |
103 | { |
104 | vfree(addr: vmw->devcaps); |
105 | vmw->devcaps = NULL; |
106 | } |
107 | |
108 | |
109 | uint32 vmw_devcaps_size(const struct vmw_private *vmw, |
110 | bool gb_aware) |
111 | { |
112 | bool gb_objects = !!(vmw->capabilities & SVGA_CAP_GBOBJECTS); |
113 | if (gb_objects && gb_aware) |
114 | return SVGA3D_DEVCAP_MAX * sizeof(uint32_t); |
115 | else if (gb_objects) |
116 | return sizeof(struct svga_3d_compat_cap) + |
117 | sizeof(uint32_t); |
118 | else if (vmw->fifo_mem != NULL) |
119 | return (SVGA_FIFO_3D_CAPS_LAST - SVGA_FIFO_3D_CAPS + 1) * |
120 | sizeof(uint32_t); |
121 | else |
122 | return 0; |
123 | } |
124 | |
125 | int vmw_devcaps_copy(struct vmw_private *vmw, bool gb_aware, |
126 | void *dst, uint32_t dst_size) |
127 | { |
128 | int ret; |
129 | bool gb_objects = !!(vmw->capabilities & SVGA_CAP_GBOBJECTS); |
130 | if (gb_objects && gb_aware) { |
131 | memcpy(dst, vmw->devcaps, dst_size); |
132 | } else if (gb_objects) { |
133 | ret = vmw_fill_compat_cap(dev_priv: vmw, bounce: dst, size: dst_size); |
134 | if (unlikely(ret != 0)) |
135 | return ret; |
136 | } else if (vmw->fifo_mem) { |
137 | u32 *fifo_mem = vmw->fifo_mem; |
138 | memcpy(dst, &fifo_mem[SVGA_FIFO_3D_CAPS], dst_size); |
139 | } else |
140 | return -EINVAL; |
141 | return 0; |
142 | } |
143 | |