Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'drm-misc-next-2022-10-27' of git://anongit.freedesktop.org/drm/drm-misc into drm-next

drm-misc-next for 6.2:

UAPI Changes:

Cross-subsystem Changes:

Core Changes:
- connector: Send hotplug event on cleanup
- edid: logging/debug improvements
- plane_helper: Improve tests

Driver Changes:
- bridge:
- it6505: Synchronization improvements
- panel:
- panel-edp: Add INX N116BGE-EA2 C2 and C4 support.
- nouveau: Fix page-fault handling
- vmwgfx: fb and cursor refactoring, convert to generic hashtable

Signed-off-by: Dave Airlie <airlied@redhat.com>

From: Maxime Ripard <maxime@cerno.tech>
Link: https://patchwork.freedesktop.org/patch/msgid/20221027073407.c2tlaczvzjrnzazi@houat

+1283 -2318
-11
Documentation/gpu/todo.rst
··· 651 651 652 652 Contact: Harry Wentland, Alex Deucher 653 653 654 - vmwgfx: Replace hashtable with Linux' implementation 655 - ---------------------------------------------------- 656 - 657 - The vmwgfx driver uses its own hashtable implementation. Replace the 658 - code with Linux' implementation and update the callers. It's mostly a 659 - refactoring task, but the interfaces are different. 660 - 661 - Contact: Zack Rusin, Thomas Zimmermann <tzimmermann@suse.de> 662 - 663 - Level: Intermediate 664 - 665 654 Bootsplash 666 655 ========== 667 656
-3
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
··· 6108 6108 aconnector->base.name); 6109 6109 6110 6110 aconnector->base.force = DRM_FORCE_OFF; 6111 - aconnector->base.override_edid = false; 6112 6111 return; 6113 6112 } 6114 6113 ··· 6142 6143 link->verified_link_cap.link_rate = LINK_RATE_HIGH2; 6143 6144 } 6144 6145 6145 - 6146 - aconnector->base.override_edid = true; 6147 6146 create_eml_sink(aconnector); 6148 6147 } 6149 6148
+51 -55
drivers/gpu/drm/bridge/ite-it6505.c
··· 412 412 * Mutex protects extcon and interrupt functions from interfering 413 413 * each other. 414 414 */ 415 + struct mutex irq_lock; 415 416 struct mutex extcon_lock; 416 417 struct mutex mode_lock; /* used to bridge_detect */ 417 418 struct mutex aux_lock; /* used to aux data transfers */ ··· 441 440 enum hdcp_state hdcp_status; 442 441 struct delayed_work hdcp_work; 443 442 struct work_struct hdcp_wait_ksv_list; 444 - struct completion wait_edid_complete; 443 + struct completion extcon_completion; 445 444 u8 auto_train_retry; 446 445 bool hdcp_desired; 447 446 bool is_repeater; ··· 724 723 725 724 DRM_DEV_DEBUG_DRIVER(dev, DRM_MODE_FMT, 726 725 DRM_MODE_ARG(&it6505->video_info)); 727 - } 728 - 729 - static int it6505_drm_dp_link_probe(struct drm_dp_aux *aux, 730 - struct it6505_drm_dp_link *link) 731 - { 732 - u8 values[3]; 733 - int err; 734 - 735 - memset(link, 0, sizeof(*link)); 736 - 737 - err = drm_dp_dpcd_read(aux, DP_DPCD_REV, values, sizeof(values)); 738 - if (err < 0) 739 - return err; 740 - 741 - link->revision = values[0]; 742 - link->rate = drm_dp_bw_code_to_link_rate(values[1]); 743 - link->num_lanes = values[2] & DP_MAX_LANE_COUNT_MASK; 744 - 745 - if (values[2] & DP_ENHANCED_FRAME_CAP) 746 - link->capabilities = DP_ENHANCED_FRAME_CAP; 747 - 748 - return 0; 749 726 } 750 727 751 728 static int it6505_drm_dp_link_set_power(struct drm_dp_aux *aux, ··· 1435 1456 int bcaps; 1436 1457 1437 1458 if (it6505->dpcd[0] == 0) { 1438 - it6505_aux_on(it6505); 1439 - it6505_get_dpcd(it6505, DP_DPCD_REV, it6505->dpcd, 1440 - ARRAY_SIZE(it6505->dpcd)); 1459 + dev_err(dev, "DPCD is not initialized"); 1460 + return; 1441 1461 } 1462 + 1463 + memset(link, 0, sizeof(*link)); 1464 + 1465 + link->revision = it6505->dpcd[0]; 1466 + link->rate = drm_dp_bw_code_to_link_rate(it6505->dpcd[1]); 1467 + link->num_lanes = it6505->dpcd[2] & DP_MAX_LANE_COUNT_MASK; 1468 + 1469 + if (it6505->dpcd[2] & DP_ENHANCED_FRAME_CAP) 1470 + link->capabilities = DP_ENHANCED_FRAME_CAP; 1442 1471 1443 1472 DRM_DEV_DEBUG_DRIVER(dev, "DPCD Rev.: %d.%d", 1444 1473 link->revision >> 4, link->revision & 0x0F); ··· 2310 2323 static void it6505_irq_hpd(struct it6505 *it6505) 2311 2324 { 2312 2325 struct device *dev = &it6505->client->dev; 2326 + int dp_sink_count; 2313 2327 2314 2328 it6505->hpd_state = it6505_get_sink_hpd_status(it6505); 2315 2329 DRM_DEV_DEBUG_DRIVER(dev, "hpd change interrupt, change to %s", 2316 2330 it6505->hpd_state ? "high" : "low"); 2317 2331 2318 - if (it6505->bridge.dev) 2319 - drm_helper_hpd_irq_event(it6505->bridge.dev); 2320 - DRM_DEV_DEBUG_DRIVER(dev, "it6505->sink_count: %d", 2321 - it6505->sink_count); 2322 - 2323 2332 if (it6505->hpd_state) { 2324 - wait_for_completion_timeout(&it6505->wait_edid_complete, 2325 - msecs_to_jiffies(6000)); 2333 + wait_for_completion_timeout(&it6505->extcon_completion, 2334 + msecs_to_jiffies(1000)); 2335 + it6505_aux_on(it6505); 2336 + if (it6505->dpcd[0] == 0) { 2337 + it6505_get_dpcd(it6505, DP_DPCD_REV, it6505->dpcd, 2338 + ARRAY_SIZE(it6505->dpcd)); 2339 + it6505_variable_config(it6505); 2340 + it6505_parse_link_capabilities(it6505); 2341 + } 2342 + it6505->auto_train_retry = AUTO_TRAIN_RETRY; 2343 + 2344 + it6505_drm_dp_link_set_power(&it6505->aux, &it6505->link, 2345 + DP_SET_POWER_D0); 2346 + dp_sink_count = it6505_dpcd_read(it6505, DP_SINK_COUNT); 2347 + it6505->sink_count = DP_GET_SINK_COUNT(dp_sink_count); 2348 + 2349 + DRM_DEV_DEBUG_DRIVER(dev, "it6505->sink_count: %d", 2350 + it6505->sink_count); 2351 + 2326 2352 it6505_lane_termination_on(it6505); 2327 2353 it6505_lane_power_on(it6505); 2328 2354 ··· 2363 2363 it6505_lane_off(it6505); 2364 2364 it6505_link_reset_step_train(it6505); 2365 2365 } 2366 + 2367 + if (it6505->bridge.dev) 2368 + drm_helper_hpd_irq_event(it6505->bridge.dev); 2366 2369 } 2367 2370 2368 2371 static void it6505_irq_hpd_irq(struct it6505 *it6505) ··· 2494 2491 }; 2495 2492 int int_status[3], i; 2496 2493 2497 - msleep(100); 2498 - mutex_lock(&it6505->extcon_lock); 2494 + mutex_lock(&it6505->irq_lock); 2499 2495 2500 2496 if (it6505->enable_drv_hold || !it6505->powered) 2501 2497 goto unlock; ··· 2524 2522 } 2525 2523 2526 2524 unlock: 2527 - mutex_unlock(&it6505->extcon_lock); 2525 + mutex_unlock(&it6505->irq_lock); 2528 2526 2529 2527 return IRQ_HANDLED; 2530 2528 } ··· 2627 2625 goto unlock; 2628 2626 2629 2627 if (it6505->enable_drv_hold) { 2630 - status = it6505_get_sink_hpd_status(it6505) ? 2631 - connector_status_connected : 2632 - connector_status_disconnected; 2628 + status = it6505->hpd_state ? connector_status_connected : 2629 + connector_status_disconnected; 2633 2630 goto unlock; 2634 2631 } 2635 2632 2636 - if (it6505_get_sink_hpd_status(it6505)) { 2637 - it6505_aux_on(it6505); 2638 - it6505_drm_dp_link_probe(&it6505->aux, &it6505->link); 2633 + if (it6505->hpd_state) { 2639 2634 it6505_drm_dp_link_set_power(&it6505->aux, &it6505->link, 2640 2635 DP_SET_POWER_D0); 2641 - it6505->auto_train_retry = AUTO_TRAIN_RETRY; 2642 - 2643 - if (it6505->dpcd[0] == 0) { 2644 - it6505_get_dpcd(it6505, DP_DPCD_REV, it6505->dpcd, 2645 - ARRAY_SIZE(it6505->dpcd)); 2646 - it6505_variable_config(it6505); 2647 - it6505_parse_link_capabilities(it6505); 2648 - } 2649 - 2650 2636 dp_sink_count = it6505_dpcd_read(it6505, DP_SINK_COUNT); 2651 2637 it6505->sink_count = DP_GET_SINK_COUNT(dp_sink_count); 2652 2638 DRM_DEV_DEBUG_DRIVER(dev, "it6505->sink_count:%d branch:%d", ··· 2701 2711 */ 2702 2712 if (ret) 2703 2713 it6505_poweron(it6505); 2714 + 2715 + complete_all(&it6505->extcon_completion); 2704 2716 } else { 2705 2717 DRM_DEV_DEBUG_DRIVER(dev, "start to power off"); 2706 2718 pm_runtime_put_sync(dev); 2719 + reinit_completion(&it6505->extcon_completion); 2707 2720 2708 2721 drm_helper_hpd_irq_event(it6505->bridge.dev); 2709 2722 memset(it6505->dpcd, 0, sizeof(it6505->dpcd)); ··· 2864 2871 } 2865 2872 2866 2873 /* Register aux channel */ 2867 - it6505->aux.name = "DP-AUX"; 2868 - it6505->aux.dev = dev; 2869 2874 it6505->aux.drm_dev = bridge->dev; 2870 - it6505->aux.transfer = it6505_aux_transfer; 2871 2875 2872 2876 ret = drm_dp_aux_register(&it6505->aux); 2873 2877 ··· 3277 3287 if (!it6505) 3278 3288 return -ENOMEM; 3279 3289 3290 + mutex_init(&it6505->irq_lock); 3280 3291 mutex_init(&it6505->extcon_lock); 3281 3292 mutex_init(&it6505->mode_lock); 3282 3293 mutex_init(&it6505->aux_lock); ··· 3333 3342 INIT_WORK(&it6505->link_works, it6505_link_training_work); 3334 3343 INIT_WORK(&it6505->hdcp_wait_ksv_list, it6505_hdcp_wait_ksv_list); 3335 3344 INIT_DELAYED_WORK(&it6505->hdcp_work, it6505_hdcp_work); 3336 - init_completion(&it6505->wait_edid_complete); 3345 + init_completion(&it6505->extcon_completion); 3337 3346 memset(it6505->dpcd, 0, sizeof(it6505->dpcd)); 3338 3347 it6505->powered = false; 3339 3348 it6505->enable_drv_hold = DEFAULT_DRV_HOLD; ··· 3344 3353 DRM_DEV_DEBUG_DRIVER(dev, "it6505 device name: %s", dev_name(dev)); 3345 3354 debugfs_init(it6505); 3346 3355 pm_runtime_enable(dev); 3356 + 3357 + it6505->aux.name = "DP-AUX"; 3358 + it6505->aux.dev = dev; 3359 + it6505->aux.transfer = it6505_aux_transfer; 3360 + drm_dp_aux_init(&it6505->aux); 3347 3361 3348 3362 it6505->bridge.funcs = &it6505_bridge_funcs; 3349 3363 it6505->bridge.type = DRM_MODE_CONNECTOR_DisplayPort;
+1 -1
drivers/gpu/drm/drm_client.c
··· 235 235 { 236 236 struct drm_device *dev = buffer->client->dev; 237 237 238 - drm_gem_vunmap(buffer->gem, &buffer->map); 238 + drm_gem_vunmap_unlocked(buffer->gem, &buffer->map); 239 239 240 240 if (buffer->gem) 241 241 drm_gem_object_put(buffer->gem);
+4
drivers/gpu/drm/drm_connector.c
··· 274 274 INIT_LIST_HEAD(&connector->probed_modes); 275 275 INIT_LIST_HEAD(&connector->modes); 276 276 mutex_init(&connector->mutex); 277 + mutex_init(&connector->edid_override_mutex); 277 278 connector->edid_blob_ptr = NULL; 278 279 connector->epoch_counter = 0; 279 280 connector->tile_blob_ptr = NULL; ··· 583 582 mutex_destroy(&connector->mutex); 584 583 585 584 memset(connector, 0, sizeof(*connector)); 585 + 586 + if (dev->registered) 587 + drm_sysfs_hotplug_event(dev); 586 588 } 587 589 EXPORT_SYMBOL(drm_connector_cleanup); 588 590
+15 -2
drivers/gpu/drm/drm_crtc_internal.h
··· 56 56 struct drm_plane_state; 57 57 struct drm_property; 58 58 struct edid; 59 - struct kref; 60 - struct work_struct; 61 59 struct fwnode_handle; 60 + struct kref; 61 + struct seq_file; 62 + struct work_struct; 62 63 63 64 /* drm_crtc.c */ 64 65 int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj, ··· 287 286 288 287 /* drm_edid.c */ 289 288 void drm_mode_fixup_1366x768(struct drm_display_mode *mode); 289 + int drm_edid_override_show(struct drm_connector *connector, struct seq_file *m); 290 290 int drm_edid_override_set(struct drm_connector *connector, const void *edid, size_t size); 291 291 int drm_edid_override_reset(struct drm_connector *connector); 292 + 293 + /* drm_edid_load.c */ 294 + #ifdef CONFIG_DRM_LOAD_EDID_FIRMWARE 295 + const struct drm_edid *drm_edid_load_firmware(struct drm_connector *connector); 296 + #else 297 + static inline const struct drm_edid * 298 + drm_edid_load_firmware(struct drm_connector *connector) 299 + { 300 + return ERR_PTR(-ENOENT); 301 + } 302 + #endif
+1 -7
drivers/gpu/drm/drm_debugfs.c
··· 328 328 329 329 static int edid_show(struct seq_file *m, void *data) 330 330 { 331 - struct drm_connector *connector = m->private; 332 - struct drm_property_blob *edid = connector->edid_blob_ptr; 333 - 334 - if (connector->override_edid && edid) 335 - seq_write(m, edid->data, edid->length); 336 - 337 - return 0; 331 + return drm_edid_override_show(m->private, m); 338 332 } 339 333 340 334 static int edid_open(struct inode *inode, struct file *file)
+215 -131
drivers/gpu/drm/drm_edid.c
··· 1613 1613 return edid_block_data(edid, index + 1); 1614 1614 } 1615 1615 1616 - static int drm_edid_block_count(const struct drm_edid *drm_edid) 1616 + /* EDID block count indicated in EDID, may exceed allocated size */ 1617 + static int __drm_edid_block_count(const struct drm_edid *drm_edid) 1617 1618 { 1618 1619 int num_blocks; 1619 1620 ··· 1634 1633 num_blocks = eeodb; 1635 1634 } 1636 1635 1637 - /* Limit by allocated size */ 1638 - num_blocks = min(num_blocks, (int)drm_edid->size / EDID_LENGTH); 1639 - 1640 1636 return num_blocks; 1641 1637 } 1642 1638 1639 + /* EDID block count, limited by allocated size */ 1640 + static int drm_edid_block_count(const struct drm_edid *drm_edid) 1641 + { 1642 + /* Limit by allocated size */ 1643 + return min(__drm_edid_block_count(drm_edid), 1644 + (int)drm_edid->size / EDID_LENGTH); 1645 + } 1646 + 1647 + /* EDID extension block count, limited by allocated size */ 1643 1648 static int drm_edid_extension_block_count(const struct drm_edid *drm_edid) 1644 1649 { 1645 1650 return drm_edid_block_count(drm_edid) - 1; ··· 1979 1972 1980 1973 status = edid_block_check(block, is_base_block); 1981 1974 if (status == EDID_BLOCK_HEADER_REPAIR) { 1982 - DRM_DEBUG("Fixing EDID header, your hardware may be failing\n"); 1975 + DRM_DEBUG_KMS("Fixing EDID header, your hardware may be failing\n"); 1983 1976 edid_header_fix(block); 1984 1977 1985 1978 /* Retry with fixed header, update status if that worked. */ ··· 2039 2032 return true; 2040 2033 } 2041 2034 EXPORT_SYMBOL(drm_edid_is_valid); 2035 + 2036 + /** 2037 + * drm_edid_valid - sanity check EDID data 2038 + * @drm_edid: EDID data 2039 + * 2040 + * Sanity check an EDID. Cross check block count against allocated size and 2041 + * checksum the blocks. 2042 + * 2043 + * Return: True if the EDID data is valid, false otherwise. 2044 + */ 2045 + bool drm_edid_valid(const struct drm_edid *drm_edid) 2046 + { 2047 + int i; 2048 + 2049 + if (!drm_edid) 2050 + return false; 2051 + 2052 + if (edid_size_by_blocks(__drm_edid_block_count(drm_edid)) != drm_edid->size) 2053 + return false; 2054 + 2055 + for (i = 0; i < drm_edid_block_count(drm_edid); i++) { 2056 + const void *block = drm_edid_block_data(drm_edid, i); 2057 + 2058 + if (!edid_block_valid(block, i == 0)) 2059 + return false; 2060 + } 2061 + 2062 + return true; 2063 + } 2064 + EXPORT_SYMBOL(drm_edid_valid); 2042 2065 2043 2066 static struct edid *edid_filter_invalid_blocks(struct edid *edid, 2044 2067 size_t *alloc_size) ··· 2196 2159 if (connector->bad_edid_counter++ && !drm_debug_enabled(DRM_UT_KMS)) 2197 2160 return; 2198 2161 2199 - drm_dbg_kms(connector->dev, "%s: EDID is invalid:\n", connector->name); 2162 + drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] EDID is invalid:\n", 2163 + connector->base.id, connector->name); 2200 2164 for (i = 0; i < num_blocks; i++) 2201 2165 edid_block_dump(KERN_DEBUG, edid + i, i); 2202 2166 } 2203 2167 2204 2168 /* Get override or firmware EDID */ 2205 - static struct edid *drm_get_override_edid(struct drm_connector *connector, 2206 - size_t *alloc_size) 2169 + static const struct drm_edid *drm_edid_override_get(struct drm_connector *connector) 2207 2170 { 2208 - struct edid *override = NULL; 2171 + const struct drm_edid *override = NULL; 2209 2172 2210 - if (connector->override_edid) 2211 - override = drm_edid_duplicate(connector->edid_blob_ptr->data); 2173 + mutex_lock(&connector->edid_override_mutex); 2174 + 2175 + if (connector->edid_override) 2176 + override = drm_edid_dup(connector->edid_override); 2177 + 2178 + mutex_unlock(&connector->edid_override_mutex); 2212 2179 2213 2180 if (!override) 2214 - override = drm_load_edid_firmware(connector); 2215 - 2216 - /* FIXME: Get alloc size from deeper down the stack */ 2217 - if (!IS_ERR_OR_NULL(override) && alloc_size) 2218 - *alloc_size = edid_size(override); 2181 + override = drm_edid_load_firmware(connector); 2219 2182 2220 2183 return IS_ERR(override) ? NULL : override; 2184 + } 2185 + 2186 + /* For debugfs edid_override implementation */ 2187 + int drm_edid_override_show(struct drm_connector *connector, struct seq_file *m) 2188 + { 2189 + const struct drm_edid *drm_edid; 2190 + 2191 + mutex_lock(&connector->edid_override_mutex); 2192 + 2193 + drm_edid = connector->edid_override; 2194 + if (drm_edid) 2195 + seq_write(m, drm_edid->edid, drm_edid->size); 2196 + 2197 + mutex_unlock(&connector->edid_override_mutex); 2198 + 2199 + return 0; 2221 2200 } 2222 2201 2223 2202 /* For debugfs edid_override implementation */ 2224 2203 int drm_edid_override_set(struct drm_connector *connector, const void *edid, 2225 2204 size_t size) 2226 2205 { 2227 - int ret; 2206 + const struct drm_edid *drm_edid; 2228 2207 2229 - if (size < EDID_LENGTH || edid_size(edid) > size) 2208 + drm_edid = drm_edid_alloc(edid, size); 2209 + if (!drm_edid_valid(drm_edid)) { 2210 + drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] EDID override invalid\n", 2211 + connector->base.id, connector->name); 2212 + drm_edid_free(drm_edid); 2230 2213 return -EINVAL; 2214 + } 2231 2215 2232 - connector->override_edid = false; 2216 + drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] EDID override set\n", 2217 + connector->base.id, connector->name); 2233 2218 2234 - ret = drm_connector_update_edid_property(connector, edid); 2235 - if (!ret) 2236 - connector->override_edid = true; 2219 + mutex_lock(&connector->edid_override_mutex); 2237 2220 2238 - return ret; 2221 + drm_edid_free(connector->edid_override); 2222 + connector->edid_override = drm_edid; 2223 + 2224 + mutex_unlock(&connector->edid_override_mutex); 2225 + 2226 + return 0; 2239 2227 } 2240 2228 2241 2229 /* For debugfs edid_override implementation */ 2242 2230 int drm_edid_override_reset(struct drm_connector *connector) 2243 2231 { 2244 - connector->override_edid = false; 2232 + drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] EDID override reset\n", 2233 + connector->base.id, connector->name); 2245 2234 2246 - return drm_connector_update_edid_property(connector, NULL); 2235 + mutex_lock(&connector->edid_override_mutex); 2236 + 2237 + drm_edid_free(connector->edid_override); 2238 + connector->edid_override = NULL; 2239 + 2240 + mutex_unlock(&connector->edid_override_mutex); 2241 + 2242 + return 0; 2247 2243 } 2248 2244 2249 2245 /** 2250 - * drm_add_override_edid_modes - add modes from override/firmware EDID 2246 + * drm_edid_override_connector_update - add modes from override/firmware EDID 2251 2247 * @connector: connector we're probing 2252 2248 * 2253 2249 * Add modes from the override/firmware EDID, if available. Only to be used from ··· 2290 2220 * 2291 2221 * Return: The number of modes added or 0 if we couldn't find any. 2292 2222 */ 2293 - int drm_add_override_edid_modes(struct drm_connector *connector) 2223 + int drm_edid_override_connector_update(struct drm_connector *connector) 2294 2224 { 2295 - struct edid *override; 2225 + const struct drm_edid *override; 2296 2226 int num_modes = 0; 2297 2227 2298 - override = drm_get_override_edid(connector, NULL); 2228 + override = drm_edid_override_get(connector); 2299 2229 if (override) { 2300 - drm_connector_update_edid_property(connector, override); 2301 - num_modes = drm_add_edid_modes(connector, override); 2302 - kfree(override); 2230 + num_modes = drm_edid_connector_update(connector, override); 2303 2231 2304 - DRM_DEBUG_KMS("[CONNECTOR:%d:%s] adding %d modes via fallback override/firmware EDID\n", 2305 - connector->base.id, connector->name, num_modes); 2232 + drm_edid_free(override); 2233 + 2234 + drm_dbg_kms(connector->dev, 2235 + "[CONNECTOR:%d:%s] adding %d modes via fallback override/firmware EDID\n", 2236 + connector->base.id, connector->name, num_modes); 2306 2237 } 2307 2238 2308 2239 return num_modes; 2309 2240 } 2310 - EXPORT_SYMBOL(drm_add_override_edid_modes); 2241 + EXPORT_SYMBOL(drm_edid_override_connector_update); 2311 2242 2312 2243 typedef int read_block_fn(void *context, u8 *buf, unsigned int block, size_t len); 2313 2244 ··· 2351 2280 { 2352 2281 enum edid_block_status status; 2353 2282 int i, num_blocks, invalid_blocks = 0; 2283 + const struct drm_edid *override; 2354 2284 struct edid *edid, *new; 2355 2285 size_t alloc_size = EDID_LENGTH; 2356 2286 2357 - edid = drm_get_override_edid(connector, &alloc_size); 2358 - if (edid) 2287 + override = drm_edid_override_get(connector); 2288 + if (override) { 2289 + alloc_size = override->size; 2290 + edid = kmemdup(override->edid, alloc_size, GFP_KERNEL); 2291 + drm_edid_free(override); 2292 + if (!edid) 2293 + return NULL; 2359 2294 goto ok; 2295 + } 2360 2296 2361 2297 edid = kmalloc(alloc_size, GFP_KERNEL); 2362 2298 if (!edid) ··· 2466 2388 * adapter and use drm_get_edid() instead of abusing this function. 2467 2389 * 2468 2390 * The EDID may be overridden using debugfs override_edid or firmware EDID 2469 - * (drm_load_edid_firmware() and drm.edid_firmware parameter), in this priority 2391 + * (drm_edid_load_firmware() and drm.edid_firmware parameter), in this priority 2470 2392 * order. Having either of them bypasses actual EDID reads. 2471 2393 * 2472 2394 * Return: Pointer to valid EDID or NULL if we couldn't find any. ··· 2644 2566 * this function. 2645 2567 * 2646 2568 * The EDID may be overridden using debugfs override_edid or firmware EDID 2647 - * (drm_load_edid_firmware() and drm.edid_firmware parameter), in this priority 2569 + * (drm_edid_load_firmware() and drm.edid_firmware parameter), in this priority 2648 2570 * order. Having either of them bypasses actual EDID reads. 2649 2571 * 2650 2572 * The returned pointer must be freed using drm_edid_free(). ··· 2682 2604 * Read EDID using the given I2C adapter. 2683 2605 * 2684 2606 * The EDID may be overridden using debugfs override_edid or firmware EDID 2685 - * (drm_load_edid_firmware() and drm.edid_firmware parameter), in this priority 2607 + * (drm_edid_load_firmware() and drm.edid_firmware parameter), in this priority 2686 2608 * order. Having either of them bypasses actual EDID reads. 2687 2609 * 2688 2610 * Prefer initializing connector->ddc with drm_connector_init_with_ddc() and ··· 2718 2640 * Read EDID using the connector's I2C adapter. 2719 2641 * 2720 2642 * The EDID may be overridden using debugfs override_edid or firmware EDID 2721 - * (drm_load_edid_firmware() and drm.edid_firmware parameter), in this priority 2643 + * (drm_edid_load_firmware() and drm.edid_firmware parameter), in this priority 2722 2644 * order. Having either of them bypasses actual EDID reads. 2723 2645 * 2724 2646 * The returned pointer must be freed using drm_edid_free(). ··· 3389 3311 * timing block contains enough info for us to create and return a new struct 3390 3312 * drm_display_mode. 3391 3313 */ 3392 - static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, 3314 + static struct drm_display_mode *drm_mode_detailed(struct drm_connector *connector, 3393 3315 const struct drm_edid *drm_edid, 3394 3316 const struct detailed_timing *timing, 3395 3317 u32 quirks) 3396 3318 { 3319 + struct drm_device *dev = connector->dev; 3397 3320 struct drm_display_mode *mode; 3398 3321 const struct detailed_pixel_timing *pt = &timing->data.pixel_data; 3399 3322 unsigned hactive = (pt->hactive_hblank_hi & 0xf0) << 4 | pt->hactive_lo; ··· 3411 3332 return NULL; 3412 3333 3413 3334 if (pt->misc & DRM_EDID_PT_STEREO) { 3414 - DRM_DEBUG_KMS("stereo mode not supported\n"); 3335 + drm_dbg_kms(dev, "[CONNECTOR:%d:%s] Stereo mode not supported\n", 3336 + connector->base.id, connector->name); 3415 3337 return NULL; 3416 3338 } 3417 3339 if (!(pt->misc & DRM_EDID_PT_SEPARATE_SYNC)) { 3418 - DRM_DEBUG_KMS("composite sync not supported\n"); 3340 + drm_dbg_kms(dev, "[CONNECTOR:%d:%s] Composite sync not supported\n", 3341 + connector->base.id, connector->name); 3419 3342 } 3420 3343 3421 3344 /* it is incorrect if hsync/vsync width is zero */ 3422 3345 if (!hsync_pulse_width || !vsync_pulse_width) { 3423 - DRM_DEBUG_KMS("Incorrect Detailed timing. " 3424 - "Wrong Hsync/Vsync pulse width\n"); 3346 + drm_dbg_kms(dev, "[CONNECTOR:%d:%s] Incorrect Detailed timing. Wrong Hsync/Vsync pulse width\n", 3347 + connector->base.id, connector->name); 3425 3348 return NULL; 3426 3349 } 3427 3350 ··· 3980 3899 return closure.modes; 3981 3900 } 3982 3901 3983 - static void fixup_detailed_cea_mode_clock(struct drm_display_mode *mode); 3902 + static void fixup_detailed_cea_mode_clock(struct drm_connector *connector, 3903 + struct drm_display_mode *mode); 3984 3904 3985 3905 static void 3986 3906 do_detailed_mode(const struct detailed_timing *timing, void *c) ··· 3992 3910 if (!is_detailed_timing_descriptor(timing)) 3993 3911 return; 3994 3912 3995 - newmode = drm_mode_detailed(closure->connector->dev, 3913 + newmode = drm_mode_detailed(closure->connector, 3996 3914 closure->drm_edid, timing, 3997 3915 closure->quirks); 3998 3916 if (!newmode) ··· 4006 3924 * so fix up anything that looks like CEA/HDMI mode, but the clock 4007 3925 * is just slightly off. 4008 3926 */ 4009 - fixup_detailed_cea_mode_clock(newmode); 3927 + fixup_detailed_cea_mode_clock(closure->connector, newmode); 4010 3928 4011 3929 drm_mode_probed_add(closure->connector, newmode); 4012 3930 closure->modes++; ··· 4668 4586 struct drm_display_mode *newmode; 4669 4587 4670 4588 if (!drm_valid_hdmi_vic(vic)) { 4671 - DRM_ERROR("Unknown HDMI VIC: %d\n", vic); 4589 + drm_err(connector->dev, "[CONNECTOR:%d:%s] Unknown HDMI VIC: %d\n", 4590 + connector->base.id, connector->name, vic); 4672 4591 return 0; 4673 4592 } 4674 4593 ··· 5276 5193 return modes; 5277 5194 } 5278 5195 5279 - static void fixup_detailed_cea_mode_clock(struct drm_display_mode *mode) 5196 + static void fixup_detailed_cea_mode_clock(struct drm_connector *connector, 5197 + struct drm_display_mode *mode) 5280 5198 { 5281 5199 const struct drm_display_mode *cea_mode; 5282 5200 int clock1, clock2, clock; ··· 5315 5231 if (mode->clock == clock) 5316 5232 return; 5317 5233 5318 - DRM_DEBUG("detailed mode matches %s VIC %d, adjusting clock %d -> %d\n", 5319 - type, vic, mode->clock, clock); 5234 + drm_dbg_kms(connector->dev, 5235 + "[CONNECTOR:%d:%s] detailed mode matches %s VIC %d, adjusting clock %d -> %d\n", 5236 + connector->base.id, connector->name, 5237 + type, vic, mode->clock, clock); 5320 5238 mode->clock = clock; 5321 5239 } 5322 5240 ··· 5426 5340 if (len >= 12) 5427 5341 connector->audio_latency[1] = db[12]; 5428 5342 5429 - DRM_DEBUG_KMS("HDMI: latency present %d %d, " 5430 - "video latency %d %d, " 5431 - "audio latency %d %d\n", 5432 - connector->latency_present[0], 5433 - connector->latency_present[1], 5434 - connector->video_latency[0], 5435 - connector->video_latency[1], 5436 - connector->audio_latency[0], 5437 - connector->audio_latency[1]); 5343 + drm_dbg_kms(connector->dev, 5344 + "[CONNECTOR:%d:%s] HDMI: latency present %d %d, video latency %d %d, audio latency %d %d\n", 5345 + connector->base.id, connector->name, 5346 + connector->latency_present[0], connector->latency_present[1], 5347 + connector->video_latency[0], connector->video_latency[1], 5348 + connector->audio_latency[0], connector->audio_latency[1]); 5438 5349 } 5439 5350 5440 5351 static void ··· 5529 5446 return; 5530 5447 5531 5448 mnl = get_monitor_name(drm_edid, &eld[DRM_ELD_MONITOR_NAME_STRING]); 5532 - DRM_DEBUG_KMS("ELD monitor %s\n", &eld[DRM_ELD_MONITOR_NAME_STRING]); 5449 + drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] ELD monitor %s\n", 5450 + connector->base.id, connector->name, 5451 + &eld[DRM_ELD_MONITOR_NAME_STRING]); 5533 5452 5534 5453 eld[DRM_ELD_CEA_EDID_VER_MNL] = info->cea_rev << DRM_ELD_CEA_EDID_VER_SHIFT; 5535 5454 eld[DRM_ELD_CEA_EDID_VER_MNL] |= mnl; ··· 5585 5500 eld[DRM_ELD_BASELINE_ELD_LEN] = 5586 5501 DIV_ROUND_UP(drm_eld_calc_baseline_block_size(eld), 4); 5587 5502 5588 - DRM_DEBUG_KMS("ELD size %d, SAD count %d\n", 5589 - drm_eld_size(eld), total_sad_count); 5503 + drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] ELD size %d, SAD count %d\n", 5504 + connector->base.id, connector->name, 5505 + drm_eld_size(eld), total_sad_count); 5590 5506 } 5591 5507 5592 5508 static int _drm_edid_to_sad(const struct drm_edid *drm_edid, ··· 5858 5772 { 5859 5773 struct drm_display_info *info = &connector->display_info; 5860 5774 5861 - DRM_DEBUG_KMS("CEA VCDB 0x%02x\n", db[2]); 5775 + drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] CEA VCDB 0x%02x\n", 5776 + connector->base.id, connector->name, db[2]); 5862 5777 5863 5778 if (db[2] & EDID_CEA_VCDB_QS) 5864 5779 info->rgb_quant_range_selectable = true; ··· 6042 5955 } 6043 5956 6044 5957 drm_dbg_kms(connector->dev, 6045 - "HF-VSDB: max TMDS clock: %d KHz, HDMI 2.1 support: %s, DSC 1.2 support: %s\n", 5958 + "[CONNECTOR:%d:%s] HF-VSDB: max TMDS clock: %d KHz, HDMI 2.1 support: %s, DSC 1.2 support: %s\n", 5959 + connector->base.id, connector->name, 6046 5960 max_tmds_clock, str_yes_no(max_frl_rate), str_yes_no(dsc_support)); 6047 5961 } 6048 5962 ··· 6062 5974 if (hdmi[6] & DRM_EDID_HDMI_DC_30) { 6063 5975 dc_bpc = 10; 6064 5976 info->edid_hdmi_rgb444_dc_modes |= DRM_EDID_HDMI_DC_30; 6065 - DRM_DEBUG("%s: HDMI sink does deep color 30.\n", 6066 - connector->name); 5977 + drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] HDMI sink does deep color 30.\n", 5978 + connector->base.id, connector->name); 6067 5979 } 6068 5980 6069 5981 if (hdmi[6] & DRM_EDID_HDMI_DC_36) { 6070 5982 dc_bpc = 12; 6071 5983 info->edid_hdmi_rgb444_dc_modes |= DRM_EDID_HDMI_DC_36; 6072 - DRM_DEBUG("%s: HDMI sink does deep color 36.\n", 6073 - connector->name); 5984 + drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] HDMI sink does deep color 36.\n", 5985 + connector->base.id, connector->name); 6074 5986 } 6075 5987 6076 5988 if (hdmi[6] & DRM_EDID_HDMI_DC_48) { 6077 5989 dc_bpc = 16; 6078 5990 info->edid_hdmi_rgb444_dc_modes |= DRM_EDID_HDMI_DC_48; 6079 - DRM_DEBUG("%s: HDMI sink does deep color 48.\n", 6080 - connector->name); 5991 + drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] HDMI sink does deep color 48.\n", 5992 + connector->base.id, connector->name); 6081 5993 } 6082 5994 6083 5995 if (dc_bpc == 0) { 6084 - DRM_DEBUG("%s: No deep color support on this HDMI sink.\n", 6085 - connector->name); 5996 + drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] No deep color support on this HDMI sink.\n", 5997 + connector->base.id, connector->name); 6086 5998 return; 6087 5999 } 6088 6000 6089 - DRM_DEBUG("%s: Assigning HDMI sink color depth as %d bpc.\n", 6090 - connector->name, dc_bpc); 6001 + drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] Assigning HDMI sink color depth as %d bpc.\n", 6002 + connector->base.id, connector->name, dc_bpc); 6091 6003 info->bpc = dc_bpc; 6092 6004 6093 6005 /* YCRCB444 is optional according to spec. */ 6094 6006 if (hdmi[6] & DRM_EDID_HDMI_DC_Y444) { 6095 6007 info->edid_hdmi_ycbcr444_dc_modes = info->edid_hdmi_rgb444_dc_modes; 6096 - DRM_DEBUG("%s: HDMI sink does YCRCB444 in deep color.\n", 6097 - connector->name); 6008 + drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] HDMI sink does YCRCB444 in deep color.\n", 6009 + connector->base.id, connector->name); 6098 6010 } 6099 6011 6100 6012 /* ··· 6102 6014 * then deep color 36 bit must be supported. 6103 6015 */ 6104 6016 if (!(hdmi[6] & DRM_EDID_HDMI_DC_36)) { 6105 - DRM_DEBUG("%s: HDMI sink should do DC_36, but does not!\n", 6106 - connector->name); 6017 + drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] HDMI sink should do DC_36, but does not!\n", 6018 + connector->base.id, connector->name); 6107 6019 } 6108 6020 } 6109 6021 ··· 6120 6032 if (len >= 7) 6121 6033 info->max_tmds_clock = db[7] * 5000; 6122 6034 6123 - DRM_DEBUG_KMS("HDMI: DVI dual %d, " 6124 - "max TMDS clock %d kHz\n", 6125 - info->dvi_dual, 6126 - info->max_tmds_clock); 6035 + drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] HDMI: DVI dual %d, max TMDS clock %d kHz\n", 6036 + connector->base.id, connector->name, 6037 + info->dvi_dual, info->max_tmds_clock); 6127 6038 6128 6039 drm_parse_hdmi_deep_color_info(connector, db); 6129 6040 } ··· 6142 6055 if (version == 1 || version == 2 || (version == 3 && !desktop_usage)) 6143 6056 info->non_desktop = true; 6144 6057 6145 - drm_dbg_kms(connector->dev, "HMD or specialized display VSDB version %u: 0x%02x\n", 6146 - version, db[5]); 6058 + drm_dbg_kms(connector->dev, 6059 + "[CONNECTOR:%d:%s] HMD or specialized display VSDB version %u: 0x%02x\n", 6060 + connector->base.id, connector->name, version, db[5]); 6147 6061 } 6148 6062 6149 6063 static void drm_parse_cea_ext(struct drm_connector *connector, ··· 6165 6077 info->cea_rev = edid_ext[1]; 6166 6078 6167 6079 if (info->cea_rev != edid_ext[1]) 6168 - DRM_DEBUG_KMS("CEA extension version mismatch %u != %u\n", 6169 - info->cea_rev, edid_ext[1]); 6080 + drm_dbg_kms(connector->dev, 6081 + "[CONNECTOR:%d:%s] CEA extension version mismatch %u != %u\n", 6082 + connector->base.id, connector->name, 6083 + info->cea_rev, edid_ext[1]); 6170 6084 6171 6085 /* The existence of a CTA extension should imply RGB support */ 6172 6086 info->color_formats = DRM_COLOR_FORMAT_RGB444; ··· 6254 6164 6255 6165 drm_for_each_detailed_block(drm_edid, get_monitor_range, &closure); 6256 6166 6257 - DRM_DEBUG_KMS("Supported Monitor Refresh rate range is %d Hz - %d Hz\n", 6258 - info->monitor_range.min_vfreq, 6259 - info->monitor_range.max_vfreq); 6167 + drm_dbg_kms(connector->dev, 6168 + "[CONNECTOR:%d:%s] Supported Monitor Refresh rate range is %d Hz - %d Hz\n", 6169 + connector->base.id, connector->name, 6170 + info->monitor_range.min_vfreq, info->monitor_range.max_vfreq); 6260 6171 } 6261 6172 6262 6173 static void drm_parse_vesa_mso_data(struct drm_connector *connector, ··· 6268 6177 struct drm_display_info *info = &connector->display_info; 6269 6178 6270 6179 if (block->num_bytes < 3) { 6271 - drm_dbg_kms(connector->dev, "Unexpected vendor block size %u\n", 6272 - block->num_bytes); 6180 + drm_dbg_kms(connector->dev, 6181 + "[CONNECTOR:%d:%s] Unexpected vendor block size %u\n", 6182 + connector->base.id, connector->name, block->num_bytes); 6273 6183 return; 6274 6184 } 6275 6185 ··· 6278 6186 return; 6279 6187 6280 6188 if (sizeof(*vesa) != sizeof(*block) + block->num_bytes) { 6281 - drm_dbg_kms(connector->dev, "Unexpected VESA vendor block size\n"); 6189 + drm_dbg_kms(connector->dev, 6190 + "[CONNECTOR:%d:%s] Unexpected VESA vendor block size\n", 6191 + connector->base.id, connector->name); 6282 6192 return; 6283 6193 } 6284 6194 6285 6195 switch (FIELD_GET(DISPLAYID_VESA_MSO_MODE, vesa->mso)) { 6286 6196 default: 6287 - drm_dbg_kms(connector->dev, "Reserved MSO mode value\n"); 6197 + drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] Reserved MSO mode value\n", 6198 + connector->base.id, connector->name); 6288 6199 fallthrough; 6289 6200 case 0: 6290 6201 info->mso_stream_count = 0; ··· 6307 6212 6308 6213 info->mso_pixel_overlap = FIELD_GET(DISPLAYID_VESA_MSO_OVERLAP, vesa->mso); 6309 6214 if (info->mso_pixel_overlap > 8) { 6310 - drm_dbg_kms(connector->dev, "Reserved MSO pixel overlap value %u\n", 6215 + drm_dbg_kms(connector->dev, 6216 + "[CONNECTOR:%d:%s] Reserved MSO pixel overlap value %u\n", 6217 + connector->base.id, connector->name, 6311 6218 info->mso_pixel_overlap); 6312 6219 info->mso_pixel_overlap = 8; 6313 6220 } 6314 6221 6315 - drm_dbg_kms(connector->dev, "MSO stream count %u, pixel overlap %u\n", 6222 + drm_dbg_kms(connector->dev, 6223 + "[CONNECTOR:%d:%s] MSO stream count %u, pixel overlap %u\n", 6224 + connector->base.id, connector->name, 6316 6225 info->mso_stream_count, info->mso_pixel_overlap); 6317 6226 } 6318 6227 ··· 6399 6300 if (info->bpc == 0 && edid->revision == 3 && 6400 6301 edid->input & DRM_EDID_DIGITAL_DFP_1_X) { 6401 6302 info->bpc = 8; 6402 - DRM_DEBUG("%s: Assigning DFP sink color depth as %d bpc.\n", 6403 - connector->name, info->bpc); 6303 + drm_dbg_kms(connector->dev, 6304 + "[CONNECTOR:%d:%s] Assigning DFP sink color depth as %d bpc.\n", 6305 + connector->base.id, connector->name, info->bpc); 6404 6306 } 6405 6307 6406 6308 /* Only defined for 1.4 with digital displays */ ··· 6433 6333 break; 6434 6334 } 6435 6335 6436 - DRM_DEBUG("%s: Assigning EDID-1.4 digital sink color depth as %d bpc.\n", 6437 - connector->name, info->bpc); 6336 + drm_dbg_kms(connector->dev, 6337 + "[CONNECTOR:%d:%s] Assigning EDID-1.4 digital sink color depth as %d bpc.\n", 6338 + connector->base.id, connector->name, info->bpc); 6438 6339 6439 6340 if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB444) 6440 6341 info->color_formats |= DRM_COLOR_FORMAT_YCBCR444; ··· 6446 6345 6447 6346 out: 6448 6347 if (quirks & EDID_QUIRK_NON_DESKTOP) { 6449 - drm_dbg_kms(connector->dev, "Non-desktop display%s\n", 6348 + drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] Non-desktop display%s\n", 6349 + connector->base.id, connector->name, 6450 6350 info->non_desktop ? " (redundant quirk)" : ""); 6451 6351 info->non_desktop = true; 6452 6352 } ··· 6682 6580 { 6683 6581 int count; 6684 6582 6685 - /* 6686 - * FIXME: Reconcile the differences in override_edid handling between 6687 - * this and drm_connector_update_edid_property(). 6688 - * 6689 - * If override_edid is set, and the EDID passed in here originates from 6690 - * drm_edid_read() and friends, it will be the override EDID, and there 6691 - * are no issues. drm_connector_update_edid_property() ignoring requests 6692 - * to set the EDID dates back to a time when override EDID was not 6693 - * handled at the low level EDID read. 6694 - * 6695 - * The only way the EDID passed in here can be different from the 6696 - * override EDID is when a driver passes in an EDID that does *not* 6697 - * originate from drm_edid_read() and friends, or passes in a stale 6698 - * cached version. This, in turn, is a question of when an override EDID 6699 - * set via debugfs should take effect. 6700 - */ 6701 - 6702 6583 count = _drm_edid_connector_update(connector, drm_edid); 6703 6584 6704 6585 _drm_update_tile_info(connector, drm_edid); ··· 6696 6611 static int _drm_connector_update_edid_property(struct drm_connector *connector, 6697 6612 const struct drm_edid *drm_edid) 6698 6613 { 6699 - /* ignore requests to set edid when overridden */ 6700 - if (connector->override_edid) 6701 - return 0; 6702 - 6703 6614 /* 6704 6615 * Set the display info, using edid if available, otherwise resetting 6705 6616 * the values to defaults. This duplicates the work done in ··· 6758 6677 struct drm_edid drm_edid; 6759 6678 6760 6679 if (edid && !drm_edid_is_valid(edid)) { 6761 - drm_warn(connector->dev, "%s: EDID invalid.\n", 6762 - connector->name); 6680 + drm_warn(connector->dev, "[CONNECTOR:%d:%s] EDID invalid.\n", 6681 + connector->base.id, connector->name); 6763 6682 edid = NULL; 6764 6683 } 6765 6684 ··· 7135 7054 connector->tile_h_size = w + 1; 7136 7055 connector->tile_v_size = h + 1; 7137 7056 7138 - DRM_DEBUG_KMS("tile cap 0x%x\n", tile->tile_cap); 7139 - DRM_DEBUG_KMS("tile_size %d x %d\n", w + 1, h + 1); 7140 - DRM_DEBUG_KMS("topo num tiles %dx%d, location %dx%d\n", 7141 - num_h_tile + 1, num_v_tile + 1, tile_h_loc, tile_v_loc); 7142 - DRM_DEBUG_KMS("vend %c%c%c\n", tile->topology_id[0], tile->topology_id[1], tile->topology_id[2]); 7057 + drm_dbg_kms(connector->dev, 7058 + "[CONNECTOR:%d:%s] tile cap 0x%x, size %dx%d, num tiles %dx%d, location %dx%d, vend %c%c%c", 7059 + connector->base.id, connector->name, 7060 + tile->tile_cap, 7061 + connector->tile_h_size, connector->tile_v_size, 7062 + connector->num_h_tile, connector->num_v_tile, 7063 + connector->tile_h_loc, connector->tile_v_loc, 7064 + tile->topology_id[0], tile->topology_id[1], tile->topology_id[2]); 7143 7065 7144 7066 tg = drm_mode_get_tile_group(connector->dev, tile->topology_id); 7145 7067 if (!tg)
+31 -80
drivers/gpu/drm/drm_edid_load.c
··· 11 11 #include <linux/module.h> 12 12 #include <linux/platform_device.h> 13 13 14 - #include <drm/drm_crtc.h> 15 - #include <drm/drm_crtc_helper.h> 14 + #include <drm/drm_connector.h> 16 15 #include <drm/drm_drv.h> 17 16 #include <drm/drm_edid.h> 18 17 #include <drm/drm_print.h> 18 + 19 + #include "drm_crtc_internal.h" 19 20 20 21 static char edid_firmware[PATH_MAX]; 21 22 module_param_string(edid_firmware, edid_firmware, sizeof(edid_firmware), 0644); ··· 160 159 }, 161 160 }; 162 161 163 - static int edid_size(const u8 *edid, int data_size) 164 - { 165 - if (data_size < EDID_LENGTH) 166 - return 0; 167 - 168 - return (edid[0x7e] + 1) * EDID_LENGTH; 169 - } 170 - 171 - static void *edid_load(struct drm_connector *connector, const char *name, 172 - const char *connector_name) 162 + static const struct drm_edid *edid_load(struct drm_connector *connector, const char *name) 173 163 { 174 164 const struct firmware *fw = NULL; 175 165 const u8 *fwdata; 176 - u8 *edid; 166 + const struct drm_edid *drm_edid; 177 167 int fwsize, builtin; 178 - int i, valid_extensions = 0; 179 - bool print_bad_edid = !connector->bad_edid_counter || drm_debug_enabled(DRM_UT_KMS); 180 168 181 169 builtin = match_string(generic_edid_name, GENERIC_EDIDS, name); 182 170 if (builtin >= 0) { ··· 175 185 struct platform_device *pdev; 176 186 int err; 177 187 178 - pdev = platform_device_register_simple(connector_name, -1, NULL, 0); 188 + pdev = platform_device_register_simple(connector->name, -1, NULL, 0); 179 189 if (IS_ERR(pdev)) { 180 - DRM_ERROR("Failed to register EDID firmware platform device " 181 - "for connector \"%s\"\n", connector_name); 190 + drm_err(connector->dev, 191 + "[CONNECTOR:%d:%s] Failed to register EDID firmware platform device for connector \"%s\"\n", 192 + connector->base.id, connector->name, 193 + connector->name); 182 194 return ERR_CAST(pdev); 183 195 } 184 196 185 197 err = request_firmware(&fw, name, &pdev->dev); 186 198 platform_device_unregister(pdev); 187 199 if (err) { 188 - DRM_ERROR("Requesting EDID firmware \"%s\" failed (err=%d)\n", 189 - name, err); 200 + drm_err(connector->dev, 201 + "[CONNECTOR:%d:%s] Requesting EDID firmware \"%s\" failed (err=%d)\n", 202 + connector->base.id, connector->name, 203 + name, err); 190 204 return ERR_PTR(err); 191 205 } 192 206 ··· 198 204 fwsize = fw->size; 199 205 } 200 206 201 - if (edid_size(fwdata, fwsize) != fwsize) { 202 - DRM_ERROR("Size of EDID firmware \"%s\" is invalid " 203 - "(expected %d, got %d\n", name, 204 - edid_size(fwdata, fwsize), (int)fwsize); 205 - edid = ERR_PTR(-EINVAL); 206 - goto out; 207 + drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] Loaded %s firmware EDID \"%s\"\n", 208 + connector->base.id, connector->name, 209 + builtin >= 0 ? "built-in" : "external", name); 210 + 211 + drm_edid = drm_edid_alloc(fwdata, fwsize); 212 + if (!drm_edid_valid(drm_edid)) { 213 + drm_err(connector->dev, "Invalid firmware EDID \"%s\"\n", name); 214 + drm_edid_free(drm_edid); 215 + drm_edid = ERR_PTR(-EINVAL); 207 216 } 208 217 209 - edid = kmemdup(fwdata, fwsize, GFP_KERNEL); 210 - if (edid == NULL) { 211 - edid = ERR_PTR(-ENOMEM); 212 - goto out; 213 - } 214 - 215 - if (!drm_edid_block_valid(edid, 0, print_bad_edid, 216 - &connector->edid_corrupt)) { 217 - connector->bad_edid_counter++; 218 - DRM_ERROR("Base block of EDID firmware \"%s\" is invalid ", 219 - name); 220 - kfree(edid); 221 - edid = ERR_PTR(-EINVAL); 222 - goto out; 223 - } 224 - 225 - for (i = 1; i <= edid[0x7e]; i++) { 226 - if (i != valid_extensions + 1) 227 - memcpy(edid + (valid_extensions + 1) * EDID_LENGTH, 228 - edid + i * EDID_LENGTH, EDID_LENGTH); 229 - if (drm_edid_block_valid(edid + i * EDID_LENGTH, i, 230 - print_bad_edid, 231 - NULL)) 232 - valid_extensions++; 233 - } 234 - 235 - if (valid_extensions != edid[0x7e]) { 236 - u8 *new_edid; 237 - 238 - edid[EDID_LENGTH-1] += edid[0x7e] - valid_extensions; 239 - DRM_INFO("Found %d valid extensions instead of %d in EDID data " 240 - "\"%s\" for connector \"%s\"\n", valid_extensions, 241 - edid[0x7e], name, connector_name); 242 - edid[0x7e] = valid_extensions; 243 - 244 - new_edid = krealloc(edid, (valid_extensions + 1) * EDID_LENGTH, 245 - GFP_KERNEL); 246 - if (new_edid) 247 - edid = new_edid; 248 - } 249 - 250 - DRM_INFO("Got %s EDID base block and %d extension%s from " 251 - "\"%s\" for connector \"%s\"\n", (builtin >= 0) ? "built-in" : 252 - "external", valid_extensions, valid_extensions == 1 ? "" : "s", 253 - name, connector_name); 254 - 255 - out: 256 218 release_firmware(fw); 257 - return edid; 219 + 220 + return drm_edid; 258 221 } 259 222 260 - struct edid *drm_load_edid_firmware(struct drm_connector *connector) 223 + const struct drm_edid *drm_edid_load_firmware(struct drm_connector *connector) 261 224 { 262 - const char *connector_name = connector->name; 263 225 char *edidname, *last, *colon, *fwstr, *edidstr, *fallback = NULL; 264 - struct edid *edid; 226 + const struct drm_edid *drm_edid; 265 227 266 228 if (edid_firmware[0] == '\0') 267 229 return ERR_PTR(-ENOENT); ··· 238 288 while ((edidname = strsep(&edidstr, ","))) { 239 289 colon = strchr(edidname, ':'); 240 290 if (colon != NULL) { 241 - if (strncmp(connector_name, edidname, colon - edidname)) 291 + if (strncmp(connector->name, edidname, colon - edidname)) 242 292 continue; 243 293 edidname = colon + 1; 244 294 break; ··· 260 310 if (*last == '\n') 261 311 *last = '\0'; 262 312 263 - edid = edid_load(connector, edidname, connector_name); 313 + drm_edid = edid_load(connector, edidname); 314 + 264 315 kfree(fwstr); 265 316 266 - return edid; 317 + return drm_edid; 267 318 }
+1 -1
drivers/gpu/drm/drm_mipi_dsi.c
··· 606 606 EXPORT_SYMBOL(mipi_dsi_turn_on_peripheral); 607 607 608 608 /* 609 - * mipi_dsi_set_maximum_return_packet_size() - specify the maximum size of the 609 + * mipi_dsi_set_maximum_return_packet_size() - specify the maximum size of 610 610 * the payload in a long packet transmitted from the peripheral back to the 611 611 * host processor 612 612 * @dsi: DSI peripheral device
-3
drivers/gpu/drm/drm_mode_config.c
··· 151 151 count = 0; 152 152 connector_id = u64_to_user_ptr(card_res->connector_id_ptr); 153 153 drm_for_each_connector_iter(connector, &conn_iter) { 154 - if (connector->registration_state != DRM_CONNECTOR_REGISTERED) 155 - continue; 156 - 157 154 /* only expose writeback connectors if userspace understands them */ 158 155 if (!file_priv->writeback_connectors && 159 156 (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK))
+1 -1
drivers/gpu/drm/drm_probe_helper.c
··· 367 367 * override/firmware EDID. 368 368 */ 369 369 if (count == 0 && connector->status == connector_status_connected) 370 - count = drm_add_override_edid_modes(connector); 370 + count = drm_edid_override_connector_update(connector); 371 371 372 372 return count; 373 373 }
+1 -1
drivers/gpu/drm/drm_rect.c
··· 80 80 * @dst: destination window rectangle 81 81 * @clip: clip rectangle 82 82 * 83 - * Clip rectangle @dst by rectangle @clip. Clip rectangle @src by the 83 + * Clip rectangle @dst by rectangle @clip. Clip rectangle @src by 84 84 * the corresponding amounts, retaining the vertical and horizontal scaling 85 85 * factors from @src to @dst. 86 86 *
+7 -13
drivers/gpu/drm/i915/display/intel_hdmi.c
··· 2355 2355 } 2356 2356 2357 2357 static void 2358 - intel_hdmi_dp_dual_mode_detect(struct drm_connector *connector, bool has_edid) 2358 + intel_hdmi_dp_dual_mode_detect(struct drm_connector *connector) 2359 2359 { 2360 2360 struct drm_i915_private *dev_priv = to_i915(connector->dev); 2361 2361 struct intel_hdmi *hdmi = intel_attached_hdmi(to_intel_connector(connector)); ··· 2371 2371 * CONFIG1 pin, but no such luck on our hardware. 2372 2372 * 2373 2373 * The only method left to us is to check the VBT to see 2374 - * if the port is a dual mode capable DP port. But let's 2375 - * only do that when we sucesfully read the EDID, to avoid 2376 - * confusing log messages about DP dual mode adaptors when 2377 - * there's nothing connected to the port. 2374 + * if the port is a dual mode capable DP port. 2378 2375 */ 2379 2376 if (type == DRM_DP_DUAL_MODE_UNKNOWN) { 2380 - /* An overridden EDID imply that we want this port for testing. 2381 - * Make sure not to set limits for that port. 2382 - */ 2383 - if (has_edid && !connector->override_edid && 2377 + if (!connector->force && 2384 2378 intel_bios_is_port_dp_dual_mode(dev_priv, port)) { 2385 2379 drm_dbg_kms(&dev_priv->drm, 2386 2380 "Assuming DP dual mode adaptor presence based on VBT\n"); ··· 2429 2435 intel_gmbus_force_bit(i2c, false); 2430 2436 } 2431 2437 2432 - intel_hdmi_dp_dual_mode_detect(connector, edid != NULL); 2433 - 2434 - intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS, wakeref); 2435 - 2436 2438 to_intel_connector(connector)->detect_edid = edid; 2437 2439 if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) { 2438 2440 intel_hdmi->has_audio = drm_detect_monitor_audio(edid); 2439 2441 intel_hdmi->has_hdmi_sink = drm_detect_hdmi_monitor(edid); 2440 2442 2443 + intel_hdmi_dp_dual_mode_detect(connector); 2444 + 2441 2445 connected = true; 2442 2446 } 2447 + 2448 + intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS, wakeref); 2443 2449 2444 2450 cec_notifier_set_phys_addr_from_edid(intel_hdmi->cec_notifier, edid); 2445 2451
-1
drivers/gpu/drm/nouveau/nouveau_dmem.c
··· 33 33 #include <nvif/if000c.h> 34 34 #include <nvif/if500b.h> 35 35 #include <nvif/if900b.h> 36 - #include <nvif/if000c.h> 37 36 38 37 #include <nvhw/class/cla0b5.h> 39 38
+2
drivers/gpu/drm/panel/panel-edp.c
··· 1883 1883 EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a5d, &delay_200_500_e50, "NV116WHM-N45"), 1884 1884 EDP_PANEL_ENTRY('B', 'O', 'E', 0x0ac5, &delay_200_500_e50, "NV116WHM-N4C"), 1885 1885 1886 + EDP_PANEL_ENTRY('C', 'M', 'N', 0x1139, &delay_200_500_e80_d50, "N116BGE-EA2"), 1886 1887 EDP_PANEL_ENTRY('C', 'M', 'N', 0x114c, &innolux_n116bca_ea1.delay, "N116BCA-EA1"), 1887 1888 EDP_PANEL_ENTRY('C', 'M', 'N', 0x1152, &delay_200_500_e80_d50, "N116BCN-EA1"), 1889 + EDP_PANEL_ENTRY('C', 'M', 'N', 0x1153, &delay_200_500_e80_d50, "N116BGE-EA2"), 1888 1890 EDP_PANEL_ENTRY('C', 'M', 'N', 0x1154, &delay_200_500_e80_d50, "N116BCA-EA2"), 1889 1891 EDP_PANEL_ENTRY('C', 'M', 'N', 0x1247, &delay_200_500_e80_d50, "N120ACA-EA1"), 1890 1892
+2 -2
drivers/gpu/drm/scheduler/sched_main.c
··· 62 62 #define to_drm_sched_job(sched_job) \ 63 63 container_of((sched_job), struct drm_sched_job, queue_node) 64 64 65 - int drm_sched_policy = DRM_SCHED_POLICY_RR; 65 + int drm_sched_policy = DRM_SCHED_POLICY_FIFO; 66 66 67 67 /** 68 68 * DOC: sched_policy (int) 69 69 * Used to override default entities scheduling policy in a run queue. 70 70 */ 71 - MODULE_PARM_DESC(sched_policy, "Specify schedule policy for entities on a runqueue, " __stringify(DRM_SCHED_POLICY_RR) " = Round Robin (default), " __stringify(DRM_SCHED_POLICY_FIFO) " = use FIFO."); 71 + MODULE_PARM_DESC(sched_policy, "Specify the scheduling policy for entities on a run-queue, " __stringify(DRM_SCHED_POLICY_RR) " = Round Robin, " __stringify(DRM_SCHED_POLICY_FIFO) " = FIFO (default)."); 72 72 module_param_named(sched_policy, drm_sched_policy, int, 0444); 73 73 74 74 static __always_inline bool drm_sched_entity_compare_before(struct rb_node *a,
+272 -191
drivers/gpu/drm/tests/drm_plane_helper_test.c
··· 10 10 #include <drm/drm_atomic_helper.h> 11 11 #include <drm/drm_framebuffer.h> 12 12 #include <drm/drm_modes.h> 13 + #include <drm/drm_rect.h> 13 14 14 - static void set_src(struct drm_plane_state *plane_state, 15 - unsigned int src_x, unsigned int src_y, 16 - unsigned int src_w, unsigned int src_h) 15 + static const struct drm_crtc_state crtc_state = { 16 + .crtc = ZERO_SIZE_PTR, 17 + .enable = true, 18 + .active = true, 19 + .mode = { 20 + DRM_MODE("1024x768", 0, 65000, 1024, 1048, 21 + 1184, 1344, 0, 768, 771, 777, 806, 0, 22 + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) 23 + }, 24 + }; 25 + 26 + struct drm_check_plane_state_test { 27 + const char *name; 28 + const char *msg; 29 + struct { 30 + unsigned int x; 31 + unsigned int y; 32 + unsigned int w; 33 + unsigned int h; 34 + } src, src_expected; 35 + struct { 36 + int x; 37 + int y; 38 + unsigned int w; 39 + unsigned int h; 40 + } crtc, crtc_expected; 41 + unsigned int rotation; 42 + int min_scale; 43 + int max_scale; 44 + bool can_position; 45 + }; 46 + 47 + static int drm_plane_helper_init(struct kunit *test) 17 48 { 18 - plane_state->src_x = src_x; 19 - plane_state->src_y = src_y; 20 - plane_state->src_w = src_w; 21 - plane_state->src_h = src_h; 49 + const struct drm_check_plane_state_test *params = test->param_value; 50 + struct drm_plane *plane; 51 + struct drm_framebuffer *fb; 52 + struct drm_plane_state *mock; 53 + 54 + plane = kunit_kzalloc(test, sizeof(*plane), GFP_KERNEL); 55 + KUNIT_ASSERT_NOT_NULL(test, plane); 56 + 57 + fb = kunit_kzalloc(test, sizeof(*fb), GFP_KERNEL); 58 + KUNIT_ASSERT_NOT_NULL(test, fb); 59 + fb->width = 2048; 60 + fb->height = 2048; 61 + 62 + mock = kunit_kzalloc(test, sizeof(*mock), GFP_KERNEL); 63 + KUNIT_ASSERT_NOT_NULL(test, mock); 64 + mock->plane = plane; 65 + mock->crtc = ZERO_SIZE_PTR; 66 + mock->fb = fb; 67 + mock->rotation = params->rotation; 68 + mock->src_x = params->src.x; 69 + mock->src_y = params->src.y; 70 + mock->src_w = params->src.w; 71 + mock->src_h = params->src.h; 72 + mock->crtc_x = params->crtc.x; 73 + mock->crtc_y = params->crtc.y; 74 + mock->crtc_w = params->crtc.w; 75 + mock->crtc_h = params->crtc.h; 76 + 77 + test->priv = mock; 78 + 79 + return 0; 22 80 } 23 81 24 - static bool check_src_eq(struct drm_plane_state *plane_state, 82 + static void check_src_eq(struct kunit *test, struct drm_plane_state *plane_state, 25 83 unsigned int src_x, unsigned int src_y, 26 84 unsigned int src_w, unsigned int src_h) 27 85 { 28 - if (plane_state->src.x1 < 0) { 29 - pr_err("src x coordinate %x should never be below 0.\n", plane_state->src.x1); 30 - drm_rect_debug_print("src: ", &plane_state->src, true); 31 - return false; 32 - } 33 - if (plane_state->src.y1 < 0) { 34 - pr_err("src y coordinate %x should never be below 0.\n", plane_state->src.y1); 35 - drm_rect_debug_print("src: ", &plane_state->src, true); 36 - return false; 37 - } 86 + struct drm_rect expected = DRM_RECT_INIT(src_x, src_y, src_w, src_h); 38 87 39 - if (plane_state->src.x1 != src_x || 40 - plane_state->src.y1 != src_y || 41 - drm_rect_width(&plane_state->src) != src_w || 42 - drm_rect_height(&plane_state->src) != src_h) { 43 - drm_rect_debug_print("src: ", &plane_state->src, true); 44 - return false; 45 - } 88 + KUNIT_ASSERT_GE_MSG(test, plane_state->src.x1, 0, 89 + "src x coordinate %x should never be below 0, src: " DRM_RECT_FP_FMT, 90 + plane_state->src.x1, DRM_RECT_FP_ARG(&plane_state->src)); 46 91 47 - return true; 92 + KUNIT_ASSERT_GE_MSG(test, plane_state->src.y1, 0, 93 + "src y coordinate %x should never be below 0, src: " DRM_RECT_FP_FMT, 94 + plane_state->src.y1, DRM_RECT_FP_ARG(&plane_state->src)); 95 + 96 + KUNIT_EXPECT_TRUE_MSG(test, drm_rect_equals(&plane_state->src, &expected), 97 + "dst: " DRM_RECT_FP_FMT ", expected: " DRM_RECT_FP_FMT, 98 + DRM_RECT_FP_ARG(&plane_state->src), DRM_RECT_FP_ARG(&expected)); 48 99 } 49 100 50 - static void set_crtc(struct drm_plane_state *plane_state, 51 - int crtc_x, int crtc_y, 52 - unsigned int crtc_w, unsigned int crtc_h) 53 - { 54 - plane_state->crtc_x = crtc_x; 55 - plane_state->crtc_y = crtc_y; 56 - plane_state->crtc_w = crtc_w; 57 - plane_state->crtc_h = crtc_h; 58 - } 59 - 60 - static bool check_crtc_eq(struct drm_plane_state *plane_state, 101 + static void check_crtc_eq(struct kunit *test, struct drm_plane_state *plane_state, 61 102 int crtc_x, int crtc_y, 62 103 unsigned int crtc_w, unsigned int crtc_h) 63 104 { 64 - if (plane_state->dst.x1 != crtc_x || 65 - plane_state->dst.y1 != crtc_y || 66 - drm_rect_width(&plane_state->dst) != crtc_w || 67 - drm_rect_height(&plane_state->dst) != crtc_h) { 68 - drm_rect_debug_print("dst: ", &plane_state->dst, false); 105 + struct drm_rect expected = DRM_RECT_INIT(crtc_x, crtc_y, crtc_w, crtc_h); 69 106 70 - return false; 71 - } 72 - 73 - return true; 107 + KUNIT_EXPECT_TRUE_MSG(test, drm_rect_equals(&plane_state->dst, &expected), 108 + "dst: " DRM_RECT_FMT ", expected: " DRM_RECT_FMT, 109 + DRM_RECT_ARG(&plane_state->dst), DRM_RECT_ARG(&expected)); 74 110 } 75 111 76 112 static void drm_test_check_plane_state(struct kunit *test) 77 113 { 78 - int ret; 114 + const struct drm_check_plane_state_test *params = test->param_value; 115 + struct drm_plane_state *plane_state = test->priv; 79 116 80 - static const struct drm_crtc_state crtc_state = { 81 - .crtc = ZERO_SIZE_PTR, 82 - .enable = true, 83 - .active = true, 84 - .mode = { 85 - DRM_MODE("1024x768", 0, 65000, 1024, 1048, 1184, 1344, 0, 768, 771, 86 - 777, 806, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) 87 - }, 88 - }; 89 - static struct drm_plane plane = { 90 - .dev = NULL 91 - }; 92 - static struct drm_framebuffer fb = { 93 - .width = 2048, 94 - .height = 2048 95 - }; 96 - static struct drm_plane_state plane_state = { 97 - .plane = &plane, 98 - .crtc = ZERO_SIZE_PTR, 99 - .fb = &fb, 100 - .rotation = DRM_MODE_ROTATE_0 101 - }; 102 - 103 - /* Simple clipping, no scaling. */ 104 - set_src(&plane_state, 0, 0, fb.width << 16, fb.height << 16); 105 - set_crtc(&plane_state, 0, 0, fb.width, fb.height); 106 - ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 107 - DRM_PLANE_NO_SCALING, 108 - DRM_PLANE_NO_SCALING, 109 - false, false); 110 - KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Simple clipping check should pass\n"); 111 - KUNIT_EXPECT_TRUE(test, plane_state.visible); 112 - KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0, 0, 1024 << 16, 768 << 16)); 113 - KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 0, 0, 1024, 768)); 114 - 115 - /* Rotated clipping + reflection, no scaling. */ 116 - plane_state.rotation = DRM_MODE_ROTATE_90 | DRM_MODE_REFLECT_X; 117 - ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 118 - DRM_PLANE_NO_SCALING, 119 - DRM_PLANE_NO_SCALING, 120 - false, false); 121 - KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Rotated clipping check should pass\n"); 122 - KUNIT_EXPECT_TRUE(test, plane_state.visible); 123 - KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0, 0, 768 << 16, 1024 << 16)); 124 - KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 0, 0, 1024, 768)); 125 - plane_state.rotation = DRM_MODE_ROTATE_0; 126 - 127 - /* Check whether positioning works correctly. */ 128 - set_src(&plane_state, 0, 0, 1023 << 16, 767 << 16); 129 - set_crtc(&plane_state, 0, 0, 1023, 767); 130 - ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 131 - DRM_PLANE_NO_SCALING, 132 - DRM_PLANE_NO_SCALING, 133 - false, false); 134 - KUNIT_EXPECT_TRUE_MSG(test, ret, 135 - "Should not be able to position on the crtc with can_position=false\n"); 136 - 137 - ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 138 - DRM_PLANE_NO_SCALING, 139 - DRM_PLANE_NO_SCALING, 140 - true, false); 141 - KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Simple positioning should work\n"); 142 - KUNIT_EXPECT_TRUE(test, plane_state.visible); 143 - KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0, 0, 1023 << 16, 767 << 16)); 144 - KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 0, 0, 1023, 767)); 145 - 146 - /* Simple scaling tests. */ 147 - set_src(&plane_state, 0, 0, 512 << 16, 384 << 16); 148 - set_crtc(&plane_state, 0, 0, 1024, 768); 149 - ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 150 - 0x8001, 151 - DRM_PLANE_NO_SCALING, 152 - false, false); 153 - KUNIT_EXPECT_TRUE_MSG(test, ret, "Upscaling out of range should fail.\n"); 154 - ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 155 - 0x8000, 156 - DRM_PLANE_NO_SCALING, 157 - false, false); 158 - KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Upscaling exactly 2x should work\n"); 159 - KUNIT_EXPECT_TRUE(test, plane_state.visible); 160 - KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0, 0, 512 << 16, 384 << 16)); 161 - KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 0, 0, 1024, 768)); 162 - 163 - set_src(&plane_state, 0, 0, 2048 << 16, 1536 << 16); 164 - ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 165 - DRM_PLANE_NO_SCALING, 166 - 0x1ffff, false, false); 167 - KUNIT_EXPECT_TRUE_MSG(test, ret, "Downscaling out of range should fail.\n"); 168 - ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 169 - DRM_PLANE_NO_SCALING, 170 - 0x20000, false, false); 171 - KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Should succeed with exact scaling limit\n"); 172 - KUNIT_EXPECT_TRUE(test, plane_state.visible); 173 - KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0, 0, 2048 << 16, 1536 << 16)); 174 - KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 0, 0, 1024, 768)); 175 - 176 - /* Testing rounding errors. */ 177 - set_src(&plane_state, 0, 0, 0x40001, 0x40001); 178 - set_crtc(&plane_state, 1022, 766, 4, 4); 179 - ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 180 - DRM_PLANE_NO_SCALING, 181 - 0x10001, 182 - true, false); 183 - KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Should succeed by clipping to exact multiple"); 184 - KUNIT_EXPECT_TRUE(test, plane_state.visible); 185 - KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0, 0, 2 << 16, 2 << 16)); 186 - KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 1022, 766, 2, 2)); 187 - 188 - set_src(&plane_state, 0x20001, 0x20001, 0x4040001, 0x3040001); 189 - set_crtc(&plane_state, -2, -2, 1028, 772); 190 - ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 191 - DRM_PLANE_NO_SCALING, 192 - 0x10001, 193 - false, false); 194 - KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Should succeed by clipping to exact multiple"); 195 - KUNIT_EXPECT_TRUE(test, plane_state.visible); 196 - KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0x40002, 0x40002, 197 - 1024 << 16, 768 << 16)); 198 - KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 0, 0, 1024, 768)); 199 - 200 - set_src(&plane_state, 0, 0, 0x3ffff, 0x3ffff); 201 - set_crtc(&plane_state, 1022, 766, 4, 4); 202 - ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 203 - 0xffff, 204 - DRM_PLANE_NO_SCALING, 205 - true, false); 206 - KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Should succeed by clipping to exact multiple"); 207 - KUNIT_EXPECT_TRUE(test, plane_state.visible); 208 - /* Should not be rounded to 0x20001, which would be upscaling. */ 209 - KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0, 0, 2 << 16, 2 << 16)); 210 - KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 1022, 766, 2, 2)); 211 - 212 - set_src(&plane_state, 0x1ffff, 0x1ffff, 0x403ffff, 0x303ffff); 213 - set_crtc(&plane_state, -2, -2, 1028, 772); 214 - ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 215 - 0xffff, 216 - DRM_PLANE_NO_SCALING, 217 - false, false); 218 - KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Should succeed by clipping to exact multiple"); 219 - KUNIT_EXPECT_TRUE(test, plane_state.visible); 220 - KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0x3fffe, 0x3fffe, 221 - 1024 << 16, 768 << 16)); 222 - KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 0, 0, 1024, 768)); 117 + KUNIT_ASSERT_EQ_MSG(test, 118 + drm_atomic_helper_check_plane_state(plane_state, &crtc_state, 119 + params->min_scale, 120 + params->max_scale, 121 + params->can_position, false), 122 + 0, params->msg); 123 + KUNIT_EXPECT_TRUE(test, plane_state->visible); 124 + check_src_eq(test, plane_state, params->src_expected.x, params->src_expected.y, 125 + params->src_expected.w, params->src_expected.h); 126 + check_crtc_eq(test, plane_state, params->crtc_expected.x, params->crtc_expected.y, 127 + params->crtc_expected.w, params->crtc_expected.h); 223 128 } 224 129 130 + static void drm_check_plane_state_desc(const struct drm_check_plane_state_test *t, 131 + char *desc) 132 + { 133 + sprintf(desc, "%s", t->name); 134 + } 135 + 136 + static const struct drm_check_plane_state_test drm_check_plane_state_tests[] = { 137 + { 138 + .name = "clipping_simple", 139 + .msg = "Simple clipping check should pass", 140 + .src = { 0, 0, 141 + 2048 << 16, 142 + 2048 << 16 }, 143 + .crtc = { 0, 0, 2048, 2048 }, 144 + .rotation = DRM_MODE_ROTATE_0, 145 + .min_scale = DRM_PLANE_NO_SCALING, 146 + .max_scale = DRM_PLANE_NO_SCALING, 147 + .can_position = false, 148 + .src_expected = { 0, 0, 1024 << 16, 768 << 16 }, 149 + .crtc_expected = { 0, 0, 1024, 768 }, 150 + }, 151 + { 152 + .name = "clipping_rotate_reflect", 153 + .msg = "Rotated clipping check should pass", 154 + .src = { 0, 0, 155 + 2048 << 16, 156 + 2048 << 16 }, 157 + .crtc = { 0, 0, 2048, 2048 }, 158 + .rotation = DRM_MODE_ROTATE_90 | DRM_MODE_REFLECT_X, 159 + .min_scale = DRM_PLANE_NO_SCALING, 160 + .max_scale = DRM_PLANE_NO_SCALING, 161 + .can_position = false, 162 + .src_expected = { 0, 0, 768 << 16, 1024 << 16 }, 163 + .crtc_expected = { 0, 0, 1024, 768 }, 164 + }, 165 + { 166 + .name = "positioning_simple", 167 + .msg = "Simple positioning should work", 168 + .src = { 0, 0, 1023 << 16, 767 << 16 }, 169 + .crtc = { 0, 0, 1023, 767 }, 170 + .rotation = DRM_MODE_ROTATE_0, 171 + .min_scale = DRM_PLANE_NO_SCALING, 172 + .max_scale = DRM_PLANE_NO_SCALING, 173 + .can_position = true, 174 + .src_expected = { 0, 0, 1023 << 16, 767 << 16 }, 175 + .crtc_expected = { 0, 0, 1023, 767 }, 176 + }, 177 + { 178 + .name = "upscaling", 179 + .msg = "Upscaling exactly 2x should work", 180 + .src = { 0, 0, 512 << 16, 384 << 16 }, 181 + .crtc = { 0, 0, 1024, 768 }, 182 + .rotation = DRM_MODE_ROTATE_0, 183 + .min_scale = 0x8000, 184 + .max_scale = DRM_PLANE_NO_SCALING, 185 + .can_position = false, 186 + .src_expected = { 0, 0, 512 << 16, 384 << 16 }, 187 + .crtc_expected = { 0, 0, 1024, 768 }, 188 + }, 189 + { 190 + .name = "downscaling", 191 + .msg = "Should succeed with exact scaling limit", 192 + .src = { 0, 0, 2048 << 16, 1536 << 16 }, 193 + .crtc = { 0, 0, 1024, 768 }, 194 + .rotation = DRM_MODE_ROTATE_0, 195 + .min_scale = DRM_PLANE_NO_SCALING, 196 + .max_scale = 0x20000, 197 + .can_position = false, 198 + .src_expected = { 0, 0, 2048 << 16, 1536 << 16 }, 199 + .crtc_expected = { 0, 0, 1024, 768 }, 200 + }, 201 + { 202 + .name = "rounding1", 203 + .msg = "Should succeed by clipping to exact multiple", 204 + .src = { 0, 0, 0x40001, 0x40001 }, 205 + .crtc = { 1022, 766, 4, 4 }, 206 + .rotation = DRM_MODE_ROTATE_0, 207 + .min_scale = DRM_PLANE_NO_SCALING, 208 + .max_scale = 0x10001, 209 + .can_position = true, 210 + .src_expected = { 0, 0, 2 << 16, 2 << 16 }, 211 + .crtc_expected = { 1022, 766, 2, 2 }, 212 + }, 213 + { 214 + .name = "rounding2", 215 + .msg = "Should succeed by clipping to exact multiple", 216 + .src = { 0x20001, 0x20001, 0x4040001, 0x3040001 }, 217 + .crtc = { -2, -2, 1028, 772 }, 218 + .rotation = DRM_MODE_ROTATE_0, 219 + .min_scale = DRM_PLANE_NO_SCALING, 220 + .max_scale = 0x10001, 221 + .can_position = false, 222 + .src_expected = { 0x40002, 0x40002, 1024 << 16, 768 << 16 }, 223 + .crtc_expected = { 0, 0, 1024, 768 }, 224 + }, 225 + { 226 + .name = "rounding3", 227 + .msg = "Should succeed by clipping to exact multiple", 228 + .src = { 0, 0, 0x3ffff, 0x3ffff }, 229 + .crtc = { 1022, 766, 4, 4 }, 230 + .rotation = DRM_MODE_ROTATE_0, 231 + .min_scale = 0xffff, 232 + .max_scale = DRM_PLANE_NO_SCALING, 233 + .can_position = true, 234 + /* Should not be rounded to 0x20001, which would be upscaling. */ 235 + .src_expected = { 0, 0, 2 << 16, 2 << 16 }, 236 + .crtc_expected = { 1022, 766, 2, 2 }, 237 + }, 238 + { 239 + .name = "rounding4", 240 + .msg = "Should succeed by clipping to exact multiple", 241 + .src = { 0x1ffff, 0x1ffff, 0x403ffff, 0x303ffff }, 242 + .crtc = { -2, -2, 1028, 772 }, 243 + .rotation = DRM_MODE_ROTATE_0, 244 + .min_scale = 0xffff, 245 + .max_scale = DRM_PLANE_NO_SCALING, 246 + .can_position = false, 247 + .src_expected = { 0x3fffe, 0x3fffe, 1024 << 16, 768 << 16 }, 248 + .crtc_expected = { 0, 0, 1024, 768 }, 249 + }, 250 + }; 251 + 252 + KUNIT_ARRAY_PARAM(drm_check_plane_state, drm_check_plane_state_tests, drm_check_plane_state_desc); 253 + 254 + static void drm_test_check_invalid_plane_state(struct kunit *test) 255 + { 256 + const struct drm_check_plane_state_test *params = test->param_value; 257 + struct drm_plane_state *plane_state = test->priv; 258 + 259 + KUNIT_ASSERT_LT_MSG(test, 260 + drm_atomic_helper_check_plane_state(plane_state, &crtc_state, 261 + params->min_scale, 262 + params->max_scale, 263 + params->can_position, false), 264 + 0, params->msg); 265 + } 266 + 267 + static const struct drm_check_plane_state_test drm_check_invalid_plane_state_tests[] = { 268 + { 269 + .name = "positioning_invalid", 270 + .msg = "Should not be able to position on the crtc with can_position=false", 271 + .src = { 0, 0, 1023 << 16, 767 << 16 }, 272 + .crtc = { 0, 0, 1023, 767 }, 273 + .rotation = DRM_MODE_ROTATE_0, 274 + .min_scale = DRM_PLANE_NO_SCALING, 275 + .max_scale = DRM_PLANE_NO_SCALING, 276 + .can_position = false, 277 + }, 278 + { 279 + .name = "upscaling_invalid", 280 + .msg = "Upscaling out of range should fail", 281 + .src = { 0, 0, 512 << 16, 384 << 16 }, 282 + .crtc = { 0, 0, 1024, 768 }, 283 + .rotation = DRM_MODE_ROTATE_0, 284 + .min_scale = 0x8001, 285 + .max_scale = DRM_PLANE_NO_SCALING, 286 + .can_position = false, 287 + }, 288 + { 289 + .name = "downscaling_invalid", 290 + .msg = "Downscaling out of range should fail", 291 + .src = { 0, 0, 2048 << 16, 1536 << 16 }, 292 + .crtc = { 0, 0, 1024, 768 }, 293 + .rotation = DRM_MODE_ROTATE_0, 294 + .min_scale = DRM_PLANE_NO_SCALING, 295 + .max_scale = 0x1ffff, 296 + .can_position = false, 297 + }, 298 + }; 299 + 300 + KUNIT_ARRAY_PARAM(drm_check_invalid_plane_state, drm_check_invalid_plane_state_tests, 301 + drm_check_plane_state_desc); 302 + 225 303 static struct kunit_case drm_plane_helper_test[] = { 226 - KUNIT_CASE(drm_test_check_plane_state), 304 + KUNIT_CASE_PARAM(drm_test_check_plane_state, drm_check_plane_state_gen_params), 305 + KUNIT_CASE_PARAM(drm_test_check_invalid_plane_state, 306 + drm_check_invalid_plane_state_gen_params), 227 307 {} 228 308 }; 229 309 230 310 static struct kunit_suite drm_plane_helper_test_suite = { 231 311 .name = "drm_plane_helper", 312 + .init = drm_plane_helper_init, 232 313 .test_cases = drm_plane_helper_test, 233 314 }; 234 315
+2 -2
drivers/gpu/drm/vc4/vc4_bo.c
··· 736 736 struct vc4_bo *bo = to_vc4_bo(obj); 737 737 738 738 if (bo->validated_shader && (vma->vm_flags & VM_WRITE)) { 739 - DRM_DEBUG("mmaping of shader BOs for writing not allowed.\n"); 739 + DRM_DEBUG("mmapping of shader BOs for writing not allowed.\n"); 740 740 return -EINVAL; 741 741 } 742 742 743 743 if (bo->madv != VC4_MADV_WILLNEED) { 744 - DRM_DEBUG("mmaping of %s BO not allowed\n", 744 + DRM_DEBUG("mmapping of %s BO not allowed\n", 745 745 bo->madv == VC4_MADV_DONTNEED ? 746 746 "purgeable" : "purged"); 747 747 return -EINVAL;
-7
drivers/gpu/drm/vmwgfx/Kconfig
··· 16 16 virtual hardware. 17 17 The compiled module will be called "vmwgfx.ko". 18 18 19 - config DRM_VMWGFX_FBCON 20 - depends on DRM_VMWGFX && DRM_FBDEV_EMULATION 21 - bool "Enable framebuffer console under vmwgfx by default" 22 - help 23 - Choose this option if you are shipping a new vmwgfx 24 - userspace driver that supports using the kernel driver. 25 - 26 19 config DRM_VMWGFX_MKSSTATS 27 20 bool "Enable mksGuestStats instrumentation of vmwgfx by default" 28 21 depends on DRM_VMWGFX
+1 -3
drivers/gpu/drm/vmwgfx/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0 2 - vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_hashtab.o vmwgfx_kms.o vmwgfx_drv.o \ 2 + vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_kms.o vmwgfx_drv.o \ 3 3 vmwgfx_ioctl.o vmwgfx_resource.o vmwgfx_ttm_buffer.o \ 4 4 vmwgfx_cmd.o vmwgfx_irq.o vmwgfx_ldu.o vmwgfx_ttm_glue.o \ 5 5 vmwgfx_overlay.o vmwgfx_gmrid_manager.o vmwgfx_fence.o \ ··· 11 11 vmwgfx_validation.o vmwgfx_page_dirty.o vmwgfx_streamoutput.o \ 12 12 vmwgfx_devcaps.o ttm_object.o vmwgfx_system_manager.o \ 13 13 vmwgfx_gem.o 14 - 15 - vmwgfx-$(CONFIG_DRM_FBDEV_EMULATION) += vmwgfx_fb.o 16 14 17 15 obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o
+60 -63
drivers/gpu/drm/vmwgfx/ttm_object.c
··· 1 1 /* SPDX-License-Identifier: GPL-2.0 OR MIT */ 2 2 /************************************************************************** 3 3 * 4 - * Copyright (c) 2009-2013 VMware, Inc., Palo Alto, CA., USA 4 + * Copyright (c) 2009-2022 VMware, Inc., Palo Alto, CA., USA 5 5 * All Rights Reserved. 6 6 * 7 7 * Permission is hereby granted, free of charge, to any person obtaining a ··· 44 44 45 45 #define pr_fmt(fmt) "[TTM] " fmt 46 46 47 + #include "ttm_object.h" 48 + #include "vmwgfx_drv.h" 49 + 47 50 #include <linux/list.h> 48 51 #include <linux/spinlock.h> 49 52 #include <linux/slab.h> 50 53 #include <linux/atomic.h> 51 54 #include <linux/module.h> 52 - #include "ttm_object.h" 53 - #include "vmwgfx_drv.h" 55 + #include <linux/hashtable.h> 54 56 55 57 MODULE_IMPORT_NS(DMA_BUF); 58 + 59 + #define VMW_TTM_OBJECT_REF_HT_ORDER 10 56 60 57 61 /** 58 62 * struct ttm_object_file ··· 78 74 struct ttm_object_device *tdev; 79 75 spinlock_t lock; 80 76 struct list_head ref_list; 81 - struct vmwgfx_open_hash ref_hash; 77 + DECLARE_HASHTABLE(ref_hash, VMW_TTM_OBJECT_REF_HT_ORDER); 82 78 struct kref refcount; 83 79 }; 84 80 85 81 /* 86 82 * struct ttm_object_device 87 83 * 88 - * @object_lock: lock that protects the object_hash hash table. 89 - * 90 - * @object_hash: hash table for fast lookup of object global names. 84 + * @object_lock: lock that protects idr. 91 85 * 92 86 * @object_count: Per device object count. 93 87 * ··· 94 92 95 93 struct ttm_object_device { 96 94 spinlock_t object_lock; 97 - struct vmwgfx_open_hash object_hash; 98 95 atomic_t object_count; 99 96 struct dma_buf_ops ops; 100 97 void (*dmabuf_release)(struct dma_buf *dma_buf); ··· 137 136 { 138 137 kref_get(&tfile->refcount); 139 138 return tfile; 139 + } 140 + 141 + static int ttm_tfile_find_ref_rcu(struct ttm_object_file *tfile, 142 + uint64_t key, 143 + struct vmwgfx_hash_item **p_hash) 144 + { 145 + struct vmwgfx_hash_item *hash; 146 + 147 + hash_for_each_possible_rcu(tfile->ref_hash, hash, head, key) { 148 + if (hash->key == key) { 149 + *p_hash = hash; 150 + return 0; 151 + } 152 + } 153 + return -EINVAL; 154 + } 155 + 156 + static int ttm_tfile_find_ref(struct ttm_object_file *tfile, 157 + uint64_t key, 158 + struct vmwgfx_hash_item **p_hash) 159 + { 160 + struct vmwgfx_hash_item *hash; 161 + 162 + hash_for_each_possible(tfile->ref_hash, hash, head, key) { 163 + if (hash->key == key) { 164 + *p_hash = hash; 165 + return 0; 166 + } 167 + } 168 + return -EINVAL; 140 169 } 141 170 142 171 static void ttm_object_file_destroy(struct kref *kref) ··· 271 240 * Return: A pointer to the object if successful or NULL otherwise. 272 241 */ 273 242 struct ttm_base_object * 274 - ttm_base_object_noref_lookup(struct ttm_object_file *tfile, uint32_t key) 243 + ttm_base_object_noref_lookup(struct ttm_object_file *tfile, uint64_t key) 275 244 { 276 245 struct vmwgfx_hash_item *hash; 277 - struct vmwgfx_open_hash *ht = &tfile->ref_hash; 278 246 int ret; 279 247 280 248 rcu_read_lock(); 281 - ret = vmwgfx_ht_find_item_rcu(ht, key, &hash); 249 + ret = ttm_tfile_find_ref_rcu(tfile, key, &hash); 282 250 if (ret) { 283 251 rcu_read_unlock(); 284 252 return NULL; 285 253 } 286 254 287 255 __release(RCU); 288 - return drm_hash_entry(hash, struct ttm_ref_object, hash)->obj; 256 + return hlist_entry(hash, struct ttm_ref_object, hash)->obj; 289 257 } 290 258 EXPORT_SYMBOL(ttm_base_object_noref_lookup); 291 259 292 260 struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file *tfile, 293 - uint32_t key) 261 + uint64_t key) 294 262 { 295 263 struct ttm_base_object *base = NULL; 296 264 struct vmwgfx_hash_item *hash; 297 - struct vmwgfx_open_hash *ht = &tfile->ref_hash; 298 265 int ret; 299 266 300 267 rcu_read_lock(); 301 - ret = vmwgfx_ht_find_item_rcu(ht, key, &hash); 268 + ret = ttm_tfile_find_ref_rcu(tfile, key, &hash); 302 269 303 270 if (likely(ret == 0)) { 304 - base = drm_hash_entry(hash, struct ttm_ref_object, hash)->obj; 271 + base = hlist_entry(hash, struct ttm_ref_object, hash)->obj; 305 272 if (!kref_get_unless_zero(&base->refcount)) 306 273 base = NULL; 307 274 } ··· 309 280 } 310 281 311 282 struct ttm_base_object * 312 - ttm_base_object_lookup_for_ref(struct ttm_object_device *tdev, uint32_t key) 283 + ttm_base_object_lookup_for_ref(struct ttm_object_device *tdev, uint64_t key) 313 284 { 314 285 struct ttm_base_object *base; 315 286 ··· 328 299 bool *existed, 329 300 bool require_existed) 330 301 { 331 - struct vmwgfx_open_hash *ht = &tfile->ref_hash; 332 302 struct ttm_ref_object *ref; 333 303 struct vmwgfx_hash_item *hash; 334 304 int ret = -EINVAL; ··· 340 312 341 313 while (ret == -EINVAL) { 342 314 rcu_read_lock(); 343 - ret = vmwgfx_ht_find_item_rcu(ht, base->handle, &hash); 315 + ret = ttm_tfile_find_ref_rcu(tfile, base->handle, &hash); 344 316 345 317 if (ret == 0) { 346 - ref = drm_hash_entry(hash, struct ttm_ref_object, hash); 318 + ref = hlist_entry(hash, struct ttm_ref_object, hash); 347 319 if (kref_get_unless_zero(&ref->kref)) { 348 320 rcu_read_unlock(); 349 321 break; ··· 365 337 kref_init(&ref->kref); 366 338 367 339 spin_lock(&tfile->lock); 368 - ret = vmwgfx_ht_insert_item_rcu(ht, &ref->hash); 340 + hash_add_rcu(tfile->ref_hash, &ref->hash.head, ref->hash.key); 341 + ret = 0; 369 342 370 - if (likely(ret == 0)) { 371 - list_add_tail(&ref->head, &tfile->ref_list); 372 - kref_get(&base->refcount); 373 - spin_unlock(&tfile->lock); 374 - if (existed != NULL) 375 - *existed = false; 376 - break; 377 - } 378 - 343 + list_add_tail(&ref->head, &tfile->ref_list); 344 + kref_get(&base->refcount); 379 345 spin_unlock(&tfile->lock); 380 - BUG_ON(ret != -EINVAL); 381 - 382 - kfree(ref); 346 + if (existed != NULL) 347 + *existed = false; 383 348 } 384 349 385 350 return ret; ··· 384 363 struct ttm_ref_object *ref = 385 364 container_of(kref, struct ttm_ref_object, kref); 386 365 struct ttm_object_file *tfile = ref->tfile; 387 - struct vmwgfx_open_hash *ht; 388 366 389 - ht = &tfile->ref_hash; 390 - (void)vmwgfx_ht_remove_item_rcu(ht, &ref->hash); 367 + hash_del_rcu(&ref->hash.head); 391 368 list_del(&ref->head); 392 369 spin_unlock(&tfile->lock); 393 370 ··· 397 378 int ttm_ref_object_base_unref(struct ttm_object_file *tfile, 398 379 unsigned long key) 399 380 { 400 - struct vmwgfx_open_hash *ht = &tfile->ref_hash; 401 381 struct ttm_ref_object *ref; 402 382 struct vmwgfx_hash_item *hash; 403 383 int ret; 404 384 405 385 spin_lock(&tfile->lock); 406 - ret = vmwgfx_ht_find_item(ht, key, &hash); 386 + ret = ttm_tfile_find_ref(tfile, key, &hash); 407 387 if (unlikely(ret != 0)) { 408 388 spin_unlock(&tfile->lock); 409 389 return -EINVAL; 410 390 } 411 - ref = drm_hash_entry(hash, struct ttm_ref_object, hash); 391 + ref = hlist_entry(hash, struct ttm_ref_object, hash); 412 392 kref_put(&ref->kref, ttm_ref_object_release); 413 393 spin_unlock(&tfile->lock); 414 394 return 0; ··· 434 416 } 435 417 436 418 spin_unlock(&tfile->lock); 437 - vmwgfx_ht_remove(&tfile->ref_hash); 438 419 439 420 ttm_object_file_unref(&tfile); 440 421 } 441 422 442 - struct ttm_object_file *ttm_object_file_init(struct ttm_object_device *tdev, 443 - unsigned int hash_order) 423 + struct ttm_object_file *ttm_object_file_init(struct ttm_object_device *tdev) 444 424 { 445 425 struct ttm_object_file *tfile = kmalloc(sizeof(*tfile), GFP_KERNEL); 446 - int ret; 447 426 448 427 if (unlikely(tfile == NULL)) 449 428 return NULL; ··· 450 435 kref_init(&tfile->refcount); 451 436 INIT_LIST_HEAD(&tfile->ref_list); 452 437 453 - ret = vmwgfx_ht_create(&tfile->ref_hash, hash_order); 454 - if (ret) 455 - goto out_err; 438 + hash_init(tfile->ref_hash); 456 439 457 440 return tfile; 458 - out_err: 459 - vmwgfx_ht_remove(&tfile->ref_hash); 460 - 461 - kfree(tfile); 462 - 463 - return NULL; 464 441 } 465 442 466 443 struct ttm_object_device * 467 - ttm_object_device_init(unsigned int hash_order, 468 - const struct dma_buf_ops *ops) 444 + ttm_object_device_init(const struct dma_buf_ops *ops) 469 445 { 470 446 struct ttm_object_device *tdev = kmalloc(sizeof(*tdev), GFP_KERNEL); 471 - int ret; 472 447 473 448 if (unlikely(tdev == NULL)) 474 449 return NULL; 475 450 476 451 spin_lock_init(&tdev->object_lock); 477 452 atomic_set(&tdev->object_count, 0); 478 - ret = vmwgfx_ht_create(&tdev->object_hash, hash_order); 479 - if (ret != 0) 480 - goto out_no_object_hash; 481 453 482 454 /* 483 455 * Our base is at VMWGFX_NUM_MOB + 1 because we want to create ··· 479 477 tdev->dmabuf_release = tdev->ops.release; 480 478 tdev->ops.release = ttm_prime_dmabuf_release; 481 479 return tdev; 482 - 483 - out_no_object_hash: 484 - kfree(tdev); 485 - return NULL; 486 480 } 487 481 488 482 void ttm_object_device_release(struct ttm_object_device **p_tdev) ··· 489 491 490 492 WARN_ON_ONCE(!idr_is_empty(&tdev->idr)); 491 493 idr_destroy(&tdev->idr); 492 - vmwgfx_ht_remove(&tdev->object_hash); 493 494 494 495 kfree(tdev); 495 496 }
+7 -13
drivers/gpu/drm/vmwgfx/ttm_object.h
··· 1 1 /************************************************************************** 2 2 * 3 - * Copyright (c) 2006-2009 VMware, Inc., Palo Alto, CA., USA 3 + * Copyright (c) 2006-2022 VMware, Inc., Palo Alto, CA., USA 4 4 * All Rights Reserved. 5 5 * 6 6 * Permission is hereby granted, free of charge, to any person obtaining a ··· 41 41 #include <linux/kref.h> 42 42 #include <linux/list.h> 43 43 #include <linux/rcupdate.h> 44 - 45 - #include "vmwgfx_hashtab.h" 46 44 47 45 /** 48 46 * enum ttm_object_type ··· 102 104 struct ttm_object_file *tfile; 103 105 struct kref refcount; 104 106 void (*refcount_release) (struct ttm_base_object **base); 105 - u32 handle; 107 + u64 handle; 106 108 enum ttm_object_type object_type; 107 109 u32 shareable; 108 110 }; ··· 162 164 */ 163 165 164 166 extern struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file 165 - *tfile, uint32_t key); 167 + *tfile, uint64_t key); 166 168 167 169 /** 168 170 * ttm_base_object_lookup_for_ref ··· 176 178 */ 177 179 178 180 extern struct ttm_base_object * 179 - ttm_base_object_lookup_for_ref(struct ttm_object_device *tdev, uint32_t key); 181 + ttm_base_object_lookup_for_ref(struct ttm_object_device *tdev, uint64_t key); 180 182 181 183 /** 182 184 * ttm_base_object_unref ··· 235 237 * ttm_object_file_init - initialize a struct ttm_object file 236 238 * 237 239 * @tdev: A struct ttm_object device this file is initialized on. 238 - * @hash_order: Order of the hash table used to hold the reference objects. 239 240 * 240 241 * This is typically called by the file_ops::open function. 241 242 */ 242 243 243 244 extern struct ttm_object_file *ttm_object_file_init(struct ttm_object_device 244 - *tdev, 245 - unsigned int hash_order); 245 + *tdev); 246 246 247 247 /** 248 248 * ttm_object_file_release - release data held by a ttm_object_file ··· 258 262 /** 259 263 * ttm_object device init - initialize a struct ttm_object_device 260 264 * 261 - * @hash_order: Order of hash table used to hash the base objects. 262 265 * @ops: DMA buf ops for prime objects of this device. 263 266 * 264 267 * This function is typically called on device initialization to prepare ··· 265 270 */ 266 271 267 272 extern struct ttm_object_device * 268 - ttm_object_device_init(unsigned int hash_order, 269 - const struct dma_buf_ops *ops); 273 + ttm_object_device_init(const struct dma_buf_ops *ops); 270 274 271 275 /** 272 276 * ttm_object_device_release - release data held by a ttm_object_device ··· 308 314 kfree_rcu(__obj, __prime.base.rhead) 309 315 310 316 struct ttm_base_object * 311 - ttm_base_object_noref_lookup(struct ttm_object_file *tfile, uint32_t key); 317 + ttm_base_object_noref_lookup(struct ttm_object_file *tfile, uint64_t key); 312 318 313 319 /** 314 320 * ttm_base_object_noref_release - release a base object pointer looked up
+15 -1
drivers/gpu/drm/vmwgfx/vmwgfx_bo.c
··· 807 807 { 808 808 struct vmw_private *dev_priv = vmw_priv(dev); 809 809 struct vmw_buffer_object *vbo; 810 + int cpp = DIV_ROUND_UP(args->bpp, 8); 810 811 int ret; 811 812 812 - args->pitch = args->width * ((args->bpp + 7) / 8); 813 + switch (cpp) { 814 + case 1: /* DRM_FORMAT_C8 */ 815 + case 2: /* DRM_FORMAT_RGB565 */ 816 + case 4: /* DRM_FORMAT_XRGB8888 */ 817 + break; 818 + default: 819 + /* 820 + * Dumb buffers don't allow anything else. 821 + * This is tested via IGT's dumb_buffers 822 + */ 823 + return -EINVAL; 824 + } 825 + 826 + args->pitch = args->width * cpp; 813 827 args->size = ALIGN(args->pitch * args->height, PAGE_SIZE); 814 828 815 829 ret = vmw_gem_object_create_with_handle(dev_priv, file_priv,
+26 -36
drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 OR MIT 2 2 /************************************************************************** 3 3 * 4 - * Copyright 2014-2015 VMware, Inc., Palo Alto, CA., USA 4 + * Copyright 2014-2022 VMware, Inc., Palo Alto, CA., USA 5 5 * 6 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 7 * copy of this software and associated documentation files (the ··· 27 27 28 28 #include "vmwgfx_drv.h" 29 29 #include "vmwgfx_resource_priv.h" 30 + 31 + #include <linux/hashtable.h> 30 32 31 33 #define VMW_CMDBUF_RES_MAN_HT_ORDER 12 32 34 ··· 61 59 * @resources and @list are protected by the cmdbuf mutex for now. 62 60 */ 63 61 struct vmw_cmdbuf_res_manager { 64 - struct vmwgfx_open_hash resources; 62 + DECLARE_HASHTABLE(resources, VMW_CMDBUF_RES_MAN_HT_ORDER); 65 63 struct list_head list; 66 64 struct vmw_private *dev_priv; 67 65 }; ··· 84 82 u32 user_key) 85 83 { 86 84 struct vmwgfx_hash_item *hash; 87 - int ret; 88 85 unsigned long key = user_key | (res_type << 24); 89 86 90 - ret = vmwgfx_ht_find_item(&man->resources, key, &hash); 91 - if (unlikely(ret != 0)) 92 - return ERR_PTR(ret); 93 - 94 - return drm_hash_entry(hash, struct vmw_cmdbuf_res, hash)->res; 87 + hash_for_each_possible_rcu(man->resources, hash, head, key) { 88 + if (hash->key == key) 89 + return hlist_entry(hash, struct vmw_cmdbuf_res, hash)->res; 90 + } 91 + return ERR_PTR(-EINVAL); 95 92 } 96 93 97 94 /** ··· 106 105 struct vmw_cmdbuf_res *entry) 107 106 { 108 107 list_del(&entry->head); 109 - WARN_ON(vmwgfx_ht_remove_item(&man->resources, &entry->hash)); 108 + hash_del_rcu(&entry->hash.head); 110 109 vmw_resource_unreference(&entry->res); 111 110 kfree(entry); 112 111 } ··· 160 159 void vmw_cmdbuf_res_revert(struct list_head *list) 161 160 { 162 161 struct vmw_cmdbuf_res *entry, *next; 163 - int ret; 164 162 165 163 list_for_each_entry_safe(entry, next, list, head) { 166 164 switch (entry->state) { ··· 167 167 vmw_cmdbuf_res_free(entry->man, entry); 168 168 break; 169 169 case VMW_CMDBUF_RES_DEL: 170 - ret = vmwgfx_ht_insert_item(&entry->man->resources, &entry->hash); 171 - BUG_ON(ret); 170 + hash_add_rcu(entry->man->resources, &entry->hash.head, 171 + entry->hash.key); 172 172 list_move_tail(&entry->head, &entry->man->list); 173 173 entry->state = VMW_CMDBUF_RES_COMMITTED; 174 174 break; ··· 199 199 struct list_head *list) 200 200 { 201 201 struct vmw_cmdbuf_res *cres; 202 - int ret; 203 202 204 203 cres = kzalloc(sizeof(*cres), GFP_KERNEL); 205 204 if (unlikely(!cres)) 206 205 return -ENOMEM; 207 206 208 207 cres->hash.key = user_key | (res_type << 24); 209 - ret = vmwgfx_ht_insert_item(&man->resources, &cres->hash); 210 - if (unlikely(ret != 0)) { 211 - kfree(cres); 212 - goto out_invalid_key; 213 - } 208 + hash_add_rcu(man->resources, &cres->hash.head, cres->hash.key); 214 209 215 210 cres->state = VMW_CMDBUF_RES_ADD; 216 211 cres->res = vmw_resource_reference(res); 217 212 cres->man = man; 218 213 list_add_tail(&cres->head, list); 219 214 220 - out_invalid_key: 221 - return ret; 215 + return 0; 222 216 } 223 217 224 218 /** ··· 237 243 struct list_head *list, 238 244 struct vmw_resource **res_p) 239 245 { 240 - struct vmw_cmdbuf_res *entry; 246 + struct vmw_cmdbuf_res *entry = NULL; 241 247 struct vmwgfx_hash_item *hash; 242 - int ret; 248 + unsigned long key = user_key | (res_type << 24); 243 249 244 - ret = vmwgfx_ht_find_item(&man->resources, user_key | (res_type << 24), 245 - &hash); 246 - if (likely(ret != 0)) 250 + hash_for_each_possible_rcu(man->resources, hash, head, key) { 251 + if (hash->key == key) { 252 + entry = hlist_entry(hash, struct vmw_cmdbuf_res, hash); 253 + break; 254 + } 255 + } 256 + if (unlikely(!entry)) 247 257 return -EINVAL; 248 - 249 - entry = drm_hash_entry(hash, struct vmw_cmdbuf_res, hash); 250 258 251 259 switch (entry->state) { 252 260 case VMW_CMDBUF_RES_ADD: ··· 256 260 *res_p = NULL; 257 261 break; 258 262 case VMW_CMDBUF_RES_COMMITTED: 259 - (void) vmwgfx_ht_remove_item(&man->resources, &entry->hash); 263 + hash_del_rcu(&entry->hash.head); 260 264 list_del(&entry->head); 261 265 entry->state = VMW_CMDBUF_RES_DEL; 262 266 list_add_tail(&entry->head, list); ··· 283 287 vmw_cmdbuf_res_man_create(struct vmw_private *dev_priv) 284 288 { 285 289 struct vmw_cmdbuf_res_manager *man; 286 - int ret; 287 290 288 291 man = kzalloc(sizeof(*man), GFP_KERNEL); 289 292 if (!man) ··· 290 295 291 296 man->dev_priv = dev_priv; 292 297 INIT_LIST_HEAD(&man->list); 293 - ret = vmwgfx_ht_create(&man->resources, VMW_CMDBUF_RES_MAN_HT_ORDER); 294 - if (ret == 0) 295 - return man; 296 - 297 - kfree(man); 298 - return ERR_PTR(ret); 298 + hash_init(man->resources); 299 + return man; 299 300 } 300 301 301 302 /** ··· 311 320 list_for_each_entry_safe(entry, next, &man->list, head) 312 321 vmw_cmdbuf_res_free(man, entry); 313 322 314 - vmwgfx_ht_remove(&man->resources); 315 323 kfree(man); 316 324 } 317 325
+25 -4
drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c
··· 33 33 #include <drm/ttm/ttm_placement.h> 34 34 35 35 #include "vmwgfx_drv.h" 36 + #include "vmwgfx_mksstat.h" 36 37 #include "vmwgfx_resource_priv.h" 37 38 #include "vmwgfx_so.h" 38 39 ··· 73 72 bool); 74 73 }; 75 74 75 + 76 + /* 77 + * Getting the initial size right is difficult because it all depends 78 + * on what the userspace is doing. The sizes will be aligned up to 79 + * a PAGE_SIZE so we just want to make sure that for majority of apps 80 + * the initial number of entries doesn't require an immediate resize. 81 + * For all cotables except SVGACOTableDXElementLayoutEntry and 82 + * SVGACOTableDXBlendStateEntry the initial number of entries fits 83 + * within the PAGE_SIZE. For SVGACOTableDXElementLayoutEntry and 84 + * SVGACOTableDXBlendStateEntry we want to reserve two pages, 85 + * because that's what all apps will require initially. 86 + */ 76 87 static const struct vmw_cotable_info co_info[] = { 77 88 {1, sizeof(SVGACOTableDXRTViewEntry), &vmw_view_cotable_list_destroy}, 78 89 {1, sizeof(SVGACOTableDXDSViewEntry), &vmw_view_cotable_list_destroy}, 79 90 {1, sizeof(SVGACOTableDXSRViewEntry), &vmw_view_cotable_list_destroy}, 80 - {1, sizeof(SVGACOTableDXElementLayoutEntry), NULL}, 81 - {1, sizeof(SVGACOTableDXBlendStateEntry), NULL}, 91 + {PAGE_SIZE/sizeof(SVGACOTableDXElementLayoutEntry) + 1, sizeof(SVGACOTableDXElementLayoutEntry), NULL}, 92 + {PAGE_SIZE/sizeof(SVGACOTableDXBlendStateEntry) + 1, sizeof(SVGACOTableDXBlendStateEntry), NULL}, 82 93 {1, sizeof(SVGACOTableDXDepthStencilEntry), NULL}, 83 94 {1, sizeof(SVGACOTableDXRasterizerStateEntry), NULL}, 84 95 {1, sizeof(SVGACOTableDXSamplerEntry), NULL}, ··· 408 395 int ret; 409 396 size_t i; 410 397 398 + MKS_STAT_TIME_DECL(MKSSTAT_KERN_COTABLE_RESIZE); 399 + MKS_STAT_TIME_PUSH(MKSSTAT_KERN_COTABLE_RESIZE); 400 + 411 401 ret = vmw_cotable_readback(res); 412 402 if (ret) 413 - return ret; 403 + goto out_done; 414 404 415 405 cur_size_read_back = vcotbl->size_read_back; 416 406 vcotbl->size_read_back = old_size_read_back; ··· 427 411 true, true, vmw_bo_bo_free, &buf); 428 412 if (ret) { 429 413 DRM_ERROR("Failed initializing new cotable MOB.\n"); 430 - return ret; 414 + goto out_done; 431 415 } 432 416 433 417 bo = &buf->base; ··· 501 485 /* Release the pin acquired in vmw_bo_init */ 502 486 ttm_bo_unpin(bo); 503 487 488 + MKS_STAT_TIME_POP(MKSSTAT_KERN_COTABLE_RESIZE); 489 + 504 490 return 0; 505 491 506 492 out_map_new: ··· 511 493 ttm_bo_unpin(bo); 512 494 ttm_bo_unreserve(bo); 513 495 vmw_bo_unreference(&buf); 496 + 497 + out_done: 498 + MKS_STAT_TIME_POP(MKSSTAT_KERN_COTABLE_RESIZE); 514 499 515 500 return ret; 516 501 }
+71 -58
drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
··· 25 25 * 26 26 **************************************************************************/ 27 27 28 - #include <linux/dma-mapping.h> 29 - #include <linux/module.h> 30 - #include <linux/pci.h> 31 - #include <linux/cc_platform.h> 28 + 29 + #include "vmwgfx_drv.h" 30 + 31 + #include "vmwgfx_devcaps.h" 32 + #include "vmwgfx_mksstat.h" 33 + #include "vmwgfx_binding.h" 34 + #include "ttm_object.h" 32 35 33 36 #include <drm/drm_aperture.h> 34 37 #include <drm/drm_drv.h> 38 + #include <drm/drm_fb_helper.h> 35 39 #include <drm/drm_gem_ttm_helper.h> 36 40 #include <drm/drm_ioctl.h> 37 41 #include <drm/drm_module.h> ··· 45 41 #include <drm/ttm/ttm_placement.h> 46 42 #include <generated/utsrelease.h> 47 43 48 - #include "ttm_object.h" 49 - #include "vmwgfx_binding.h" 50 - #include "vmwgfx_devcaps.h" 51 - #include "vmwgfx_drv.h" 52 - #include "vmwgfx_mksstat.h" 44 + #include <linux/cc_platform.h> 45 + #include <linux/dma-mapping.h> 46 + #include <linux/module.h> 47 + #include <linux/pci.h> 48 + #include <linux/version.h> 53 49 54 50 #define VMWGFX_DRIVER_DESC "Linux drm driver for VMware graphics devices" 55 - 56 - #define VMW_MIN_INITIAL_WIDTH 800 57 - #define VMW_MIN_INITIAL_HEIGHT 600 58 51 59 52 /* 60 53 * Fully encoded drm commands. Might move to vmw_drm.h ··· 263 262 }; 264 263 MODULE_DEVICE_TABLE(pci, vmw_pci_id_list); 265 264 266 - static int enable_fbdev = IS_ENABLED(CONFIG_DRM_VMWGFX_FBCON); 267 265 static int vmw_restrict_iommu; 268 266 static int vmw_force_coherent; 269 267 static int vmw_restrict_dma_mask; ··· 272 272 static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val, 273 273 void *ptr); 274 274 275 - MODULE_PARM_DESC(enable_fbdev, "Enable vmwgfx fbdev"); 276 - module_param_named(enable_fbdev, enable_fbdev, int, 0600); 277 275 MODULE_PARM_DESC(restrict_iommu, "Try to limit IOMMU usage for TTM pages"); 278 276 module_param_named(restrict_iommu, vmw_restrict_iommu, int, 0600); 279 277 MODULE_PARM_DESC(force_coherent, "Force coherent TTM pages"); ··· 621 623 width = vmw_read(dev_priv, SVGA_REG_WIDTH); 622 624 height = vmw_read(dev_priv, SVGA_REG_HEIGHT); 623 625 624 - width = max_t(uint32_t, width, VMW_MIN_INITIAL_WIDTH); 625 - height = max_t(uint32_t, height, VMW_MIN_INITIAL_HEIGHT); 626 + width = max_t(uint32_t, width, VMWGFX_MIN_INITIAL_WIDTH); 627 + height = max_t(uint32_t, height, VMWGFX_MIN_INITIAL_HEIGHT); 626 628 627 629 if (width > dev_priv->fb_max_width || 628 630 height > dev_priv->fb_max_height) { ··· 631 633 * This is a host error and shouldn't occur. 632 634 */ 633 635 634 - width = VMW_MIN_INITIAL_WIDTH; 635 - height = VMW_MIN_INITIAL_HEIGHT; 636 + width = VMWGFX_MIN_INITIAL_WIDTH; 637 + height = VMWGFX_MIN_INITIAL_HEIGHT; 636 638 } 637 639 638 640 dev_priv->initial_width = width; ··· 804 806 return 0; 805 807 } 806 808 809 + static void vmw_write_driver_id(struct vmw_private *dev) 810 + { 811 + if ((dev->capabilities2 & SVGA_CAP2_DX2) != 0) { 812 + vmw_write(dev, SVGA_REG_GUEST_DRIVER_ID, 813 + SVGA_REG_GUEST_DRIVER_ID_LINUX); 814 + 815 + vmw_write(dev, SVGA_REG_GUEST_DRIVER_VERSION1, 816 + LINUX_VERSION_MAJOR << 24 | 817 + LINUX_VERSION_PATCHLEVEL << 16 | 818 + LINUX_VERSION_SUBLEVEL); 819 + vmw_write(dev, SVGA_REG_GUEST_DRIVER_VERSION2, 820 + VMWGFX_DRIVER_MAJOR << 24 | 821 + VMWGFX_DRIVER_MINOR << 16 | 822 + VMWGFX_DRIVER_PATCHLEVEL); 823 + vmw_write(dev, SVGA_REG_GUEST_DRIVER_VERSION3, 0); 824 + 825 + vmw_write(dev, SVGA_REG_GUEST_DRIVER_ID, 826 + SVGA_REG_GUEST_DRIVER_ID_SUBMIT); 827 + } 828 + } 829 + 830 + static void vmw_sw_context_init(struct vmw_private *dev_priv) 831 + { 832 + struct vmw_sw_context *sw_context = &dev_priv->ctx; 833 + 834 + hash_init(sw_context->res_ht); 835 + } 836 + 837 + static void vmw_sw_context_fini(struct vmw_private *dev_priv) 838 + { 839 + struct vmw_sw_context *sw_context = &dev_priv->ctx; 840 + 841 + vfree(sw_context->cmd_bounce); 842 + if (sw_context->staged_bindings) 843 + vmw_binding_state_free(sw_context->staged_bindings); 844 + } 845 + 807 846 static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id) 808 847 { 809 848 int ret; ··· 849 814 struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); 850 815 851 816 dev_priv->drm.dev_private = dev_priv; 817 + 818 + vmw_sw_context_init(dev_priv); 852 819 853 820 mutex_init(&dev_priv->cmdbuf_mutex); 854 821 mutex_init(&dev_priv->binding_mutex); ··· 880 843 dev_priv->used_memory_size = 0; 881 844 882 845 dev_priv->assume_16bpp = !!vmw_assume_16bpp; 883 - 884 - dev_priv->enable_fb = enable_fbdev; 885 - 886 846 887 847 dev_priv->capabilities = vmw_read(dev_priv, SVGA_REG_CAPABILITIES); 888 848 vmw_print_bitmap(&dev_priv->drm, "Capabilities", ··· 1004 970 goto out_err0; 1005 971 } 1006 972 1007 - dev_priv->tdev = ttm_object_device_init(12, &vmw_prime_dmabuf_ops); 973 + dev_priv->tdev = ttm_object_device_init(&vmw_prime_dmabuf_ops); 1008 974 1009 975 if (unlikely(dev_priv->tdev == NULL)) { 1010 976 drm_err(&dev_priv->drm, ··· 1125 1091 vmw_host_printf("vmwgfx: Module Version: %d.%d.%d (kernel: %s)", 1126 1092 VMWGFX_DRIVER_MAJOR, VMWGFX_DRIVER_MINOR, 1127 1093 VMWGFX_DRIVER_PATCHLEVEL, UTS_RELEASE); 1128 - 1129 - if (dev_priv->enable_fb) { 1130 - vmw_fifo_resource_inc(dev_priv); 1131 - vmw_svga_enable(dev_priv); 1132 - vmw_fb_init(dev_priv); 1133 - } 1094 + vmw_write_driver_id(dev_priv); 1134 1095 1135 1096 dev_priv->pm_nb.notifier_call = vmwgfx_pm_notifier; 1136 1097 register_pm_notifier(&dev_priv->pm_nb); ··· 1172 1143 1173 1144 unregister_pm_notifier(&dev_priv->pm_nb); 1174 1145 1175 - if (dev_priv->ctx.res_ht_initialized) 1176 - vmwgfx_ht_remove(&dev_priv->ctx.res_ht); 1177 - vfree(dev_priv->ctx.cmd_bounce); 1178 - if (dev_priv->enable_fb) { 1179 - vmw_fb_off(dev_priv); 1180 - vmw_fb_close(dev_priv); 1181 - vmw_fifo_resource_dec(dev_priv); 1182 - vmw_svga_disable(dev_priv); 1183 - } 1146 + vmw_sw_context_fini(dev_priv); 1147 + vmw_fifo_resource_dec(dev_priv); 1148 + 1149 + vmw_svga_disable(dev_priv); 1184 1150 1185 1151 vmw_kms_close(dev_priv); 1186 1152 vmw_overlay_close(dev_priv); ··· 1197 1173 vmw_irq_uninstall(&dev_priv->drm); 1198 1174 1199 1175 ttm_object_device_release(&dev_priv->tdev); 1200 - if (dev_priv->ctx.staged_bindings) 1201 - vmw_binding_state_free(dev_priv->ctx.staged_bindings); 1202 1176 1203 1177 for (i = vmw_res_context; i < vmw_res_max; ++i) 1204 1178 idr_destroy(&dev_priv->res_idr[i]); ··· 1225 1203 if (unlikely(!vmw_fp)) 1226 1204 return ret; 1227 1205 1228 - vmw_fp->tfile = ttm_object_file_init(dev_priv->tdev, 10); 1206 + vmw_fp->tfile = ttm_object_file_init(dev_priv->tdev); 1229 1207 if (unlikely(vmw_fp->tfile == NULL)) 1230 1208 goto out_no_tfile; 1231 1209 ··· 1313 1291 struct vmw_private *dev_priv = vmw_priv(dev); 1314 1292 1315 1293 vmw_kms_legacy_hotspot_clear(dev_priv); 1316 - if (!dev_priv->enable_fb) 1317 - vmw_svga_disable(dev_priv); 1318 1294 } 1319 1295 1320 1296 /** ··· 1505 1485 DRM_ERROR("Failed to freeze modesetting.\n"); 1506 1486 return ret; 1507 1487 } 1508 - if (dev_priv->enable_fb) 1509 - vmw_fb_off(dev_priv); 1510 1488 1511 1489 vmw_execbuf_release_pinned_bo(dev_priv); 1512 1490 vmw_resource_evict_all(dev_priv); 1513 1491 vmw_release_device_early(dev_priv); 1514 1492 while (ttm_device_swapout(&dev_priv->bdev, &ctx, GFP_KERNEL) > 0); 1515 - if (dev_priv->enable_fb) 1516 - vmw_fifo_resource_dec(dev_priv); 1493 + vmw_fifo_resource_dec(dev_priv); 1517 1494 if (atomic_read(&dev_priv->num_fifo_resources) != 0) { 1518 1495 DRM_ERROR("Can't hibernate while 3D resources are active.\n"); 1519 - if (dev_priv->enable_fb) 1520 - vmw_fifo_resource_inc(dev_priv); 1496 + vmw_fifo_resource_inc(dev_priv); 1521 1497 WARN_ON(vmw_request_device_late(dev_priv)); 1522 1498 dev_priv->suspend_locked = false; 1523 1499 if (dev_priv->suspend_state) 1524 1500 vmw_kms_resume(dev); 1525 - if (dev_priv->enable_fb) 1526 - vmw_fb_on(dev_priv); 1527 1501 return -EBUSY; 1528 1502 } 1529 1503 ··· 1537 1523 1538 1524 vmw_detect_version(dev_priv); 1539 1525 1540 - if (dev_priv->enable_fb) 1541 - vmw_fifo_resource_inc(dev_priv); 1526 + vmw_fifo_resource_inc(dev_priv); 1542 1527 1543 1528 ret = vmw_request_device(dev_priv); 1544 1529 if (ret) 1545 1530 return ret; 1546 1531 1547 - if (dev_priv->enable_fb) 1548 - __vmw_svga_enable(dev_priv); 1532 + __vmw_svga_enable(dev_priv); 1549 1533 1550 1534 vmw_fence_fifo_up(dev_priv->fman); 1551 1535 dev_priv->suspend_locked = false; 1552 1536 if (dev_priv->suspend_state) 1553 1537 vmw_kms_resume(&dev_priv->drm); 1554 - 1555 - if (dev_priv->enable_fb) 1556 - vmw_fb_on(dev_priv); 1557 1538 1558 1539 return 0; 1559 1540 } ··· 1639 1630 ret = drm_dev_register(&vmw->drm, 0); 1640 1631 if (ret) 1641 1632 goto out_unload; 1633 + 1634 + vmw_fifo_resource_inc(vmw); 1635 + vmw_svga_enable(vmw); 1636 + drm_fbdev_generic_setup(&vmw->drm, 0); 1642 1637 1643 1638 vmw_debugfs_gem_init(vmw); 1644 1639 vmw_debugfs_resource_managers_init(vmw);
+11 -38
drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
··· 30 30 31 31 #include <linux/suspend.h> 32 32 #include <linux/sync_file.h> 33 + #include <linux/hashtable.h> 33 34 34 35 #include <drm/drm_auth.h> 35 36 #include <drm/drm_device.h> ··· 43 42 #include "ttm_object.h" 44 43 45 44 #include "vmwgfx_fence.h" 46 - #include "vmwgfx_hashtab.h" 47 45 #include "vmwgfx_reg.h" 48 46 #include "vmwgfx_validation.h" 49 47 ··· 61 61 #define VMWGFX_FIFO_STATIC_SIZE (1024*1024) 62 62 #define VMWGFX_MAX_DISPLAYS 16 63 63 #define VMWGFX_CMD_BOUNCE_INIT_SIZE 32768 64 + 65 + #define VMWGFX_MIN_INITIAL_WIDTH 1280 66 + #define VMWGFX_MIN_INITIAL_HEIGHT 800 64 67 65 68 #define VMWGFX_PCI_ID_SVGA2 0x0405 66 69 #define VMWGFX_PCI_ID_SVGA3 0x0406 ··· 96 93 #define VMW_RES_STREAM ttm_driver_type2 97 94 #define VMW_RES_FENCE ttm_driver_type3 98 95 #define VMW_RES_SHADER ttm_driver_type4 96 + #define VMW_RES_HT_ORDER 12 99 97 100 98 #define MKSSTAT_CAPACITY_LOG2 5U 101 99 #define MKSSTAT_CAPACITY (1U << MKSSTAT_CAPACITY_LOG2) ··· 104 100 struct vmw_fpriv { 105 101 struct ttm_object_file *tfile; 106 102 bool gb_aware; /* user-space is guest-backed aware */ 103 + }; 104 + 105 + struct vmwgfx_hash_item { 106 + struct hlist_node head; 107 + unsigned long key; 107 108 }; 108 109 109 110 /** ··· 434 425 * @ctx: The validation context 435 426 */ 436 427 struct vmw_sw_context{ 437 - struct vmwgfx_open_hash res_ht; 438 - bool res_ht_initialized; 428 + DECLARE_HASHTABLE(res_ht, VMW_RES_HT_ORDER); 439 429 bool kernel; 440 430 struct vmw_fpriv *fp; 441 431 struct drm_file *filp; ··· 554 546 * Framebuffer info. 555 547 */ 556 548 557 - void *fb_info; 558 549 enum vmw_display_unit_type active_display_unit; 559 550 struct vmw_legacy_display *ldu_priv; 560 551 struct vmw_overlay *overlay_priv; ··· 611 604 struct vmw_sw_context ctx; 612 605 struct mutex cmdbuf_mutex; 613 606 struct mutex binding_mutex; 614 - 615 - bool enable_fb; 616 607 617 608 /** 618 609 * PM management. ··· 1189 1184 extern void vmw_generic_waiter_remove(struct vmw_private *dev_priv, 1190 1185 u32 flag, int *waiter_count); 1191 1186 1192 - 1193 - /** 1194 - * Kernel framebuffer - vmwgfx_fb.c 1195 - */ 1196 - 1197 - #ifdef CONFIG_DRM_FBDEV_EMULATION 1198 - int vmw_fb_init(struct vmw_private *vmw_priv); 1199 - int vmw_fb_close(struct vmw_private *dev_priv); 1200 - int vmw_fb_off(struct vmw_private *vmw_priv); 1201 - int vmw_fb_on(struct vmw_private *vmw_priv); 1202 - #else 1203 - static inline int vmw_fb_init(struct vmw_private *vmw_priv) 1204 - { 1205 - return 0; 1206 - } 1207 - static inline int vmw_fb_close(struct vmw_private *dev_priv) 1208 - { 1209 - return 0; 1210 - } 1211 - static inline int vmw_fb_off(struct vmw_private *vmw_priv) 1212 - { 1213 - return 0; 1214 - } 1215 - static inline int vmw_fb_on(struct vmw_private *vmw_priv) 1216 - { 1217 - return 0; 1218 - } 1219 - #endif 1220 - 1221 1187 /** 1222 1188 * Kernel modesetting - vmwgfx_kms.c 1223 1189 */ ··· 1208 1232 bool vmw_kms_validate_mode_vram(struct vmw_private *dev_priv, 1209 1233 uint32_t pitch, 1210 1234 uint32_t height); 1211 - u32 vmw_get_vblank_counter(struct drm_crtc *crtc); 1212 - int vmw_enable_vblank(struct drm_crtc *crtc); 1213 - void vmw_disable_vblank(struct drm_crtc *crtc); 1214 1235 int vmw_kms_present(struct vmw_private *dev_priv, 1215 1236 struct drm_file *file_priv, 1216 1237 struct vmw_framebuffer *vfb,
+3 -12
drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 OR MIT 2 2 /************************************************************************** 3 3 * 4 - * Copyright 2009 - 2015 VMware, Inc., Palo Alto, CA., USA 4 + * Copyright 2009 - 2022 VMware, Inc., Palo Alto, CA., USA 5 5 * 6 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 7 * copy of this software and associated documentation files (the ··· 25 25 * 26 26 **************************************************************************/ 27 27 #include <linux/sync_file.h> 28 + #include <linux/hashtable.h> 28 29 29 30 #include "vmwgfx_drv.h" 30 31 #include "vmwgfx_reg.h" ··· 35 34 #include "vmwgfx_binding.h" 36 35 #include "vmwgfx_mksstat.h" 37 36 38 - #define VMW_RES_HT_ORDER 12 39 37 40 38 /* 41 39 * Helper macro to get dx_ctx_node if available otherwise print an error ··· 3869 3869 * @fence: Pointer to the fenc object. 3870 3870 * @fence_handle: User-space fence handle. 3871 3871 * @out_fence_fd: exported file descriptor for the fence. -1 if not used 3872 - * @sync_file: Only used to clean up in case of an error in this function. 3873 3872 * 3874 3873 * This function copies fence information to user-space. If copying fails, the 3875 3874 * user-space struct drm_vmw_fence_rep::error member is hopefully left ··· 4100 4101 int ret; 4101 4102 int32_t out_fence_fd = -1; 4102 4103 struct sync_file *sync_file = NULL; 4103 - DECLARE_VAL_CONTEXT(val_ctx, &sw_context->res_ht, 1); 4104 + DECLARE_VAL_CONTEXT(val_ctx, sw_context, 1); 4104 4105 4105 4106 if (flags & DRM_VMW_EXECBUF_FLAG_EXPORT_FENCE_FD) { 4106 4107 out_fence_fd = get_unused_fd_flags(O_CLOEXEC); ··· 4162 4163 4163 4164 if (sw_context->staged_bindings) 4164 4165 vmw_binding_state_reset(sw_context->staged_bindings); 4165 - 4166 - if (!sw_context->res_ht_initialized) { 4167 - ret = vmwgfx_ht_create(&sw_context->res_ht, VMW_RES_HT_ORDER); 4168 - if (unlikely(ret != 0)) 4169 - goto out_unlock; 4170 - 4171 - sw_context->res_ht_initialized = true; 4172 - } 4173 4166 4174 4167 INIT_LIST_HEAD(&sw_context->staged_cmd_res); 4175 4168 sw_context->ctx = &val_ctx;
-831
drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
··· 1 - /************************************************************************** 2 - * 3 - * Copyright © 2007 David Airlie 4 - * Copyright © 2009-2015 VMware, Inc., Palo Alto, CA., USA 5 - * All Rights Reserved. 6 - * 7 - * Permission is hereby granted, free of charge, to any person obtaining a 8 - * copy of this software and associated documentation files (the 9 - * "Software"), to deal in the Software without restriction, including 10 - * without limitation the rights to use, copy, modify, merge, publish, 11 - * distribute, sub license, and/or sell copies of the Software, and to 12 - * permit persons to whom the Software is furnished to do so, subject to 13 - * the following conditions: 14 - * 15 - * The above copyright notice and this permission notice (including the 16 - * next paragraph) shall be included in all copies or substantial portions 17 - * of the Software. 18 - * 19 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 22 - * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 23 - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 24 - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 25 - * USE OR OTHER DEALINGS IN THE SOFTWARE. 26 - * 27 - **************************************************************************/ 28 - 29 - #include <linux/fb.h> 30 - #include <linux/pci.h> 31 - 32 - #include <drm/drm_fourcc.h> 33 - #include <drm/ttm/ttm_placement.h> 34 - 35 - #include "vmwgfx_drv.h" 36 - #include "vmwgfx_kms.h" 37 - 38 - #define VMW_DIRTY_DELAY (HZ / 30) 39 - 40 - struct vmw_fb_par { 41 - struct vmw_private *vmw_priv; 42 - 43 - void *vmalloc; 44 - 45 - struct mutex bo_mutex; 46 - struct vmw_buffer_object *vmw_bo; 47 - unsigned bo_size; 48 - struct drm_framebuffer *set_fb; 49 - struct drm_display_mode *set_mode; 50 - u32 fb_x; 51 - u32 fb_y; 52 - bool bo_iowrite; 53 - 54 - u32 pseudo_palette[17]; 55 - 56 - unsigned max_width; 57 - unsigned max_height; 58 - 59 - struct { 60 - spinlock_t lock; 61 - bool active; 62 - unsigned x1; 63 - unsigned y1; 64 - unsigned x2; 65 - unsigned y2; 66 - } dirty; 67 - 68 - struct drm_crtc *crtc; 69 - struct drm_connector *con; 70 - struct delayed_work local_work; 71 - }; 72 - 73 - static int vmw_fb_setcolreg(unsigned regno, unsigned red, unsigned green, 74 - unsigned blue, unsigned transp, 75 - struct fb_info *info) 76 - { 77 - struct vmw_fb_par *par = info->par; 78 - u32 *pal = par->pseudo_palette; 79 - 80 - if (regno > 15) { 81 - DRM_ERROR("Bad regno %u.\n", regno); 82 - return 1; 83 - } 84 - 85 - switch (par->set_fb->format->depth) { 86 - case 24: 87 - case 32: 88 - pal[regno] = ((red & 0xff00) << 8) | 89 - (green & 0xff00) | 90 - ((blue & 0xff00) >> 8); 91 - break; 92 - default: 93 - DRM_ERROR("Bad depth %u, bpp %u.\n", 94 - par->set_fb->format->depth, 95 - par->set_fb->format->cpp[0] * 8); 96 - return 1; 97 - } 98 - 99 - return 0; 100 - } 101 - 102 - static int vmw_fb_check_var(struct fb_var_screeninfo *var, 103 - struct fb_info *info) 104 - { 105 - int depth = var->bits_per_pixel; 106 - struct vmw_fb_par *par = info->par; 107 - struct vmw_private *vmw_priv = par->vmw_priv; 108 - 109 - switch (var->bits_per_pixel) { 110 - case 32: 111 - depth = (var->transp.length > 0) ? 32 : 24; 112 - break; 113 - default: 114 - DRM_ERROR("Bad bpp %u.\n", var->bits_per_pixel); 115 - return -EINVAL; 116 - } 117 - 118 - switch (depth) { 119 - case 24: 120 - var->red.offset = 16; 121 - var->green.offset = 8; 122 - var->blue.offset = 0; 123 - var->red.length = 8; 124 - var->green.length = 8; 125 - var->blue.length = 8; 126 - var->transp.length = 0; 127 - var->transp.offset = 0; 128 - break; 129 - case 32: 130 - var->red.offset = 16; 131 - var->green.offset = 8; 132 - var->blue.offset = 0; 133 - var->red.length = 8; 134 - var->green.length = 8; 135 - var->blue.length = 8; 136 - var->transp.length = 8; 137 - var->transp.offset = 24; 138 - break; 139 - default: 140 - DRM_ERROR("Bad depth %u.\n", depth); 141 - return -EINVAL; 142 - } 143 - 144 - if ((var->xoffset + var->xres) > par->max_width || 145 - (var->yoffset + var->yres) > par->max_height) { 146 - DRM_ERROR("Requested geom can not fit in framebuffer\n"); 147 - return -EINVAL; 148 - } 149 - 150 - if (!vmw_kms_validate_mode_vram(vmw_priv, 151 - var->xres * var->bits_per_pixel/8, 152 - var->yoffset + var->yres)) { 153 - DRM_ERROR("Requested geom can not fit in framebuffer\n"); 154 - return -EINVAL; 155 - } 156 - 157 - return 0; 158 - } 159 - 160 - static int vmw_fb_blank(int blank, struct fb_info *info) 161 - { 162 - return 0; 163 - } 164 - 165 - /** 166 - * vmw_fb_dirty_flush - flush dirty regions to the kms framebuffer 167 - * 168 - * @work: The struct work_struct associated with this task. 169 - * 170 - * This function flushes the dirty regions of the vmalloc framebuffer to the 171 - * kms framebuffer, and if the kms framebuffer is visible, also updated the 172 - * corresponding displays. Note that this function runs even if the kms 173 - * framebuffer is not bound to a crtc and thus not visible, but it's turned 174 - * off during hibernation using the par->dirty.active bool. 175 - */ 176 - static void vmw_fb_dirty_flush(struct work_struct *work) 177 - { 178 - struct vmw_fb_par *par = container_of(work, struct vmw_fb_par, 179 - local_work.work); 180 - struct vmw_private *vmw_priv = par->vmw_priv; 181 - struct fb_info *info = vmw_priv->fb_info; 182 - unsigned long irq_flags; 183 - s32 dst_x1, dst_x2, dst_y1, dst_y2, w = 0, h = 0; 184 - u32 cpp, max_x, max_y; 185 - struct drm_clip_rect clip; 186 - struct drm_framebuffer *cur_fb; 187 - u8 *src_ptr, *dst_ptr; 188 - struct vmw_buffer_object *vbo = par->vmw_bo; 189 - void *virtual; 190 - 191 - if (!READ_ONCE(par->dirty.active)) 192 - return; 193 - 194 - mutex_lock(&par->bo_mutex); 195 - cur_fb = par->set_fb; 196 - if (!cur_fb) 197 - goto out_unlock; 198 - 199 - (void) ttm_bo_reserve(&vbo->base, false, false, NULL); 200 - virtual = vmw_bo_map_and_cache(vbo); 201 - if (!virtual) 202 - goto out_unreserve; 203 - 204 - spin_lock_irqsave(&par->dirty.lock, irq_flags); 205 - if (!par->dirty.active) { 206 - spin_unlock_irqrestore(&par->dirty.lock, irq_flags); 207 - goto out_unreserve; 208 - } 209 - 210 - /* 211 - * Handle panning when copying from vmalloc to framebuffer. 212 - * Clip dirty area to framebuffer. 213 - */ 214 - cpp = cur_fb->format->cpp[0]; 215 - max_x = par->fb_x + cur_fb->width; 216 - max_y = par->fb_y + cur_fb->height; 217 - 218 - dst_x1 = par->dirty.x1 - par->fb_x; 219 - dst_y1 = par->dirty.y1 - par->fb_y; 220 - dst_x1 = max_t(s32, dst_x1, 0); 221 - dst_y1 = max_t(s32, dst_y1, 0); 222 - 223 - dst_x2 = par->dirty.x2 - par->fb_x; 224 - dst_y2 = par->dirty.y2 - par->fb_y; 225 - dst_x2 = min_t(s32, dst_x2, max_x); 226 - dst_y2 = min_t(s32, dst_y2, max_y); 227 - w = dst_x2 - dst_x1; 228 - h = dst_y2 - dst_y1; 229 - w = max_t(s32, 0, w); 230 - h = max_t(s32, 0, h); 231 - 232 - par->dirty.x1 = par->dirty.x2 = 0; 233 - par->dirty.y1 = par->dirty.y2 = 0; 234 - spin_unlock_irqrestore(&par->dirty.lock, irq_flags); 235 - 236 - if (w && h) { 237 - dst_ptr = (u8 *)virtual + 238 - (dst_y1 * par->set_fb->pitches[0] + dst_x1 * cpp); 239 - src_ptr = (u8 *)par->vmalloc + 240 - ((dst_y1 + par->fb_y) * info->fix.line_length + 241 - (dst_x1 + par->fb_x) * cpp); 242 - 243 - while (h-- > 0) { 244 - memcpy(dst_ptr, src_ptr, w*cpp); 245 - dst_ptr += par->set_fb->pitches[0]; 246 - src_ptr += info->fix.line_length; 247 - } 248 - 249 - clip.x1 = dst_x1; 250 - clip.x2 = dst_x2; 251 - clip.y1 = dst_y1; 252 - clip.y2 = dst_y2; 253 - } 254 - 255 - out_unreserve: 256 - ttm_bo_unreserve(&vbo->base); 257 - if (w && h) { 258 - WARN_ON_ONCE(par->set_fb->funcs->dirty(cur_fb, NULL, 0, 0, 259 - &clip, 1)); 260 - vmw_cmd_flush(vmw_priv, false); 261 - } 262 - out_unlock: 263 - mutex_unlock(&par->bo_mutex); 264 - } 265 - 266 - static void vmw_fb_dirty_mark(struct vmw_fb_par *par, 267 - unsigned x1, unsigned y1, 268 - unsigned width, unsigned height) 269 - { 270 - unsigned long flags; 271 - unsigned x2 = x1 + width; 272 - unsigned y2 = y1 + height; 273 - 274 - spin_lock_irqsave(&par->dirty.lock, flags); 275 - if (par->dirty.x1 == par->dirty.x2) { 276 - par->dirty.x1 = x1; 277 - par->dirty.y1 = y1; 278 - par->dirty.x2 = x2; 279 - par->dirty.y2 = y2; 280 - /* if we are active start the dirty work 281 - * we share the work with the defio system */ 282 - if (par->dirty.active) 283 - schedule_delayed_work(&par->local_work, 284 - VMW_DIRTY_DELAY); 285 - } else { 286 - if (x1 < par->dirty.x1) 287 - par->dirty.x1 = x1; 288 - if (y1 < par->dirty.y1) 289 - par->dirty.y1 = y1; 290 - if (x2 > par->dirty.x2) 291 - par->dirty.x2 = x2; 292 - if (y2 > par->dirty.y2) 293 - par->dirty.y2 = y2; 294 - } 295 - spin_unlock_irqrestore(&par->dirty.lock, flags); 296 - } 297 - 298 - static int vmw_fb_pan_display(struct fb_var_screeninfo *var, 299 - struct fb_info *info) 300 - { 301 - struct vmw_fb_par *par = info->par; 302 - 303 - if ((var->xoffset + var->xres) > var->xres_virtual || 304 - (var->yoffset + var->yres) > var->yres_virtual) { 305 - DRM_ERROR("Requested panning can not fit in framebuffer\n"); 306 - return -EINVAL; 307 - } 308 - 309 - mutex_lock(&par->bo_mutex); 310 - par->fb_x = var->xoffset; 311 - par->fb_y = var->yoffset; 312 - if (par->set_fb) 313 - vmw_fb_dirty_mark(par, par->fb_x, par->fb_y, par->set_fb->width, 314 - par->set_fb->height); 315 - mutex_unlock(&par->bo_mutex); 316 - 317 - return 0; 318 - } 319 - 320 - static void vmw_deferred_io(struct fb_info *info, struct list_head *pagereflist) 321 - { 322 - struct vmw_fb_par *par = info->par; 323 - unsigned long start, end, min, max; 324 - unsigned long flags; 325 - struct fb_deferred_io_pageref *pageref; 326 - int y1, y2; 327 - 328 - min = ULONG_MAX; 329 - max = 0; 330 - list_for_each_entry(pageref, pagereflist, list) { 331 - start = pageref->offset; 332 - end = start + PAGE_SIZE - 1; 333 - min = min(min, start); 334 - max = max(max, end); 335 - } 336 - 337 - if (min < max) { 338 - y1 = min / info->fix.line_length; 339 - y2 = (max / info->fix.line_length) + 1; 340 - 341 - spin_lock_irqsave(&par->dirty.lock, flags); 342 - par->dirty.x1 = 0; 343 - par->dirty.y1 = y1; 344 - par->dirty.x2 = info->var.xres; 345 - par->dirty.y2 = y2; 346 - spin_unlock_irqrestore(&par->dirty.lock, flags); 347 - 348 - /* 349 - * Since we've already waited on this work once, try to 350 - * execute asap. 351 - */ 352 - cancel_delayed_work(&par->local_work); 353 - schedule_delayed_work(&par->local_work, 0); 354 - } 355 - }; 356 - 357 - static struct fb_deferred_io vmw_defio = { 358 - .delay = VMW_DIRTY_DELAY, 359 - .deferred_io = vmw_deferred_io, 360 - }; 361 - 362 - /* 363 - * Draw code 364 - */ 365 - 366 - static void vmw_fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) 367 - { 368 - cfb_fillrect(info, rect); 369 - vmw_fb_dirty_mark(info->par, rect->dx, rect->dy, 370 - rect->width, rect->height); 371 - } 372 - 373 - static void vmw_fb_copyarea(struct fb_info *info, const struct fb_copyarea *region) 374 - { 375 - cfb_copyarea(info, region); 376 - vmw_fb_dirty_mark(info->par, region->dx, region->dy, 377 - region->width, region->height); 378 - } 379 - 380 - static void vmw_fb_imageblit(struct fb_info *info, const struct fb_image *image) 381 - { 382 - cfb_imageblit(info, image); 383 - vmw_fb_dirty_mark(info->par, image->dx, image->dy, 384 - image->width, image->height); 385 - } 386 - 387 - /* 388 - * Bring up code 389 - */ 390 - 391 - static int vmw_fb_create_bo(struct vmw_private *vmw_priv, 392 - size_t size, struct vmw_buffer_object **out) 393 - { 394 - struct vmw_buffer_object *vmw_bo; 395 - int ret; 396 - 397 - ret = vmw_bo_create(vmw_priv, size, 398 - &vmw_sys_placement, 399 - false, false, 400 - &vmw_bo_bo_free, &vmw_bo); 401 - if (unlikely(ret != 0)) 402 - return ret; 403 - 404 - *out = vmw_bo; 405 - 406 - return ret; 407 - } 408 - 409 - static int vmw_fb_compute_depth(struct fb_var_screeninfo *var, 410 - int *depth) 411 - { 412 - switch (var->bits_per_pixel) { 413 - case 32: 414 - *depth = (var->transp.length > 0) ? 32 : 24; 415 - break; 416 - default: 417 - DRM_ERROR("Bad bpp %u.\n", var->bits_per_pixel); 418 - return -EINVAL; 419 - } 420 - 421 - return 0; 422 - } 423 - 424 - static int vmwgfx_set_config_internal(struct drm_mode_set *set) 425 - { 426 - struct drm_crtc *crtc = set->crtc; 427 - struct drm_modeset_acquire_ctx ctx; 428 - int ret; 429 - 430 - drm_modeset_acquire_init(&ctx, 0); 431 - 432 - restart: 433 - ret = crtc->funcs->set_config(set, &ctx); 434 - 435 - if (ret == -EDEADLK) { 436 - drm_modeset_backoff(&ctx); 437 - goto restart; 438 - } 439 - 440 - drm_modeset_drop_locks(&ctx); 441 - drm_modeset_acquire_fini(&ctx); 442 - 443 - return ret; 444 - } 445 - 446 - static int vmw_fb_kms_detach(struct vmw_fb_par *par, 447 - bool detach_bo, 448 - bool unref_bo) 449 - { 450 - struct drm_framebuffer *cur_fb = par->set_fb; 451 - int ret; 452 - 453 - /* Detach the KMS framebuffer from crtcs */ 454 - if (par->set_mode) { 455 - struct drm_mode_set set; 456 - 457 - set.crtc = par->crtc; 458 - set.x = 0; 459 - set.y = 0; 460 - set.mode = NULL; 461 - set.fb = NULL; 462 - set.num_connectors = 0; 463 - set.connectors = &par->con; 464 - ret = vmwgfx_set_config_internal(&set); 465 - if (ret) { 466 - DRM_ERROR("Could not unset a mode.\n"); 467 - return ret; 468 - } 469 - drm_mode_destroy(&par->vmw_priv->drm, par->set_mode); 470 - par->set_mode = NULL; 471 - } 472 - 473 - if (cur_fb) { 474 - drm_framebuffer_put(cur_fb); 475 - par->set_fb = NULL; 476 - } 477 - 478 - if (par->vmw_bo && detach_bo && unref_bo) 479 - vmw_bo_unreference(&par->vmw_bo); 480 - 481 - return 0; 482 - } 483 - 484 - static int vmw_fb_kms_framebuffer(struct fb_info *info) 485 - { 486 - struct drm_mode_fb_cmd2 mode_cmd = {0}; 487 - struct vmw_fb_par *par = info->par; 488 - struct fb_var_screeninfo *var = &info->var; 489 - struct drm_framebuffer *cur_fb; 490 - struct vmw_framebuffer *vfb; 491 - int ret = 0, depth; 492 - size_t new_bo_size; 493 - 494 - ret = vmw_fb_compute_depth(var, &depth); 495 - if (ret) 496 - return ret; 497 - 498 - mode_cmd.width = var->xres; 499 - mode_cmd.height = var->yres; 500 - mode_cmd.pitches[0] = ((var->bits_per_pixel + 7) / 8) * mode_cmd.width; 501 - mode_cmd.pixel_format = 502 - drm_mode_legacy_fb_format(var->bits_per_pixel, depth); 503 - 504 - cur_fb = par->set_fb; 505 - if (cur_fb && cur_fb->width == mode_cmd.width && 506 - cur_fb->height == mode_cmd.height && 507 - cur_fb->format->format == mode_cmd.pixel_format && 508 - cur_fb->pitches[0] == mode_cmd.pitches[0]) 509 - return 0; 510 - 511 - /* Need new buffer object ? */ 512 - new_bo_size = (size_t) mode_cmd.pitches[0] * (size_t) mode_cmd.height; 513 - ret = vmw_fb_kms_detach(par, 514 - par->bo_size < new_bo_size || 515 - par->bo_size > 2*new_bo_size, 516 - true); 517 - if (ret) 518 - return ret; 519 - 520 - if (!par->vmw_bo) { 521 - ret = vmw_fb_create_bo(par->vmw_priv, new_bo_size, 522 - &par->vmw_bo); 523 - if (ret) { 524 - DRM_ERROR("Failed creating a buffer object for " 525 - "fbdev.\n"); 526 - return ret; 527 - } 528 - par->bo_size = new_bo_size; 529 - } 530 - 531 - vfb = vmw_kms_new_framebuffer(par->vmw_priv, par->vmw_bo, NULL, 532 - true, &mode_cmd); 533 - if (IS_ERR(vfb)) 534 - return PTR_ERR(vfb); 535 - 536 - par->set_fb = &vfb->base; 537 - 538 - return 0; 539 - } 540 - 541 - static int vmw_fb_set_par(struct fb_info *info) 542 - { 543 - struct vmw_fb_par *par = info->par; 544 - struct vmw_private *vmw_priv = par->vmw_priv; 545 - struct drm_mode_set set; 546 - struct fb_var_screeninfo *var = &info->var; 547 - struct drm_display_mode new_mode = { DRM_MODE("fb_mode", 548 - DRM_MODE_TYPE_DRIVER, 549 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 550 - DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) 551 - }; 552 - struct drm_display_mode *mode; 553 - int ret; 554 - 555 - mode = drm_mode_duplicate(&vmw_priv->drm, &new_mode); 556 - if (!mode) { 557 - DRM_ERROR("Could not create new fb mode.\n"); 558 - return -ENOMEM; 559 - } 560 - 561 - mode->hdisplay = var->xres; 562 - mode->vdisplay = var->yres; 563 - vmw_guess_mode_timing(mode); 564 - 565 - if (!vmw_kms_validate_mode_vram(vmw_priv, 566 - mode->hdisplay * 567 - DIV_ROUND_UP(var->bits_per_pixel, 8), 568 - mode->vdisplay)) { 569 - drm_mode_destroy(&vmw_priv->drm, mode); 570 - return -EINVAL; 571 - } 572 - 573 - mutex_lock(&par->bo_mutex); 574 - ret = vmw_fb_kms_framebuffer(info); 575 - if (ret) 576 - goto out_unlock; 577 - 578 - par->fb_x = var->xoffset; 579 - par->fb_y = var->yoffset; 580 - 581 - set.crtc = par->crtc; 582 - set.x = 0; 583 - set.y = 0; 584 - set.mode = mode; 585 - set.fb = par->set_fb; 586 - set.num_connectors = 1; 587 - set.connectors = &par->con; 588 - 589 - ret = vmwgfx_set_config_internal(&set); 590 - if (ret) 591 - goto out_unlock; 592 - 593 - vmw_fb_dirty_mark(par, par->fb_x, par->fb_y, 594 - par->set_fb->width, par->set_fb->height); 595 - 596 - /* If there already was stuff dirty we wont 597 - * schedule a new work, so lets do it now */ 598 - 599 - schedule_delayed_work(&par->local_work, 0); 600 - 601 - out_unlock: 602 - if (par->set_mode) 603 - drm_mode_destroy(&vmw_priv->drm, par->set_mode); 604 - par->set_mode = mode; 605 - 606 - mutex_unlock(&par->bo_mutex); 607 - 608 - return ret; 609 - } 610 - 611 - 612 - static const struct fb_ops vmw_fb_ops = { 613 - .owner = THIS_MODULE, 614 - .fb_check_var = vmw_fb_check_var, 615 - .fb_set_par = vmw_fb_set_par, 616 - .fb_setcolreg = vmw_fb_setcolreg, 617 - .fb_fillrect = vmw_fb_fillrect, 618 - .fb_copyarea = vmw_fb_copyarea, 619 - .fb_imageblit = vmw_fb_imageblit, 620 - .fb_pan_display = vmw_fb_pan_display, 621 - .fb_blank = vmw_fb_blank, 622 - .fb_mmap = fb_deferred_io_mmap, 623 - }; 624 - 625 - int vmw_fb_init(struct vmw_private *vmw_priv) 626 - { 627 - struct device *device = vmw_priv->drm.dev; 628 - struct vmw_fb_par *par; 629 - struct fb_info *info; 630 - unsigned fb_width, fb_height; 631 - unsigned int fb_bpp, fb_pitch, fb_size; 632 - struct drm_display_mode *init_mode; 633 - int ret; 634 - 635 - fb_bpp = 32; 636 - 637 - /* XXX As shouldn't these be as well. */ 638 - fb_width = min(vmw_priv->fb_max_width, (unsigned)2048); 639 - fb_height = min(vmw_priv->fb_max_height, (unsigned)2048); 640 - 641 - fb_pitch = fb_width * fb_bpp / 8; 642 - fb_size = fb_pitch * fb_height; 643 - 644 - info = framebuffer_alloc(sizeof(*par), device); 645 - if (!info) 646 - return -ENOMEM; 647 - 648 - /* 649 - * Par 650 - */ 651 - vmw_priv->fb_info = info; 652 - par = info->par; 653 - memset(par, 0, sizeof(*par)); 654 - INIT_DELAYED_WORK(&par->local_work, &vmw_fb_dirty_flush); 655 - par->vmw_priv = vmw_priv; 656 - par->vmalloc = NULL; 657 - par->max_width = fb_width; 658 - par->max_height = fb_height; 659 - 660 - ret = vmw_kms_fbdev_init_data(vmw_priv, 0, par->max_width, 661 - par->max_height, &par->con, 662 - &par->crtc, &init_mode); 663 - if (ret) 664 - goto err_kms; 665 - 666 - info->var.xres = init_mode->hdisplay; 667 - info->var.yres = init_mode->vdisplay; 668 - 669 - /* 670 - * Create buffers and alloc memory 671 - */ 672 - par->vmalloc = vzalloc(fb_size); 673 - if (unlikely(par->vmalloc == NULL)) { 674 - ret = -ENOMEM; 675 - goto err_free; 676 - } 677 - 678 - /* 679 - * Fixed and var 680 - */ 681 - strcpy(info->fix.id, "svgadrmfb"); 682 - info->fix.type = FB_TYPE_PACKED_PIXELS; 683 - info->fix.visual = FB_VISUAL_TRUECOLOR; 684 - info->fix.type_aux = 0; 685 - info->fix.xpanstep = 1; /* doing it in hw */ 686 - info->fix.ypanstep = 1; /* doing it in hw */ 687 - info->fix.ywrapstep = 0; 688 - info->fix.accel = FB_ACCEL_NONE; 689 - info->fix.line_length = fb_pitch; 690 - 691 - info->fix.smem_start = 0; 692 - info->fix.smem_len = fb_size; 693 - 694 - info->pseudo_palette = par->pseudo_palette; 695 - info->screen_base = (char __iomem *)par->vmalloc; 696 - info->screen_size = fb_size; 697 - 698 - info->fbops = &vmw_fb_ops; 699 - 700 - /* 24 depth per default */ 701 - info->var.red.offset = 16; 702 - info->var.green.offset = 8; 703 - info->var.blue.offset = 0; 704 - info->var.red.length = 8; 705 - info->var.green.length = 8; 706 - info->var.blue.length = 8; 707 - info->var.transp.offset = 0; 708 - info->var.transp.length = 0; 709 - 710 - info->var.xres_virtual = fb_width; 711 - info->var.yres_virtual = fb_height; 712 - info->var.bits_per_pixel = fb_bpp; 713 - info->var.xoffset = 0; 714 - info->var.yoffset = 0; 715 - info->var.activate = FB_ACTIVATE_NOW; 716 - info->var.height = -1; 717 - info->var.width = -1; 718 - 719 - /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */ 720 - info->apertures = alloc_apertures(1); 721 - if (!info->apertures) { 722 - ret = -ENOMEM; 723 - goto err_aper; 724 - } 725 - info->apertures->ranges[0].base = vmw_priv->vram_start; 726 - info->apertures->ranges[0].size = vmw_priv->vram_size; 727 - 728 - /* 729 - * Dirty & Deferred IO 730 - */ 731 - par->dirty.x1 = par->dirty.x2 = 0; 732 - par->dirty.y1 = par->dirty.y2 = 0; 733 - par->dirty.active = true; 734 - spin_lock_init(&par->dirty.lock); 735 - mutex_init(&par->bo_mutex); 736 - info->fbdefio = &vmw_defio; 737 - fb_deferred_io_init(info); 738 - 739 - ret = register_framebuffer(info); 740 - if (unlikely(ret != 0)) 741 - goto err_defio; 742 - 743 - vmw_fb_set_par(info); 744 - 745 - return 0; 746 - 747 - err_defio: 748 - fb_deferred_io_cleanup(info); 749 - err_aper: 750 - err_free: 751 - vfree(par->vmalloc); 752 - err_kms: 753 - framebuffer_release(info); 754 - vmw_priv->fb_info = NULL; 755 - 756 - return ret; 757 - } 758 - 759 - int vmw_fb_close(struct vmw_private *vmw_priv) 760 - { 761 - struct fb_info *info; 762 - struct vmw_fb_par *par; 763 - 764 - if (!vmw_priv->fb_info) 765 - return 0; 766 - 767 - info = vmw_priv->fb_info; 768 - par = info->par; 769 - 770 - /* ??? order */ 771 - fb_deferred_io_cleanup(info); 772 - cancel_delayed_work_sync(&par->local_work); 773 - unregister_framebuffer(info); 774 - 775 - mutex_lock(&par->bo_mutex); 776 - (void) vmw_fb_kms_detach(par, true, true); 777 - mutex_unlock(&par->bo_mutex); 778 - 779 - vfree(par->vmalloc); 780 - framebuffer_release(info); 781 - 782 - return 0; 783 - } 784 - 785 - int vmw_fb_off(struct vmw_private *vmw_priv) 786 - { 787 - struct fb_info *info; 788 - struct vmw_fb_par *par; 789 - unsigned long flags; 790 - 791 - if (!vmw_priv->fb_info) 792 - return -EINVAL; 793 - 794 - info = vmw_priv->fb_info; 795 - par = info->par; 796 - 797 - spin_lock_irqsave(&par->dirty.lock, flags); 798 - par->dirty.active = false; 799 - spin_unlock_irqrestore(&par->dirty.lock, flags); 800 - 801 - flush_delayed_work(&info->deferred_work); 802 - flush_delayed_work(&par->local_work); 803 - 804 - return 0; 805 - } 806 - 807 - int vmw_fb_on(struct vmw_private *vmw_priv) 808 - { 809 - struct fb_info *info; 810 - struct vmw_fb_par *par; 811 - unsigned long flags; 812 - 813 - if (!vmw_priv->fb_info) 814 - return -EINVAL; 815 - 816 - info = vmw_priv->fb_info; 817 - par = info->par; 818 - 819 - spin_lock_irqsave(&par->dirty.lock, flags); 820 - par->dirty.active = true; 821 - spin_unlock_irqrestore(&par->dirty.lock, flags); 822 - 823 - /* 824 - * Need to reschedule a dirty update, because otherwise that's 825 - * only done in dirty_mark() if the previous coalesced 826 - * dirty region was empty. 827 - */ 828 - schedule_delayed_work(&par->local_work, 0); 829 - 830 - return 0; 831 - }
-199
drivers/gpu/drm/vmwgfx/vmwgfx_hashtab.c
··· 1 - /* 2 - * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND. USA. 3 - * All Rights Reserved. 4 - * 5 - * Permission is hereby granted, free of charge, to any person obtaining a 6 - * copy of this software and associated documentation files (the 7 - * "Software"), to deal in the Software without restriction, including 8 - * without limitation the rights to use, copy, modify, merge, publish, 9 - * distribute, sub license, and/or sell copies of the Software, and to 10 - * permit persons to whom the Software is furnished to do so, subject to 11 - * the following conditions: 12 - * 13 - * The above copyright notice and this permission notice (including the 14 - * next paragraph) shall be included in all copies or substantial portions 15 - * of the Software. 16 - * 17 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 20 - * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 21 - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 22 - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 23 - * USE OR OTHER DEALINGS IN THE SOFTWARE. 24 - */ 25 - 26 - /* 27 - * Simple open hash tab implementation. 28 - * 29 - * Authors: 30 - * Thomas Hellström <thomas-at-tungstengraphics-dot-com> 31 - */ 32 - 33 - #include <linux/export.h> 34 - #include <linux/hash.h> 35 - #include <linux/mm.h> 36 - #include <linux/rculist.h> 37 - #include <linux/slab.h> 38 - #include <linux/vmalloc.h> 39 - 40 - #include <drm/drm_print.h> 41 - 42 - #include "vmwgfx_hashtab.h" 43 - 44 - int vmwgfx_ht_create(struct vmwgfx_open_hash *ht, unsigned int order) 45 - { 46 - unsigned int size = 1 << order; 47 - 48 - ht->order = order; 49 - ht->table = NULL; 50 - if (size <= PAGE_SIZE / sizeof(*ht->table)) 51 - ht->table = kcalloc(size, sizeof(*ht->table), GFP_KERNEL); 52 - else 53 - ht->table = vzalloc(array_size(size, sizeof(*ht->table))); 54 - if (!ht->table) { 55 - DRM_ERROR("Out of memory for hash table\n"); 56 - return -ENOMEM; 57 - } 58 - return 0; 59 - } 60 - 61 - void vmwgfx_ht_verbose_list(struct vmwgfx_open_hash *ht, unsigned long key) 62 - { 63 - struct vmwgfx_hash_item *entry; 64 - struct hlist_head *h_list; 65 - unsigned int hashed_key; 66 - int count = 0; 67 - 68 - hashed_key = hash_long(key, ht->order); 69 - DRM_DEBUG("Key is 0x%08lx, Hashed key is 0x%08x\n", key, hashed_key); 70 - h_list = &ht->table[hashed_key]; 71 - hlist_for_each_entry(entry, h_list, head) 72 - DRM_DEBUG("count %d, key: 0x%08lx\n", count++, entry->key); 73 - } 74 - 75 - static struct hlist_node *vmwgfx_ht_find_key(struct vmwgfx_open_hash *ht, unsigned long key) 76 - { 77 - struct vmwgfx_hash_item *entry; 78 - struct hlist_head *h_list; 79 - unsigned int hashed_key; 80 - 81 - hashed_key = hash_long(key, ht->order); 82 - h_list = &ht->table[hashed_key]; 83 - hlist_for_each_entry(entry, h_list, head) { 84 - if (entry->key == key) 85 - return &entry->head; 86 - if (entry->key > key) 87 - break; 88 - } 89 - return NULL; 90 - } 91 - 92 - static struct hlist_node *vmwgfx_ht_find_key_rcu(struct vmwgfx_open_hash *ht, unsigned long key) 93 - { 94 - struct vmwgfx_hash_item *entry; 95 - struct hlist_head *h_list; 96 - unsigned int hashed_key; 97 - 98 - hashed_key = hash_long(key, ht->order); 99 - h_list = &ht->table[hashed_key]; 100 - hlist_for_each_entry_rcu(entry, h_list, head) { 101 - if (entry->key == key) 102 - return &entry->head; 103 - if (entry->key > key) 104 - break; 105 - } 106 - return NULL; 107 - } 108 - 109 - int vmwgfx_ht_insert_item(struct vmwgfx_open_hash *ht, struct vmwgfx_hash_item *item) 110 - { 111 - struct vmwgfx_hash_item *entry; 112 - struct hlist_head *h_list; 113 - struct hlist_node *parent; 114 - unsigned int hashed_key; 115 - unsigned long key = item->key; 116 - 117 - hashed_key = hash_long(key, ht->order); 118 - h_list = &ht->table[hashed_key]; 119 - parent = NULL; 120 - hlist_for_each_entry(entry, h_list, head) { 121 - if (entry->key == key) 122 - return -EINVAL; 123 - if (entry->key > key) 124 - break; 125 - parent = &entry->head; 126 - } 127 - if (parent) 128 - hlist_add_behind_rcu(&item->head, parent); 129 - else 130 - hlist_add_head_rcu(&item->head, h_list); 131 - return 0; 132 - } 133 - 134 - /* 135 - * Just insert an item and return any "bits" bit key that hasn't been 136 - * used before. 137 - */ 138 - int vmwgfx_ht_just_insert_please(struct vmwgfx_open_hash *ht, struct vmwgfx_hash_item *item, 139 - unsigned long seed, int bits, int shift, 140 - unsigned long add) 141 - { 142 - int ret; 143 - unsigned long mask = (1UL << bits) - 1; 144 - unsigned long first, unshifted_key; 145 - 146 - unshifted_key = hash_long(seed, bits); 147 - first = unshifted_key; 148 - do { 149 - item->key = (unshifted_key << shift) + add; 150 - ret = vmwgfx_ht_insert_item(ht, item); 151 - if (ret) 152 - unshifted_key = (unshifted_key + 1) & mask; 153 - } while (ret && (unshifted_key != first)); 154 - 155 - if (ret) { 156 - DRM_ERROR("Available key bit space exhausted\n"); 157 - return -EINVAL; 158 - } 159 - return 0; 160 - } 161 - 162 - int vmwgfx_ht_find_item(struct vmwgfx_open_hash *ht, unsigned long key, 163 - struct vmwgfx_hash_item **item) 164 - { 165 - struct hlist_node *list; 166 - 167 - list = vmwgfx_ht_find_key_rcu(ht, key); 168 - if (!list) 169 - return -EINVAL; 170 - 171 - *item = hlist_entry(list, struct vmwgfx_hash_item, head); 172 - return 0; 173 - } 174 - 175 - int vmwgfx_ht_remove_key(struct vmwgfx_open_hash *ht, unsigned long key) 176 - { 177 - struct hlist_node *list; 178 - 179 - list = vmwgfx_ht_find_key(ht, key); 180 - if (list) { 181 - hlist_del_init_rcu(list); 182 - return 0; 183 - } 184 - return -EINVAL; 185 - } 186 - 187 - int vmwgfx_ht_remove_item(struct vmwgfx_open_hash *ht, struct vmwgfx_hash_item *item) 188 - { 189 - hlist_del_init_rcu(&item->head); 190 - return 0; 191 - } 192 - 193 - void vmwgfx_ht_remove(struct vmwgfx_open_hash *ht) 194 - { 195 - if (ht->table) { 196 - kvfree(ht->table); 197 - ht->table = NULL; 198 - } 199 - }
-83
drivers/gpu/drm/vmwgfx/vmwgfx_hashtab.h
··· 1 - /* 2 - * Copyright 2006 Tungsten Graphics, Inc., Bismack, ND. USA. 3 - * All Rights Reserved. 4 - * 5 - * Permission is hereby granted, free of charge, to any person obtaining a 6 - * copy of this software and associated documentation files (the 7 - * "Software"), to deal in the Software without restriction, including 8 - * without limitation the rights to use, copy, modify, merge, publish, 9 - * distribute, sub license, and/or sell copies of the Software, and to 10 - * permit persons to whom the Software is furnished to do so, subject to 11 - * the following conditions: 12 - * 13 - * The above copyright notice and this permission notice (including the 14 - * next paragraph) shall be included in all copies or substantial portions 15 - * of the Software. 16 - * 17 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 20 - * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 21 - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 22 - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 23 - * USE OR OTHER DEALINGS IN THE SOFTWARE. 24 - */ 25 - 26 - /* 27 - * Simple open hash tab implementation. 28 - * 29 - * Authors: 30 - * Thomas Hellström <thomas-at-tungstengraphics-dot-com> 31 - */ 32 - 33 - /* 34 - * TODO: Replace this hashtable with Linux' generic implementation 35 - * from <linux/hashtable.h>. 36 - */ 37 - 38 - #ifndef VMWGFX_HASHTAB_H 39 - #define VMWGFX_HASHTAB_H 40 - 41 - #include <linux/list.h> 42 - 43 - #define drm_hash_entry(_ptr, _type, _member) container_of(_ptr, _type, _member) 44 - 45 - struct vmwgfx_hash_item { 46 - struct hlist_node head; 47 - unsigned long key; 48 - }; 49 - 50 - struct vmwgfx_open_hash { 51 - struct hlist_head *table; 52 - u8 order; 53 - }; 54 - 55 - int vmwgfx_ht_create(struct vmwgfx_open_hash *ht, unsigned int order); 56 - int vmwgfx_ht_insert_item(struct vmwgfx_open_hash *ht, struct vmwgfx_hash_item *item); 57 - int vmwgfx_ht_just_insert_please(struct vmwgfx_open_hash *ht, struct vmwgfx_hash_item *item, 58 - unsigned long seed, int bits, int shift, 59 - unsigned long add); 60 - int vmwgfx_ht_find_item(struct vmwgfx_open_hash *ht, unsigned long key, 61 - struct vmwgfx_hash_item **item); 62 - 63 - void vmwgfx_ht_verbose_list(struct vmwgfx_open_hash *ht, unsigned long key); 64 - int vmwgfx_ht_remove_key(struct vmwgfx_open_hash *ht, unsigned long key); 65 - int vmwgfx_ht_remove_item(struct vmwgfx_open_hash *ht, struct vmwgfx_hash_item *item); 66 - void vmwgfx_ht_remove(struct vmwgfx_open_hash *ht); 67 - 68 - /* 69 - * RCU-safe interface 70 - * 71 - * The user of this API needs to make sure that two or more instances of the 72 - * hash table manipulation functions are never run simultaneously. 73 - * The lookup function vmwgfx_ht_find_item_rcu may, however, run simultaneously 74 - * with any of the manipulation functions as long as it's called from within 75 - * an RCU read-locked section. 76 - */ 77 - #define vmwgfx_ht_insert_item_rcu vmwgfx_ht_insert_item 78 - #define vmwgfx_ht_just_insert_please_rcu vmwgfx_ht_just_insert_please 79 - #define vmwgfx_ht_remove_key_rcu vmwgfx_ht_remove_key 80 - #define vmwgfx_ht_remove_item_rcu vmwgfx_ht_remove_item 81 - #define vmwgfx_ht_find_item_rcu vmwgfx_ht_find_item 82 - 83 - #endif
+357 -302
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
··· 31 31 #include <drm/drm_fourcc.h> 32 32 #include <drm/drm_rect.h> 33 33 #include <drm/drm_sysfs.h> 34 - #include <drm/drm_vblank.h> 35 34 36 35 #include "vmwgfx_kms.h" 37 36 ··· 51 52 * Display Unit Cursor functions 52 53 */ 53 54 55 + static int vmw_du_cursor_plane_unmap_cm(struct vmw_plane_state *vps); 54 56 static void vmw_cursor_update_mob(struct vmw_private *dev_priv, 55 - struct ttm_buffer_object *bo, 56 - struct ttm_bo_kmap_obj *map, 57 + struct vmw_plane_state *vps, 57 58 u32 *image, u32 width, u32 height, 58 59 u32 hotspotX, u32 hotspotY); 59 60 ··· 62 63 SVGAFifoCmdDefineAlphaCursor cursor; 63 64 }; 64 65 65 - static void vmw_cursor_update_image(struct vmw_private *dev_priv, 66 - struct ttm_buffer_object *cm_bo, 67 - struct ttm_bo_kmap_obj *cm_map, 68 - u32 *image, u32 width, u32 height, 69 - u32 hotspotX, u32 hotspotY) 66 + /** 67 + * vmw_send_define_cursor_cmd - queue a define cursor command 68 + * @dev_priv: the private driver struct 69 + * @image: buffer which holds the cursor image 70 + * @width: width of the mouse cursor image 71 + * @height: height of the mouse cursor image 72 + * @hotspotX: the horizontal position of mouse hotspot 73 + * @hotspotY: the vertical position of mouse hotspot 74 + */ 75 + static void vmw_send_define_cursor_cmd(struct vmw_private *dev_priv, 76 + u32 *image, u32 width, u32 height, 77 + u32 hotspotX, u32 hotspotY) 70 78 { 71 79 struct vmw_svga_fifo_cmd_define_cursor *cmd; 72 80 const u32 image_size = width * height * sizeof(*image); 73 81 const u32 cmd_size = sizeof(*cmd) + image_size; 74 - 75 - if (cm_bo != NULL) { 76 - vmw_cursor_update_mob(dev_priv, cm_bo, cm_map, image, 77 - width, height, 78 - hotspotX, hotspotY); 79 - return; 80 - } 81 82 82 83 /* Try to reserve fifocmd space and swallow any failures; 83 84 such reservations cannot be left unconsumed for long ··· 86 87 other fallible KMS-atomic resources at prepare_fb */ 87 88 cmd = VMW_CMD_RESERVE(dev_priv, cmd_size); 88 89 89 - if (unlikely(cmd == NULL)) 90 + if (unlikely(!cmd)) 90 91 return; 91 92 92 93 memset(cmd, 0, sizeof(*cmd)); ··· 104 105 } 105 106 106 107 /** 108 + * vmw_cursor_update_image - update the cursor image on the provided plane 109 + * @dev_priv: the private driver struct 110 + * @vps: the plane state of the cursor plane 111 + * @image: buffer which holds the cursor image 112 + * @width: width of the mouse cursor image 113 + * @height: height of the mouse cursor image 114 + * @hotspotX: the horizontal position of mouse hotspot 115 + * @hotspotY: the vertical position of mouse hotspot 116 + */ 117 + static void vmw_cursor_update_image(struct vmw_private *dev_priv, 118 + struct vmw_plane_state *vps, 119 + u32 *image, u32 width, u32 height, 120 + u32 hotspotX, u32 hotspotY) 121 + { 122 + if (vps->cursor.bo) 123 + vmw_cursor_update_mob(dev_priv, vps, image, 124 + vps->base.crtc_w, vps->base.crtc_h, 125 + hotspotX, hotspotY); 126 + 127 + else 128 + vmw_send_define_cursor_cmd(dev_priv, image, width, height, 129 + hotspotX, hotspotY); 130 + } 131 + 132 + 133 + /** 107 134 * vmw_cursor_update_mob - Update cursor vis CursorMob mechanism 108 135 * 136 + * Called from inside vmw_du_cursor_plane_atomic_update to actually 137 + * make the cursor-image live. 138 + * 109 139 * @dev_priv: device to work with 110 - * @bo: BO for the MOB 111 - * @map: kmap obj for the BO 140 + * @vps: the plane state of the cursor plane 112 141 * @image: cursor source data to fill the MOB with 113 142 * @width: source data width 114 143 * @height: source data height ··· 144 117 * @hotspotY: cursor hotspot Y 145 118 */ 146 119 static void vmw_cursor_update_mob(struct vmw_private *dev_priv, 147 - struct ttm_buffer_object *bo, 148 - struct ttm_bo_kmap_obj *map, 120 + struct vmw_plane_state *vps, 149 121 u32 *image, u32 width, u32 height, 150 122 u32 hotspotX, u32 hotspotY) 151 123 { ··· 153 127 const u32 image_size = width * height * sizeof(*image); 154 128 bool dummy; 155 129 156 - BUG_ON(!image); 157 - 158 - header = (SVGAGBCursorHeader *)ttm_kmap_obj_virtual(map, &dummy); 130 + header = ttm_kmap_obj_virtual(&vps->cursor.map, &dummy); 159 131 alpha_header = &header->header.alphaHeader; 132 + 133 + memset(header, 0, sizeof(*header)); 160 134 161 135 header->type = SVGA_ALPHA_CURSOR; 162 136 header->sizeInBytes = image_size; ··· 167 141 alpha_header->height = height; 168 142 169 143 memcpy(header + 1, image, image_size); 170 - 171 - vmw_write(dev_priv, SVGA_REG_CURSOR_MOBID, bo->resource->start); 144 + vmw_write(dev_priv, SVGA_REG_CURSOR_MOBID, 145 + vps->cursor.bo->resource->start); 172 146 } 173 147 174 - void vmw_du_destroy_cursor_mob_array(struct vmw_cursor_plane *vcp) 175 - { 176 - size_t i; 177 148 178 - for (i = 0; i < ARRAY_SIZE(vcp->cursor_mob); i++) { 179 - if (vcp->cursor_mob[i] != NULL) { 180 - ttm_bo_unpin(vcp->cursor_mob[i]); 181 - ttm_bo_put(vcp->cursor_mob[i]); 182 - kfree(vcp->cursor_mob[i]); 183 - vcp->cursor_mob[i] = NULL; 149 + static u32 vmw_du_cursor_mob_size(u32 w, u32 h) 150 + { 151 + return w * h * sizeof(u32) + sizeof(SVGAGBCursorHeader); 152 + } 153 + 154 + /** 155 + * vmw_du_cursor_plane_acquire_image -- Acquire the image data 156 + * @vps: cursor plane state 157 + */ 158 + static u32 *vmw_du_cursor_plane_acquire_image(struct vmw_plane_state *vps) 159 + { 160 + bool dummy; 161 + if (vps->surf) { 162 + if (vps->surf_mapped) 163 + return vmw_bo_map_and_cache(vps->surf->res.backup); 164 + return vps->surf->snooper.image; 165 + } else if (vps->bo) 166 + return ttm_kmap_obj_virtual(&vps->bo->map, &dummy); 167 + return NULL; 168 + } 169 + 170 + static bool vmw_du_cursor_plane_has_changed(struct vmw_plane_state *old_vps, 171 + struct vmw_plane_state *new_vps) 172 + { 173 + void *old_image; 174 + void *new_image; 175 + u32 size; 176 + bool changed; 177 + 178 + if (old_vps->base.crtc_w != new_vps->base.crtc_w || 179 + old_vps->base.crtc_h != new_vps->base.crtc_h) 180 + return true; 181 + 182 + if (old_vps->cursor.hotspot_x != new_vps->cursor.hotspot_x || 183 + old_vps->cursor.hotspot_y != new_vps->cursor.hotspot_y) 184 + return true; 185 + 186 + size = new_vps->base.crtc_w * new_vps->base.crtc_h * sizeof(u32); 187 + 188 + old_image = vmw_du_cursor_plane_acquire_image(old_vps); 189 + new_image = vmw_du_cursor_plane_acquire_image(new_vps); 190 + 191 + changed = false; 192 + if (old_image && new_image) 193 + changed = memcmp(old_image, new_image, size) != 0; 194 + 195 + return changed; 196 + } 197 + 198 + static void vmw_du_destroy_cursor_mob(struct ttm_buffer_object **bo) 199 + { 200 + if (!(*bo)) 201 + return; 202 + 203 + ttm_bo_unpin(*bo); 204 + ttm_bo_put(*bo); 205 + kfree(*bo); 206 + *bo = NULL; 207 + } 208 + 209 + static void vmw_du_put_cursor_mob(struct vmw_cursor_plane *vcp, 210 + struct vmw_plane_state *vps) 211 + { 212 + u32 i; 213 + 214 + if (!vps->cursor.bo) 215 + return; 216 + 217 + vmw_du_cursor_plane_unmap_cm(vps); 218 + 219 + /* Look for a free slot to return this mob to the cache. */ 220 + for (i = 0; i < ARRAY_SIZE(vcp->cursor_mobs); i++) { 221 + if (!vcp->cursor_mobs[i]) { 222 + vcp->cursor_mobs[i] = vps->cursor.bo; 223 + vps->cursor.bo = NULL; 224 + return; 184 225 } 185 226 } 227 + 228 + /* Cache is full: See if this mob is bigger than an existing mob. */ 229 + for (i = 0; i < ARRAY_SIZE(vcp->cursor_mobs); i++) { 230 + if (vcp->cursor_mobs[i]->base.size < 231 + vps->cursor.bo->base.size) { 232 + vmw_du_destroy_cursor_mob(&vcp->cursor_mobs[i]); 233 + vcp->cursor_mobs[i] = vps->cursor.bo; 234 + vps->cursor.bo = NULL; 235 + return; 236 + } 237 + } 238 + 239 + /* Destroy it if it's not worth caching. */ 240 + vmw_du_destroy_cursor_mob(&vps->cursor.bo); 186 241 } 187 242 188 - #define CURSOR_MOB_SIZE(dimension) \ 189 - ((dimension) * (dimension) * sizeof(u32) + sizeof(SVGAGBCursorHeader)) 190 - 191 - int vmw_du_create_cursor_mob_array(struct vmw_cursor_plane *cursor) 243 + static int vmw_du_get_cursor_mob(struct vmw_cursor_plane *vcp, 244 + struct vmw_plane_state *vps) 192 245 { 193 - struct vmw_private *dev_priv = cursor->base.dev->dev_private; 194 - uint32_t cursor_max_dim, mob_max_size; 195 - int ret = 0; 196 - size_t i; 246 + struct vmw_private *dev_priv = vcp->base.dev->dev_private; 247 + u32 size = vmw_du_cursor_mob_size(vps->base.crtc_w, vps->base.crtc_h); 248 + u32 i; 249 + u32 cursor_max_dim, mob_max_size; 250 + int ret; 197 251 198 - if (!dev_priv->has_mob || (dev_priv->capabilities2 & SVGA_CAP2_CURSOR_MOB) == 0) 199 - return -ENOSYS; 252 + if (!dev_priv->has_mob || 253 + (dev_priv->capabilities2 & SVGA_CAP2_CURSOR_MOB) == 0) 254 + return -EINVAL; 200 255 201 256 mob_max_size = vmw_read(dev_priv, SVGA_REG_MOB_MAX_SIZE); 202 257 cursor_max_dim = vmw_read(dev_priv, SVGA_REG_CURSOR_MAX_DIMENSION); 203 258 204 - if (CURSOR_MOB_SIZE(cursor_max_dim) > mob_max_size) 205 - cursor_max_dim = 64; /* Mandatorily-supported cursor dimension */ 259 + if (size > mob_max_size || vps->base.crtc_w > cursor_max_dim || 260 + vps->base.crtc_h > cursor_max_dim) 261 + return -EINVAL; 206 262 207 - for (i = 0; i < ARRAY_SIZE(cursor->cursor_mob); i++) { 208 - struct ttm_buffer_object **const bo = &cursor->cursor_mob[i]; 209 - 210 - ret = vmw_bo_create_kernel(dev_priv, 211 - CURSOR_MOB_SIZE(cursor_max_dim), 212 - &vmw_mob_placement, bo); 213 - 214 - if (ret != 0) 215 - goto teardown; 216 - 217 - if ((*bo)->resource->mem_type != VMW_PL_MOB) { 218 - DRM_ERROR("Obtained buffer object is not a MOB.\n"); 219 - ret = -ENOSYS; 220 - goto teardown; 221 - } 222 - 223 - /* Fence the mob creation so we are guarateed to have the mob */ 224 - ret = ttm_bo_reserve(*bo, false, false, NULL); 225 - 226 - if (ret != 0) 227 - goto teardown; 228 - 229 - vmw_bo_fence_single(*bo, NULL); 230 - 231 - ttm_bo_unreserve(*bo); 232 - 233 - drm_info(&dev_priv->drm, "Using CursorMob mobid %lu, max dimension %u\n", 234 - (*bo)->resource->start, cursor_max_dim); 263 + if (vps->cursor.bo) { 264 + if (vps->cursor.bo->base.size >= size) 265 + return 0; 266 + vmw_du_put_cursor_mob(vcp, vps); 235 267 } 236 268 269 + /* Look for an unused mob in the cache. */ 270 + for (i = 0; i < ARRAY_SIZE(vcp->cursor_mobs); i++) { 271 + if (vcp->cursor_mobs[i] && 272 + vcp->cursor_mobs[i]->base.size >= size) { 273 + vps->cursor.bo = vcp->cursor_mobs[i]; 274 + vcp->cursor_mobs[i] = NULL; 275 + return 0; 276 + } 277 + } 278 + /* Create a new mob if we can't find an existing one. */ 279 + ret = vmw_bo_create_kernel(dev_priv, size, &vmw_mob_placement, 280 + &vps->cursor.bo); 281 + 282 + if (ret != 0) 283 + return ret; 284 + 285 + /* Fence the mob creation so we are guarateed to have the mob */ 286 + ret = ttm_bo_reserve(vps->cursor.bo, false, false, NULL); 287 + if (ret != 0) 288 + goto teardown; 289 + 290 + vmw_bo_fence_single(vps->cursor.bo, NULL); 291 + ttm_bo_unreserve(vps->cursor.bo); 237 292 return 0; 238 293 239 294 teardown: 240 - vmw_du_destroy_cursor_mob_array(cursor); 241 - 295 + vmw_du_destroy_cursor_mob(&vps->cursor.bo); 242 296 return ret; 243 - } 244 - 245 - #undef CURSOR_MOB_SIZE 246 - 247 - static void vmw_cursor_update_bo(struct vmw_private *dev_priv, 248 - struct ttm_buffer_object *cm_bo, 249 - struct ttm_bo_kmap_obj *cm_map, 250 - struct vmw_buffer_object *bo, 251 - u32 width, u32 height, 252 - u32 hotspotX, u32 hotspotY) 253 - { 254 - void *virtual; 255 - bool dummy; 256 - 257 - virtual = ttm_kmap_obj_virtual(&bo->map, &dummy); 258 - if (virtual) { 259 - vmw_cursor_update_image(dev_priv, cm_bo, cm_map, virtual, 260 - width, height, 261 - hotspotX, hotspotY); 262 - atomic_dec(&bo->base_mapped_count); 263 - } 264 297 } 265 298 266 299 ··· 372 287 373 288 cmd = container_of(header, struct vmw_dma_cmd, header); 374 289 375 - /* No snooper installed */ 290 + /* No snooper installed, nothing to copy */ 376 291 if (!srf->snooper.image) 377 292 return; 378 293 ··· 472 387 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 473 388 du = vmw_crtc_to_du(crtc); 474 389 if (!du->cursor_surface || 475 - du->cursor_age == du->cursor_surface->snooper.age) 390 + du->cursor_age == du->cursor_surface->snooper.age || 391 + !du->cursor_surface->snooper.image) 476 392 continue; 477 393 478 394 du->cursor_age = du->cursor_surface->snooper.age; 479 - vmw_cursor_update_image(dev_priv, NULL, NULL, 480 - du->cursor_surface->snooper.image, 481 - 64, 64, 482 - du->hotspot_x + du->core_hotspot_x, 483 - du->hotspot_y + du->core_hotspot_y); 395 + vmw_send_define_cursor_cmd(dev_priv, 396 + du->cursor_surface->snooper.image, 397 + 64, 64, 398 + du->hotspot_x + du->core_hotspot_x, 399 + du->hotspot_y + du->core_hotspot_y); 484 400 } 485 401 486 402 mutex_unlock(&dev->mode_config.mutex); ··· 490 404 491 405 void vmw_du_cursor_plane_destroy(struct drm_plane *plane) 492 406 { 407 + struct vmw_cursor_plane *vcp = vmw_plane_to_vcp(plane); 408 + u32 i; 409 + 493 410 vmw_cursor_update_position(plane->dev->dev_private, false, 0, 0); 494 - vmw_du_destroy_cursor_mob_array(vmw_plane_to_vcp(plane)); 411 + 412 + for (i = 0; i < ARRAY_SIZE(vcp->cursor_mobs); i++) 413 + vmw_du_destroy_cursor_mob(&vcp->cursor_mobs[i]); 414 + 495 415 drm_plane_cleanup(plane); 496 416 } 497 417 ··· 555 463 556 464 557 465 /** 466 + * vmw_du_cursor_plane_map_cm - Maps the cursor mobs. 467 + * 468 + * @vps: plane_state 469 + * 470 + * Returns 0 on success 471 + */ 472 + 473 + static int 474 + vmw_du_cursor_plane_map_cm(struct vmw_plane_state *vps) 475 + { 476 + int ret; 477 + u32 size = vmw_du_cursor_mob_size(vps->base.crtc_w, vps->base.crtc_h); 478 + struct ttm_buffer_object *bo = vps->cursor.bo; 479 + 480 + if (!bo) 481 + return -EINVAL; 482 + 483 + if (bo->base.size < size) 484 + return -EINVAL; 485 + 486 + if (vps->cursor.mapped) 487 + return 0; 488 + 489 + ret = ttm_bo_reserve(bo, false, false, NULL); 490 + 491 + if (unlikely(ret != 0)) 492 + return -ENOMEM; 493 + 494 + ret = ttm_bo_kmap(bo, 0, PFN_UP(size), &vps->cursor.map); 495 + 496 + /* 497 + * We just want to try to get mob bind to finish 498 + * so that the first write to SVGA_REG_CURSOR_MOBID 499 + * is done with a buffer that the device has already 500 + * seen 501 + */ 502 + (void) ttm_bo_wait(bo, false, false); 503 + 504 + ttm_bo_unreserve(bo); 505 + 506 + if (unlikely(ret != 0)) 507 + return -ENOMEM; 508 + 509 + vps->cursor.mapped = true; 510 + 511 + return 0; 512 + } 513 + 514 + 515 + /** 516 + * vmw_du_cursor_plane_unmap_cm - Unmaps the cursor mobs. 517 + * 518 + * @vps: state of the cursor plane 519 + * 520 + * Returns 0 on success 521 + */ 522 + 523 + static int 524 + vmw_du_cursor_plane_unmap_cm(struct vmw_plane_state *vps) 525 + { 526 + int ret = 0; 527 + struct ttm_buffer_object *bo = vps->cursor.bo; 528 + 529 + if (!vps->cursor.mapped) 530 + return 0; 531 + 532 + if (!bo) 533 + return 0; 534 + 535 + ret = ttm_bo_reserve(bo, true, false, NULL); 536 + if (likely(ret == 0)) { 537 + ttm_bo_kunmap(&vps->cursor.map); 538 + ttm_bo_unreserve(bo); 539 + vps->cursor.mapped = false; 540 + } 541 + 542 + return ret; 543 + } 544 + 545 + 546 + /** 558 547 * vmw_du_cursor_plane_cleanup_fb - Unpins the plane surface 559 548 * 560 549 * @plane: cursor plane ··· 649 476 vmw_du_cursor_plane_cleanup_fb(struct drm_plane *plane, 650 477 struct drm_plane_state *old_state) 651 478 { 479 + struct vmw_cursor_plane *vcp = vmw_plane_to_vcp(plane); 652 480 struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state); 653 481 bool dummy; 654 482 655 - if (vps->bo != NULL && ttm_kmap_obj_virtual(&vps->bo->map, &dummy) != NULL) { 483 + if (vps->surf_mapped) { 484 + vmw_bo_unmap(vps->surf->res.backup); 485 + vps->surf_mapped = false; 486 + } 487 + 488 + if (vps->bo && ttm_kmap_obj_virtual(&vps->bo->map, &dummy)) { 656 489 const int ret = ttm_bo_reserve(&vps->bo->base, true, false, NULL); 657 490 658 491 if (likely(ret == 0)) { ··· 668 489 } 669 490 } 670 491 671 - if (vps->cm_bo != NULL && ttm_kmap_obj_virtual(&vps->cm_map, &dummy) != NULL) { 672 - const int ret = ttm_bo_reserve(vps->cm_bo, true, false, NULL); 673 - 674 - if (likely(ret == 0)) { 675 - ttm_bo_kunmap(&vps->cm_map); 676 - ttm_bo_unreserve(vps->cm_bo); 677 - } 678 - } 492 + vmw_du_cursor_plane_unmap_cm(vps); 493 + vmw_du_put_cursor_mob(vcp, vps); 679 494 680 495 vmw_du_plane_unpin_surf(vps, false); 681 496 ··· 683 510 vps->bo = NULL; 684 511 } 685 512 } 513 + 686 514 687 515 /** 688 516 * vmw_du_cursor_plane_prepare_fb - Readies the cursor by referencing it ··· 700 526 struct drm_framebuffer *fb = new_state->fb; 701 527 struct vmw_cursor_plane *vcp = vmw_plane_to_vcp(plane); 702 528 struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state); 703 - struct ttm_buffer_object *cm_bo = NULL; 704 - bool dummy; 705 529 int ret = 0; 706 530 707 531 if (vps->surf) { ··· 722 550 } 723 551 } 724 552 725 - vps->cm_bo = NULL; 726 - 727 - if (vps->surf == NULL && vps->bo != NULL) { 553 + if (!vps->surf && vps->bo) { 728 554 const u32 size = new_state->crtc_w * new_state->crtc_h * sizeof(u32); 729 555 730 - /* Not using vmw_bo_map_and_cache() helper here as we need to reserve 731 - the ttm_buffer_object first which wmw_bo_map_and_cache() omits. */ 556 + /* 557 + * Not using vmw_bo_map_and_cache() helper here as we need to 558 + * reserve the ttm_buffer_object first which 559 + * vmw_bo_map_and_cache() omits. 560 + */ 732 561 ret = ttm_bo_reserve(&vps->bo->base, true, false, NULL); 733 562 734 563 if (unlikely(ret != 0)) ··· 744 571 745 572 if (unlikely(ret != 0)) 746 573 return -ENOMEM; 574 + } else if (vps->surf && !vps->bo && vps->surf->res.backup) { 575 + 576 + WARN_ON(vps->surf->snooper.image); 577 + ret = ttm_bo_reserve(&vps->surf->res.backup->base, true, false, 578 + NULL); 579 + if (unlikely(ret != 0)) 580 + return -ENOMEM; 581 + vmw_bo_map_and_cache(vps->surf->res.backup); 582 + ttm_bo_unreserve(&vps->surf->res.backup->base); 583 + vps->surf_mapped = true; 747 584 } 748 585 749 586 if (vps->surf || vps->bo) { 750 - unsigned cursor_mob_idx = vps->cursor_mob_idx; 751 - 752 - /* Lazily set up cursor MOBs just once -- no reattempts. */ 753 - if (cursor_mob_idx == 0 && vcp->cursor_mob[0] == NULL) 754 - if (vmw_du_create_cursor_mob_array(vcp) != 0) 755 - vps->cursor_mob_idx = cursor_mob_idx = -1U; 756 - 757 - if (cursor_mob_idx < ARRAY_SIZE(vcp->cursor_mob)) { 758 - const u32 size = sizeof(SVGAGBCursorHeader) + 759 - new_state->crtc_w * new_state->crtc_h * sizeof(u32); 760 - 761 - cm_bo = vcp->cursor_mob[cursor_mob_idx]; 762 - 763 - if (cm_bo->resource->num_pages * PAGE_SIZE < size) { 764 - ret = -EINVAL; 765 - goto error_bo_unmap; 766 - } 767 - 768 - ret = ttm_bo_reserve(cm_bo, false, false, NULL); 769 - 770 - if (unlikely(ret != 0)) { 771 - ret = -ENOMEM; 772 - goto error_bo_unmap; 773 - } 774 - 775 - ret = ttm_bo_kmap(cm_bo, 0, PFN_UP(size), &vps->cm_map); 776 - 777 - /* 778 - * We just want to try to get mob bind to finish 779 - * so that the first write to SVGA_REG_CURSOR_MOBID 780 - * is done with a buffer that the device has already 781 - * seen 782 - */ 783 - (void) ttm_bo_wait(cm_bo, false, false); 784 - 785 - ttm_bo_unreserve(cm_bo); 786 - 787 - if (unlikely(ret != 0)) { 788 - ret = -ENOMEM; 789 - goto error_bo_unmap; 790 - } 791 - 792 - vps->cursor_mob_idx = cursor_mob_idx ^ 1; 793 - vps->cm_bo = cm_bo; 794 - } 587 + vmw_du_get_cursor_mob(vcp, vps); 588 + vmw_du_cursor_plane_map_cm(vps); 795 589 } 796 590 797 591 return 0; 798 - 799 - error_bo_unmap: 800 - if (vps->bo != NULL && ttm_kmap_obj_virtual(&vps->bo->map, &dummy) != NULL) { 801 - const int ret = ttm_bo_reserve(&vps->bo->base, true, false, NULL); 802 - if (likely(ret == 0)) { 803 - atomic_dec(&vps->bo->base_mapped_count); 804 - ttm_bo_kunmap(&vps->bo->map); 805 - ttm_bo_unreserve(&vps->bo->base); 806 - } 807 - } 808 - 809 - return ret; 810 592 } 811 593 812 594 ··· 777 649 struct vmw_private *dev_priv = vmw_priv(crtc->dev); 778 650 struct vmw_display_unit *du = vmw_crtc_to_du(crtc); 779 651 struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state); 652 + struct vmw_plane_state *old_vps = vmw_plane_state_to_vps(old_state); 780 653 s32 hotspot_x, hotspot_y; 654 + bool dummy; 781 655 782 656 hotspot_x = du->hotspot_x; 783 657 hotspot_y = du->hotspot_y; ··· 792 662 du->cursor_surface = vps->surf; 793 663 du->cursor_bo = vps->bo; 794 664 795 - if (vps->surf) { 796 - du->cursor_age = du->cursor_surface->snooper.age; 797 - 798 - vmw_cursor_update_image(dev_priv, vps->cm_bo, &vps->cm_map, 799 - vps->surf->snooper.image, 800 - new_state->crtc_w, 801 - new_state->crtc_h, 802 - hotspot_x, hotspot_y); 803 - } else if (vps->bo) { 804 - vmw_cursor_update_bo(dev_priv, vps->cm_bo, &vps->cm_map, 805 - vps->bo, 806 - new_state->crtc_w, 807 - new_state->crtc_h, 808 - hotspot_x, hotspot_y); 809 - } else { 665 + if (!vps->surf && !vps->bo) { 810 666 vmw_cursor_update_position(dev_priv, false, 0, 0); 811 667 return; 668 + } 669 + 670 + vps->cursor.hotspot_x = hotspot_x; 671 + vps->cursor.hotspot_y = hotspot_y; 672 + 673 + if (vps->surf) { 674 + du->cursor_age = du->cursor_surface->snooper.age; 675 + } 676 + 677 + if (!vmw_du_cursor_plane_has_changed(old_vps, vps)) { 678 + /* 679 + * If it hasn't changed, avoid making the device do extra 680 + * work by keeping the old cursor active. 681 + */ 682 + struct vmw_cursor_plane_state tmp = old_vps->cursor; 683 + old_vps->cursor = vps->cursor; 684 + vps->cursor = tmp; 685 + } else { 686 + void *image = vmw_du_cursor_plane_acquire_image(vps); 687 + if (image) 688 + vmw_cursor_update_image(dev_priv, vps, image, 689 + new_state->crtc_w, 690 + new_state->crtc_h, 691 + hotspot_x, hotspot_y); 692 + } 693 + 694 + if (vps->bo) { 695 + if (ttm_kmap_obj_virtual(&vps->bo->map, &dummy)) 696 + atomic_dec(&vps->bo->base_mapped_count); 812 697 } 813 698 814 699 du->cursor_x = new_state->crtc_x + du->set_gui_x; ··· 923 778 return -EINVAL; 924 779 } 925 780 926 - if (!vmw_framebuffer_to_vfb(fb)->bo) 781 + if (!vmw_framebuffer_to_vfb(fb)->bo) { 927 782 surface = vmw_framebuffer_to_vfbs(fb)->surface; 928 783 929 - if (surface && !surface->snooper.image) { 930 - DRM_ERROR("surface not suitable for cursor\n"); 931 - return -EINVAL; 784 + WARN_ON(!surface); 785 + 786 + if (!surface || 787 + (!surface->snooper.image && !surface->res.backup)) { 788 + DRM_ERROR("surface not suitable for cursor\n"); 789 + return -EINVAL; 790 + } 932 791 } 933 792 934 793 return 0; ··· 980 831 void vmw_du_crtc_atomic_flush(struct drm_crtc *crtc, 981 832 struct drm_atomic_state *state) 982 833 { 983 - struct drm_pending_vblank_event *event = crtc->state->event; 984 - 985 - if (event) { 986 - crtc->state->event = NULL; 987 - 988 - spin_lock_irq(&crtc->dev->event_lock); 989 - drm_crtc_send_vblank_event(crtc, event); 990 - spin_unlock_irq(&crtc->dev->event_lock); 991 - } 992 834 } 993 835 994 836 ··· 1083 943 vps->pinned = 0; 1084 944 vps->cpp = 0; 1085 945 946 + memset(&vps->cursor, 0, sizeof(vps->cursor)); 947 + 1086 948 /* Each ref counted resource needs to be acquired again */ 1087 949 if (vps->surf) 1088 950 (void) vmw_surface_reference(vps->surf); ··· 1138 996 struct drm_plane_state *state) 1139 997 { 1140 998 struct vmw_plane_state *vps = vmw_plane_state_to_vps(state); 1141 - 1142 999 1143 1000 /* Should have been freed by cleanup_fb */ 1144 1001 if (vps->surf) ··· 2193 2052 dev->mode_config.min_height = 1; 2194 2053 dev->mode_config.max_width = dev_priv->texture_max_width; 2195 2054 dev->mode_config.max_height = dev_priv->texture_max_height; 2055 + dev->mode_config.preferred_depth = dev_priv->assume_16bpp ? 16 : 32; 2056 + dev->mode_config.prefer_shadow_fbdev = !dev_priv->has_mob; 2196 2057 2197 2058 drm_mode_create_suggested_offset_properties(dev); 2198 2059 vmw_kms_create_hotplug_mode_update_property(dev_priv); ··· 2235 2092 struct vmw_display_unit *du; 2236 2093 struct drm_crtc *crtc; 2237 2094 int ret = 0; 2238 - 2239 2095 2240 2096 mutex_lock(&dev->mode_config.mutex); 2241 2097 if (arg->flags & DRM_VMW_CURSOR_BYPASS_ALL) { ··· 2297 2155 dev_priv->max_primary_mem : dev_priv->vram_size); 2298 2156 } 2299 2157 2300 - 2301 - /* 2302 - * Function called by DRM code called with vbl_lock held. 2303 - */ 2304 - u32 vmw_get_vblank_counter(struct drm_crtc *crtc) 2305 - { 2306 - return 0; 2307 - } 2308 - 2309 - /* 2310 - * Function called by DRM code called with vbl_lock held. 2311 - */ 2312 - int vmw_enable_vblank(struct drm_crtc *crtc) 2313 - { 2314 - return -EINVAL; 2315 - } 2316 - 2317 - /* 2318 - * Function called by DRM code called with vbl_lock held. 2319 - */ 2320 - void vmw_disable_vblank(struct drm_crtc *crtc) 2321 - { 2322 - } 2323 - 2324 2158 /** 2325 2159 * vmw_du_update_layout - Update the display unit with topology from resolution 2326 2160 * plugin and generate DRM uevent ··· 2340 2222 du->gui_x = rects[du->unit].x1; 2341 2223 du->gui_y = rects[du->unit].y1; 2342 2224 } else { 2343 - du->pref_width = 800; 2344 - du->pref_height = 600; 2225 + du->pref_width = VMWGFX_MIN_INITIAL_WIDTH; 2226 + du->pref_height = VMWGFX_MIN_INITIAL_HEIGHT; 2345 2227 du->pref_active = false; 2346 2228 du->gui_x = 0; 2347 2229 du->gui_y = 0; ··· 2368 2250 } 2369 2251 con->status = vmw_du_connector_detect(con, true); 2370 2252 } 2371 - 2372 - drm_sysfs_hotplug_event(dev); 2373 2253 out_fini: 2374 2254 drm_modeset_drop_locks(&ctx); 2375 2255 drm_modeset_acquire_fini(&ctx); 2376 2256 mutex_unlock(&dev->mode_config.mutex); 2257 + 2258 + drm_sysfs_hotplug_event(dev); 2377 2259 2378 2260 return 0; 2379 2261 } ··· 2654 2536 int ret, i; 2655 2537 2656 2538 if (!arg->num_outputs) { 2657 - struct drm_rect def_rect = {0, 0, 800, 600}; 2658 - VMW_DEBUG_KMS("Default layout x1 = %d y1 = %d x2 = %d y2 = %d\n", 2659 - def_rect.x1, def_rect.y1, 2660 - def_rect.x2, def_rect.y2); 2539 + struct drm_rect def_rect = {0, 0, 2540 + VMWGFX_MIN_INITIAL_WIDTH, 2541 + VMWGFX_MIN_INITIAL_HEIGHT}; 2661 2542 vmw_du_update_layout(dev_priv, 1, &def_rect); 2662 2543 return 0; 2663 2544 } ··· 2949 2832 vmw_cmd_commit(dev_priv, copy_size); 2950 2833 2951 2834 return 0; 2952 - } 2953 - 2954 - int vmw_kms_fbdev_init_data(struct vmw_private *dev_priv, 2955 - unsigned unit, 2956 - u32 max_width, 2957 - u32 max_height, 2958 - struct drm_connector **p_con, 2959 - struct drm_crtc **p_crtc, 2960 - struct drm_display_mode **p_mode) 2961 - { 2962 - struct drm_connector *con; 2963 - struct vmw_display_unit *du; 2964 - struct drm_display_mode *mode; 2965 - int i = 0; 2966 - int ret = 0; 2967 - 2968 - mutex_lock(&dev_priv->drm.mode_config.mutex); 2969 - list_for_each_entry(con, &dev_priv->drm.mode_config.connector_list, 2970 - head) { 2971 - if (i == unit) 2972 - break; 2973 - 2974 - ++i; 2975 - } 2976 - 2977 - if (&con->head == &dev_priv->drm.mode_config.connector_list) { 2978 - DRM_ERROR("Could not find initial display unit.\n"); 2979 - ret = -EINVAL; 2980 - goto out_unlock; 2981 - } 2982 - 2983 - if (list_empty(&con->modes)) 2984 - (void) vmw_du_connector_fill_modes(con, max_width, max_height); 2985 - 2986 - if (list_empty(&con->modes)) { 2987 - DRM_ERROR("Could not find initial display mode.\n"); 2988 - ret = -EINVAL; 2989 - goto out_unlock; 2990 - } 2991 - 2992 - du = vmw_connector_to_du(con); 2993 - *p_con = con; 2994 - *p_crtc = &du->crtc; 2995 - 2996 - list_for_each_entry(mode, &con->modes, head) { 2997 - if (mode->type & DRM_MODE_TYPE_PREFERRED) 2998 - break; 2999 - } 3000 - 3001 - if (&mode->head == &con->modes) { 3002 - WARN_ONCE(true, "Could not find initial preferred mode.\n"); 3003 - *p_mode = list_first_entry(&con->modes, 3004 - struct drm_display_mode, 3005 - head); 3006 - } else { 3007 - *p_mode = mode; 3008 - } 3009 - 3010 - out_unlock: 3011 - mutex_unlock(&dev_priv->drm.mode_config.mutex); 3012 - 3013 - return ret; 3014 2835 } 3015 2836 3016 2837 /**
+13 -18
drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
··· 272 272 struct drm_crtc_state base; 273 273 }; 274 274 275 + struct vmw_cursor_plane_state { 276 + struct ttm_buffer_object *bo; 277 + struct ttm_bo_kmap_obj map; 278 + bool mapped; 279 + s32 hotspot_x; 280 + s32 hotspot_y; 281 + }; 282 + 275 283 /** 276 284 * Derived class for plane state object 277 285 * ··· 303 295 /* For CPU Blit */ 304 296 unsigned int cpp; 305 297 306 - /* CursorMob flipping index; -1 if cursor mobs not used */ 307 - unsigned int cursor_mob_idx; 308 - /* Currently-active CursorMob */ 309 - struct ttm_buffer_object *cm_bo; 310 - /* CursorMob kmap_obj; expected valid at cursor_plane_atomic_update 311 - IFF currently-active CursorMob above is valid */ 312 - struct ttm_bo_kmap_obj cm_map; 298 + bool surf_mapped; 299 + struct vmw_cursor_plane_state cursor; 313 300 }; 314 301 315 302 ··· 341 338 * Derived class for cursor plane object 342 339 * 343 340 * @base DRM plane object 344 - * @cursor_mob array of two MOBs for CursorMob flipping 341 + * @cursor.cursor_mobs Cursor mobs available for re-use 345 342 */ 346 343 struct vmw_cursor_plane { 347 344 struct drm_plane base; 348 - struct ttm_buffer_object *cursor_mob[2]; 345 + 346 + struct ttm_buffer_object *cursor_mobs[3]; 349 347 }; 350 348 351 349 /** ··· 462 458 struct vmw_surface *surface, 463 459 bool only_2d, 464 460 const struct drm_mode_fb_cmd2 *mode_cmd); 465 - int vmw_kms_fbdev_init_data(struct vmw_private *dev_priv, 466 - unsigned unit, 467 - u32 max_width, 468 - u32 max_height, 469 - struct drm_connector **p_con, 470 - struct drm_crtc **p_crtc, 471 - struct drm_display_mode **p_mode); 472 461 void vmw_guess_mode_timing(struct drm_display_mode *mode); 473 462 void vmw_kms_update_implicit_fb(struct vmw_private *dev_priv); 474 463 void vmw_kms_create_implicit_placement_property(struct vmw_private *dev_priv); ··· 469 472 /* Universal Plane Helpers */ 470 473 void vmw_du_primary_plane_destroy(struct drm_plane *plane); 471 474 void vmw_du_cursor_plane_destroy(struct drm_plane *plane); 472 - int vmw_du_create_cursor_mob_array(struct vmw_cursor_plane *vcp); 473 - void vmw_du_destroy_cursor_mob_array(struct vmw_cursor_plane *vcp); 474 475 475 476 /* Atomic Helpers */ 476 477 int vmw_du_primary_plane_atomic_check(struct drm_plane *plane,
-8
drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
··· 28 28 #include <drm/drm_atomic.h> 29 29 #include <drm/drm_atomic_helper.h> 30 30 #include <drm/drm_fourcc.h> 31 - #include <drm/drm_vblank.h> 32 31 33 32 #include "vmwgfx_kms.h" 34 33 ··· 234 235 .atomic_duplicate_state = vmw_du_crtc_duplicate_state, 235 236 .atomic_destroy_state = vmw_du_crtc_destroy_state, 236 237 .set_config = drm_atomic_helper_set_config, 237 - .get_vblank_counter = vmw_get_vblank_counter, 238 - .enable_vblank = vmw_enable_vblank, 239 - .disable_vblank = vmw_disable_vblank, 240 238 }; 241 239 242 240 ··· 502 506 dev_priv->ldu_priv->num_active = 0; 503 507 dev_priv->ldu_priv->last_num_active = 0; 504 508 dev_priv->ldu_priv->fb = NULL; 505 - 506 - ret = drm_vblank_init(dev, num_display_units); 507 - if (ret != 0) 508 - goto err_free; 509 509 510 510 vmw_kms_create_implicit_placement_property(dev_priv); 511 511
+2
drivers/gpu/drm/vmwgfx/vmwgfx_mksstat.h
··· 29 29 #define _VMWGFX_MKSSTAT_H_ 30 30 31 31 #include <asm/page.h> 32 + #include <linux/kconfig.h> 32 33 33 34 /* Reservation marker for mksstat pid's */ 34 35 #define MKSSTAT_PID_RESERVED -1 ··· 42 41 43 42 typedef enum { 44 43 MKSSTAT_KERN_EXECBUF, /* vmw_execbuf_ioctl */ 44 + MKSSTAT_KERN_COTABLE_RESIZE, 45 45 46 46 MKSSTAT_KERN_COUNT /* Reserved entry; always last */ 47 47 } mksstat_kern_stats_t;
+38 -21
drivers/gpu/drm/vmwgfx/vmwgfx_msg.c
··· 85 85 u32 cookie_low; 86 86 }; 87 87 88 - 88 + #if IS_ENABLED(CONFIG_DRM_VMWGFX_MKSSTATS) 89 + /* Kernel mksGuestStats counter names and desciptions; same order as enum mksstat_kern_stats_t */ 90 + static const char* const mksstat_kern_name_desc[MKSSTAT_KERN_COUNT][2] = 91 + { 92 + { "vmw_execbuf_ioctl", "vmw_execbuf_ioctl" }, 93 + { "vmw_cotable_resize", "vmw_cotable_resize" }, 94 + }; 95 + #endif 89 96 90 97 /** 91 98 * vmw_open_channel ··· 702 695 /* Header to the text description of mksGuestStat instance descriptor */ 703 696 #define MKSSTAT_KERNEL_DESCRIPTION "vmwgfx" 704 697 705 - /* Kernel mksGuestStats counter names and desciptions; same order as enum mksstat_kern_stats_t */ 706 - static const char* const mksstat_kern_name_desc[MKSSTAT_KERN_COUNT][2] = 707 - { 708 - { "vmw_execbuf_ioctl", "vmw_execbuf_ioctl" }, 709 - }; 710 - 711 698 /** 712 699 * mksstat_init_record: Initializes an MKSGuestStatCounter-based record 713 700 * for the respective mksGuestStat index. ··· 787 786 /* Set up all kernel-internal counters and corresponding structures */ 788 787 pstrs_acc = pstrs; 789 788 pstrs_acc = mksstat_init_record_time(MKSSTAT_KERN_EXECBUF, pstat, pinfo, pstrs_acc); 789 + pstrs_acc = mksstat_init_record_time(MKSSTAT_KERN_COTABLE_RESIZE, pstat, pinfo, pstrs_acc); 790 790 791 791 /* Add new counters above, in their order of appearance in mksstat_kern_stats_t */ 792 792 ··· 1016 1014 1017 1015 struct vmw_private *const dev_priv = vmw_priv(dev); 1018 1016 1019 - struct page *page; 1020 - MKSGuestStatInstanceDescriptor *pdesc; 1021 1017 const size_t num_pages_stat = PFN_UP(arg->stat_len); 1022 1018 const size_t num_pages_info = PFN_UP(arg->info_len); 1023 1019 const size_t num_pages_strs = PFN_UP(arg->strs_len); ··· 1023 1023 long nr_pinned_stat; 1024 1024 long nr_pinned_info; 1025 1025 long nr_pinned_strs; 1026 - struct page *pages_stat[ARRAY_SIZE(pdesc->statPPNs)]; 1027 - struct page *pages_info[ARRAY_SIZE(pdesc->infoPPNs)]; 1028 - struct page *pages_strs[ARRAY_SIZE(pdesc->strsPPNs)]; 1026 + MKSGuestStatInstanceDescriptor *pdesc; 1027 + struct page *page = NULL; 1028 + struct page **pages_stat = NULL; 1029 + struct page **pages_info = NULL; 1030 + struct page **pages_strs = NULL; 1029 1031 size_t i, slot; 1032 + int ret_err = -ENOMEM; 1030 1033 1031 1034 arg->id = -1; 1032 1035 ··· 1057 1054 1058 1055 BUG_ON(dev_priv->mksstat_user_pages[slot]); 1059 1056 1057 + /* Allocate statically-sized temp arrays for pages -- too big to keep in frame */ 1058 + pages_stat = (struct page **)kmalloc_array( 1059 + ARRAY_SIZE(pdesc->statPPNs) + 1060 + ARRAY_SIZE(pdesc->infoPPNs) + 1061 + ARRAY_SIZE(pdesc->strsPPNs), sizeof(*pages_stat), GFP_KERNEL); 1062 + 1063 + if (!pages_stat) 1064 + goto err_nomem; 1065 + 1066 + pages_info = pages_stat + ARRAY_SIZE(pdesc->statPPNs); 1067 + pages_strs = pages_info + ARRAY_SIZE(pdesc->infoPPNs); 1068 + 1060 1069 /* Allocate a page for the instance descriptor */ 1061 1070 page = alloc_page(GFP_KERNEL | __GFP_ZERO); 1062 1071 1063 - if (!page) { 1064 - atomic_set(&dev_priv->mksstat_user_pids[slot], 0); 1065 - return -ENOMEM; 1066 - } 1072 + if (!page) 1073 + goto err_nomem; 1067 1074 1068 1075 /* Set up the instance descriptor */ 1069 1076 pdesc = page_address(page); ··· 1088 1075 ARRAY_SIZE(pdesc->description) - 1); 1089 1076 1090 1077 if (desc_len < 0) { 1091 - atomic_set(&dev_priv->mksstat_user_pids[slot], 0); 1092 - __free_page(page); 1093 - return -EFAULT; 1078 + ret_err = -EFAULT; 1079 + goto err_nomem; 1094 1080 } 1095 1081 1096 1082 reset_ppn_array(pdesc->statPPNs, ARRAY_SIZE(pdesc->statPPNs)); ··· 1130 1118 1131 1119 DRM_DEV_INFO(dev->dev, "pid=%d arg.description='%.*s' id=%zu\n", current->pid, (int)desc_len, pdesc->description, slot); 1132 1120 1121 + kfree(pages_stat); 1133 1122 return 0; 1134 1123 1135 1124 err_pin_strs: ··· 1145 1132 if (nr_pinned_stat > 0) 1146 1133 unpin_user_pages(pages_stat, nr_pinned_stat); 1147 1134 1135 + err_nomem: 1148 1136 atomic_set(&dev_priv->mksstat_user_pids[slot], 0); 1149 - __free_page(page); 1150 - return -ENOMEM; 1137 + if (page) 1138 + __free_page(page); 1139 + kfree(pages_stat); 1140 + 1141 + return ret_err; 1151 1142 } 1152 1143 1153 1144 /**
+1 -30
drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
··· 29 29 #include <drm/drm_atomic_helper.h> 30 30 #include <drm/drm_damage_helper.h> 31 31 #include <drm/drm_fourcc.h> 32 - #include <drm/drm_vblank.h> 33 32 34 33 #include "vmwgfx_kms.h" 35 34 ··· 319 320 .atomic_destroy_state = vmw_du_crtc_destroy_state, 320 321 .set_config = drm_atomic_helper_set_config, 321 322 .page_flip = drm_atomic_helper_page_flip, 322 - .get_vblank_counter = vmw_get_vblank_counter, 323 - .enable_vblank = vmw_enable_vblank, 324 - .disable_vblank = vmw_disable_vblank, 325 323 }; 326 324 327 325 /* ··· 726 730 struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane); 727 731 struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane); 728 732 struct drm_crtc *crtc = new_state->crtc; 729 - struct drm_pending_vblank_event *event = NULL; 730 733 struct vmw_fence_obj *fence = NULL; 731 734 int ret; 732 735 ··· 747 752 } else { 748 753 /* Do nothing when fb and crtc is NULL (blank crtc) */ 749 754 return; 750 - } 751 - 752 - /* For error case vblank event is send from vmw_du_crtc_atomic_flush */ 753 - event = crtc->state->event; 754 - if (event && fence) { 755 - struct drm_file *file_priv = event->base.file_priv; 756 - 757 - ret = vmw_event_fence_action_queue(file_priv, 758 - fence, 759 - &event->base, 760 - &event->event.vbl.tv_sec, 761 - &event->event.vbl.tv_usec, 762 - true); 763 - 764 - if (unlikely(ret != 0)) 765 - DRM_ERROR("Failed to queue event on fence.\n"); 766 - else 767 - crtc->state->event = NULL; 768 755 } 769 756 770 757 if (fence) ··· 924 947 int vmw_kms_sou_init_display(struct vmw_private *dev_priv) 925 948 { 926 949 struct drm_device *dev = &dev_priv->drm; 927 - int i, ret; 950 + int i; 928 951 929 952 if (!(dev_priv->capabilities & SVGA_CAP_SCREEN_OBJECT_2)) { 930 953 return -ENOSYS; 931 954 } 932 - 933 - ret = -ENOMEM; 934 - 935 - ret = drm_vblank_init(dev, VMWGFX_NUM_DISPLAY_UNITS); 936 - if (unlikely(ret != 0)) 937 - return ret; 938 955 939 956 for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) 940 957 vmw_sou_init(dev_priv, i);
-26
drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
··· 29 29 #include <drm/drm_atomic_helper.h> 30 30 #include <drm/drm_damage_helper.h> 31 31 #include <drm/drm_fourcc.h> 32 - #include <drm/drm_vblank.h> 33 32 34 33 #include "vmwgfx_kms.h" 35 34 #include "vmw_surface_cache.h" ··· 924 925 .atomic_destroy_state = vmw_du_crtc_destroy_state, 925 926 .set_config = drm_atomic_helper_set_config, 926 927 .page_flip = drm_atomic_helper_page_flip, 927 - .get_vblank_counter = vmw_get_vblank_counter, 928 - .enable_vblank = vmw_enable_vblank, 929 - .disable_vblank = vmw_disable_vblank, 930 928 }; 931 929 932 930 ··· 1587 1591 struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state); 1588 1592 struct drm_crtc *crtc = new_state->crtc; 1589 1593 struct vmw_screen_target_display_unit *stdu; 1590 - struct drm_pending_vblank_event *event; 1591 1594 struct vmw_fence_obj *fence = NULL; 1592 1595 struct vmw_private *dev_priv; 1593 1596 int ret; ··· 1633 1638 DRM_ERROR("Failed to update STDU.\n"); 1634 1639 1635 1640 return; 1636 - } 1637 - 1638 - /* In case of error, vblank event is send in vmw_du_crtc_atomic_flush */ 1639 - event = crtc->state->event; 1640 - if (event && fence) { 1641 - struct drm_file *file_priv = event->base.file_priv; 1642 - 1643 - ret = vmw_event_fence_action_queue(file_priv, 1644 - fence, 1645 - &event->base, 1646 - &event->event.vbl.tv_sec, 1647 - &event->event.vbl.tv_usec, 1648 - true); 1649 - if (ret) 1650 - DRM_ERROR("Failed to queue event on fence.\n"); 1651 - else 1652 - crtc->state->event = NULL; 1653 1641 } 1654 1642 1655 1643 if (fence) ··· 1860 1882 1861 1883 if (!(dev_priv->capabilities & SVGA_CAP_GBOBJECTS)) 1862 1884 return -ENOSYS; 1863 - 1864 - ret = drm_vblank_init(dev, VMWGFX_NUM_DISPLAY_UNITS); 1865 - if (unlikely(ret != 0)) 1866 - return ret; 1867 1885 1868 1886 dev_priv->active_display_unit = vmw_du_screen_target; 1869 1887
+27 -28
drivers/gpu/drm/vmwgfx/vmwgfx_validation.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 OR MIT 2 2 /************************************************************************** 3 3 * 4 - * Copyright © 2018 VMware, Inc., Palo Alto, CA., USA 4 + * Copyright © 2018 - 2022 VMware, Inc., Palo Alto, CA., USA 5 5 * All Rights Reserved. 6 6 * 7 7 * Permission is hereby granted, free of charge, to any person obtaining a ··· 180 180 if (!ctx->merge_dups) 181 181 return NULL; 182 182 183 - if (ctx->ht) { 183 + if (ctx->sw_context) { 184 184 struct vmwgfx_hash_item *hash; 185 + unsigned long key = (unsigned long) vbo; 185 186 186 - if (!vmwgfx_ht_find_item(ctx->ht, (unsigned long) vbo, &hash)) 187 - bo_node = container_of(hash, typeof(*bo_node), hash); 187 + hash_for_each_possible_rcu(ctx->sw_context->res_ht, hash, head, key) { 188 + if (hash->key == key) { 189 + bo_node = container_of(hash, typeof(*bo_node), hash); 190 + break; 191 + } 192 + } 188 193 } else { 189 194 struct vmw_validation_bo_node *entry; 190 195 ··· 222 217 if (!ctx->merge_dups) 223 218 return NULL; 224 219 225 - if (ctx->ht) { 220 + if (ctx->sw_context) { 226 221 struct vmwgfx_hash_item *hash; 222 + unsigned long key = (unsigned long) res; 227 223 228 - if (!vmwgfx_ht_find_item(ctx->ht, (unsigned long) res, &hash)) 229 - res_node = container_of(hash, typeof(*res_node), hash); 224 + hash_for_each_possible_rcu(ctx->sw_context->res_ht, hash, head, key) { 225 + if (hash->key == key) { 226 + res_node = container_of(hash, typeof(*res_node), hash); 227 + break; 228 + } 229 + } 230 230 } else { 231 231 struct vmw_validation_res_node *entry; 232 232 ··· 279 269 } 280 270 } else { 281 271 struct ttm_validate_buffer *val_buf; 282 - int ret; 283 272 284 273 bo_node = vmw_validation_mem_alloc(ctx, sizeof(*bo_node)); 285 274 if (!bo_node) 286 275 return -ENOMEM; 287 276 288 - if (ctx->ht) { 277 + if (ctx->sw_context) { 289 278 bo_node->hash.key = (unsigned long) vbo; 290 - ret = vmwgfx_ht_insert_item(ctx->ht, &bo_node->hash); 291 - if (ret) { 292 - DRM_ERROR("Failed to initialize a buffer " 293 - "validation entry.\n"); 294 - return ret; 295 - } 279 + hash_add_rcu(ctx->sw_context->res_ht, &bo_node->hash.head, 280 + bo_node->hash.key); 296 281 } 297 282 val_buf = &bo_node->base; 298 283 val_buf->bo = ttm_bo_get_unless_zero(&vbo->base); ··· 321 316 bool *first_usage) 322 317 { 323 318 struct vmw_validation_res_node *node; 324 - int ret; 325 319 326 320 node = vmw_validation_find_res_dup(ctx, res); 327 321 if (node) { ··· 334 330 return -ENOMEM; 335 331 } 336 332 337 - if (ctx->ht) { 333 + if (ctx->sw_context) { 338 334 node->hash.key = (unsigned long) res; 339 - ret = vmwgfx_ht_insert_item(ctx->ht, &node->hash); 340 - if (ret) { 341 - DRM_ERROR("Failed to initialize a resource validation " 342 - "entry.\n"); 343 - return ret; 344 - } 335 + hash_add_rcu(ctx->sw_context->res_ht, &node->hash.head, node->hash.key); 345 336 } 346 337 node->res = vmw_resource_reference_unless_doomed(res); 347 338 if (!node->res) ··· 680 681 struct vmw_validation_bo_node *entry; 681 682 struct vmw_validation_res_node *val; 682 683 683 - if (!ctx->ht) 684 + if (!ctx->sw_context) 684 685 return; 685 686 686 687 list_for_each_entry(entry, &ctx->bo_list, base.head) 687 - (void) vmwgfx_ht_remove_item(ctx->ht, &entry->hash); 688 + hash_del_rcu(&entry->hash.head); 688 689 689 690 list_for_each_entry(val, &ctx->resource_list, head) 690 - (void) vmwgfx_ht_remove_item(ctx->ht, &val->hash); 691 + hash_del_rcu(&val->hash.head); 691 692 692 693 list_for_each_entry(val, &ctx->resource_ctx_list, head) 693 - (void) vmwgfx_ht_remove_item(ctx->ht, &val->hash); 694 + hash_del_rcu(&entry->hash.head); 694 695 695 - ctx->ht = NULL; 696 + ctx->sw_context = NULL; 696 697 } 697 698 698 699 /**
+6 -20
drivers/gpu/drm/vmwgfx/vmwgfx_validation.h
··· 1 1 /* SPDX-License-Identifier: GPL-2.0 OR MIT */ 2 2 /************************************************************************** 3 3 * 4 - * Copyright © 2018 VMware, Inc., Palo Alto, CA., USA 4 + * Copyright © 2018 - 2022 VMware, Inc., Palo Alto, CA., USA 5 5 * All Rights Reserved. 6 6 * 7 7 * Permission is hereby granted, free of charge, to any person obtaining a ··· 29 29 #define _VMWGFX_VALIDATION_H_ 30 30 31 31 #include <linux/list.h> 32 + #include <linux/hashtable.h> 32 33 #include <linux/ww_mutex.h> 33 34 34 35 #include <drm/ttm/ttm_execbuf_util.h> 35 - 36 - #include "vmwgfx_hashtab.h" 37 36 38 37 #define VMW_RES_DIRTY_NONE 0 39 38 #define VMW_RES_DIRTY_SET BIT(0) ··· 58 59 * @total_mem: Amount of reserved memory. 59 60 */ 60 61 struct vmw_validation_context { 61 - struct vmwgfx_open_hash *ht; 62 + struct vmw_sw_context *sw_context; 62 63 struct list_head resource_list; 63 64 struct list_head resource_ctx_list; 64 65 struct list_head bo_list; ··· 81 82 /** 82 83 * DECLARE_VAL_CONTEXT - Declare a validation context with initialization 83 84 * @_name: The name of the variable 84 - * @_ht: The hash table used to find dups or NULL if none 85 + * @_sw_context: Contains the hash table used to find dups or NULL if none 85 86 * @_merge_dups: Whether to merge duplicate buffer object- or resource 86 87 * entries. If set to true, ideally a hash table pointer should be supplied 87 88 * as well unless the number of resources and buffer objects per validation 88 89 * is known to be very small 89 90 */ 90 91 #endif 91 - #define DECLARE_VAL_CONTEXT(_name, _ht, _merge_dups) \ 92 + #define DECLARE_VAL_CONTEXT(_name, _sw_context, _merge_dups) \ 92 93 struct vmw_validation_context _name = \ 93 - { .ht = _ht, \ 94 + { .sw_context = _sw_context, \ 94 95 .resource_list = LIST_HEAD_INIT((_name).resource_list), \ 95 96 .resource_ctx_list = LIST_HEAD_INIT((_name).resource_ctx_list), \ 96 97 .bo_list = LIST_HEAD_INIT((_name).bo_list), \ ··· 111 112 vmw_validation_has_bos(struct vmw_validation_context *ctx) 112 113 { 113 114 return !list_empty(&ctx->bo_list); 114 - } 115 - 116 - /** 117 - * vmw_validation_set_ht - Register a hash table for duplicate finding 118 - * @ctx: The validation context 119 - * @ht: Pointer to a hash table to use for duplicate finding 120 - * This function is intended to be used if the hash table wasn't 121 - * available at validation context declaration time 122 - */ 123 - static inline void vmw_validation_set_ht(struct vmw_validation_context *ctx, 124 - struct vmwgfx_open_hash *ht) 125 - { 126 - ctx->ht = ht; 127 115 } 128 116 129 117 /**
+12 -4
include/drm/drm_connector.h
··· 1550 1550 struct drm_cmdline_mode cmdline_mode; 1551 1551 /** @force: a DRM_FORCE_<foo> state for forced mode sets */ 1552 1552 enum drm_connector_force force; 1553 + 1553 1554 /** 1554 - * @override_edid: has the EDID been overwritten through debugfs for 1555 - * testing? Do not modify outside of drm_edid_override_set() and 1556 - * drm_edid_override_reset(). 1555 + * @edid_override: Override EDID set via debugfs. 1556 + * 1557 + * Do not modify or access outside of the drm_edid_override_* family of 1558 + * functions. 1557 1559 */ 1558 - bool override_edid; 1560 + const struct drm_edid *edid_override; 1561 + 1562 + /** 1563 + * @edid_override_mutex: Protect access to edid_override. 1564 + */ 1565 + struct mutex edid_override_mutex; 1566 + 1559 1567 /** @epoch_counter: used to detect any other changes in connector, besides status */ 1560 1568 u64 epoch_counter; 1561 1569
+2 -8
include/drm/drm_edid.h
··· 388 388 const struct drm_display_mode *mode); 389 389 390 390 #ifdef CONFIG_DRM_LOAD_EDID_FIRMWARE 391 - struct edid *drm_load_edid_firmware(struct drm_connector *connector); 392 391 int __drm_set_edid_firmware_path(const char *path); 393 392 int __drm_get_edid_firmware_path(char *buf, size_t bufsize); 394 - #else 395 - static inline struct edid * 396 - drm_load_edid_firmware(struct drm_connector *connector) 397 - { 398 - return ERR_PTR(-ENOENT); 399 - } 400 393 #endif 401 394 402 395 bool drm_edid_are_equal(const struct edid *edid1, const struct edid *edid2); ··· 570 577 struct i2c_adapter *adapter); 571 578 struct edid *drm_edid_duplicate(const struct edid *edid); 572 579 int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid); 573 - int drm_add_override_edid_modes(struct drm_connector *connector); 580 + int drm_edid_override_connector_update(struct drm_connector *connector); 574 581 575 582 u8 drm_match_cea_mode(const struct drm_display_mode *to_match); 576 583 bool drm_detect_hdmi_monitor(const struct edid *edid); ··· 599 606 const struct drm_edid *drm_edid_alloc(const void *edid, size_t size); 600 607 const struct drm_edid *drm_edid_dup(const struct drm_edid *drm_edid); 601 608 void drm_edid_free(const struct drm_edid *drm_edid); 609 + bool drm_edid_valid(const struct drm_edid *drm_edid); 602 610 const struct edid *drm_edid_raw(const struct drm_edid *drm_edid); 603 611 const struct drm_edid *drm_edid_read(struct drm_connector *connector); 604 612 const struct drm_edid *drm_edid_read_ddc(struct drm_connector *connector,