Commit 2b1966c6 authored by Dave Airlie's avatar Dave Airlie

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: default avatarDave Airlie <airlied@redhat.com>

From: Maxime Ripard <maxime@cerno.tech>
Link: https://patchwork.freedesktop.org/patch/msgid/20221027073407.c2tlaczvzjrnzazi@houat
parents 7f7a942c e1e7bc48
...@@ -651,17 +651,6 @@ See drivers/gpu/drm/amd/display/TODO for tasks. ...@@ -651,17 +651,6 @@ See drivers/gpu/drm/amd/display/TODO for tasks.
Contact: Harry Wentland, Alex Deucher Contact: Harry Wentland, Alex Deucher
vmwgfx: Replace hashtable with Linux' implementation
----------------------------------------------------
The vmwgfx driver uses its own hashtable implementation. Replace the
code with Linux' implementation and update the callers. It's mostly a
refactoring task, but the interfaces are different.
Contact: Zack Rusin, Thomas Zimmermann <tzimmermann@suse.de>
Level: Intermediate
Bootsplash Bootsplash
========== ==========
......
...@@ -6108,7 +6108,6 @@ static void create_eml_sink(struct amdgpu_dm_connector *aconnector) ...@@ -6108,7 +6108,6 @@ static void create_eml_sink(struct amdgpu_dm_connector *aconnector)
aconnector->base.name); aconnector->base.name);
aconnector->base.force = DRM_FORCE_OFF; aconnector->base.force = DRM_FORCE_OFF;
aconnector->base.override_edid = false;
return; return;
} }
...@@ -6143,8 +6142,6 @@ static void handle_edid_mgmt(struct amdgpu_dm_connector *aconnector) ...@@ -6143,8 +6142,6 @@ static void handle_edid_mgmt(struct amdgpu_dm_connector *aconnector)
link->verified_link_cap.link_rate = LINK_RATE_HIGH2; link->verified_link_cap.link_rate = LINK_RATE_HIGH2;
} }
aconnector->base.override_edid = true;
create_eml_sink(aconnector); create_eml_sink(aconnector);
} }
......
...@@ -412,6 +412,7 @@ struct it6505 { ...@@ -412,6 +412,7 @@ struct it6505 {
* Mutex protects extcon and interrupt functions from interfering * Mutex protects extcon and interrupt functions from interfering
* each other. * each other.
*/ */
struct mutex irq_lock;
struct mutex extcon_lock; struct mutex extcon_lock;
struct mutex mode_lock; /* used to bridge_detect */ struct mutex mode_lock; /* used to bridge_detect */
struct mutex aux_lock; /* used to aux data transfers */ struct mutex aux_lock; /* used to aux data transfers */
...@@ -440,7 +441,7 @@ struct it6505 { ...@@ -440,7 +441,7 @@ struct it6505 {
enum hdcp_state hdcp_status; enum hdcp_state hdcp_status;
struct delayed_work hdcp_work; struct delayed_work hdcp_work;
struct work_struct hdcp_wait_ksv_list; struct work_struct hdcp_wait_ksv_list;
struct completion wait_edid_complete; struct completion extcon_completion;
u8 auto_train_retry; u8 auto_train_retry;
bool hdcp_desired; bool hdcp_desired;
bool is_repeater; bool is_repeater;
...@@ -725,28 +726,6 @@ static void it6505_calc_video_info(struct it6505 *it6505) ...@@ -725,28 +726,6 @@ static void it6505_calc_video_info(struct it6505 *it6505)
DRM_MODE_ARG(&it6505->video_info)); DRM_MODE_ARG(&it6505->video_info));
} }
static int it6505_drm_dp_link_probe(struct drm_dp_aux *aux,
struct it6505_drm_dp_link *link)
{
u8 values[3];
int err;
memset(link, 0, sizeof(*link));
err = drm_dp_dpcd_read(aux, DP_DPCD_REV, values, sizeof(values));
if (err < 0)
return err;
link->revision = values[0];
link->rate = drm_dp_bw_code_to_link_rate(values[1]);
link->num_lanes = values[2] & DP_MAX_LANE_COUNT_MASK;
if (values[2] & DP_ENHANCED_FRAME_CAP)
link->capabilities = DP_ENHANCED_FRAME_CAP;
return 0;
}
static int it6505_drm_dp_link_set_power(struct drm_dp_aux *aux, static int it6505_drm_dp_link_set_power(struct drm_dp_aux *aux,
struct it6505_drm_dp_link *link, struct it6505_drm_dp_link *link,
u8 mode) u8 mode)
...@@ -1456,11 +1435,19 @@ static void it6505_parse_link_capabilities(struct it6505 *it6505) ...@@ -1456,11 +1435,19 @@ static void it6505_parse_link_capabilities(struct it6505 *it6505)
int bcaps; int bcaps;
if (it6505->dpcd[0] == 0) { if (it6505->dpcd[0] == 0) {
it6505_aux_on(it6505); dev_err(dev, "DPCD is not initialized");
it6505_get_dpcd(it6505, DP_DPCD_REV, it6505->dpcd, return;
ARRAY_SIZE(it6505->dpcd));
} }
memset(link, 0, sizeof(*link));
link->revision = it6505->dpcd[0];
link->rate = drm_dp_bw_code_to_link_rate(it6505->dpcd[1]);
link->num_lanes = it6505->dpcd[2] & DP_MAX_LANE_COUNT_MASK;
if (it6505->dpcd[2] & DP_ENHANCED_FRAME_CAP)
link->capabilities = DP_ENHANCED_FRAME_CAP;
DRM_DEV_DEBUG_DRIVER(dev, "DPCD Rev.: %d.%d", DRM_DEV_DEBUG_DRIVER(dev, "DPCD Rev.: %d.%d",
link->revision >> 4, link->revision & 0x0F); link->revision >> 4, link->revision & 0x0F);
...@@ -2323,19 +2310,32 @@ static int it6505_process_hpd_irq(struct it6505 *it6505) ...@@ -2323,19 +2310,32 @@ static int it6505_process_hpd_irq(struct it6505 *it6505)
static void it6505_irq_hpd(struct it6505 *it6505) static void it6505_irq_hpd(struct it6505 *it6505)
{ {
struct device *dev = &it6505->client->dev; struct device *dev = &it6505->client->dev;
int dp_sink_count;
it6505->hpd_state = it6505_get_sink_hpd_status(it6505); it6505->hpd_state = it6505_get_sink_hpd_status(it6505);
DRM_DEV_DEBUG_DRIVER(dev, "hpd change interrupt, change to %s", DRM_DEV_DEBUG_DRIVER(dev, "hpd change interrupt, change to %s",
it6505->hpd_state ? "high" : "low"); it6505->hpd_state ? "high" : "low");
if (it6505->bridge.dev)
drm_helper_hpd_irq_event(it6505->bridge.dev);
DRM_DEV_DEBUG_DRIVER(dev, "it6505->sink_count: %d",
it6505->sink_count);
if (it6505->hpd_state) { if (it6505->hpd_state) {
wait_for_completion_timeout(&it6505->wait_edid_complete, wait_for_completion_timeout(&it6505->extcon_completion,
msecs_to_jiffies(6000)); msecs_to_jiffies(1000));
it6505_aux_on(it6505);
if (it6505->dpcd[0] == 0) {
it6505_get_dpcd(it6505, DP_DPCD_REV, it6505->dpcd,
ARRAY_SIZE(it6505->dpcd));
it6505_variable_config(it6505);
it6505_parse_link_capabilities(it6505);
}
it6505->auto_train_retry = AUTO_TRAIN_RETRY;
it6505_drm_dp_link_set_power(&it6505->aux, &it6505->link,
DP_SET_POWER_D0);
dp_sink_count = it6505_dpcd_read(it6505, DP_SINK_COUNT);
it6505->sink_count = DP_GET_SINK_COUNT(dp_sink_count);
DRM_DEV_DEBUG_DRIVER(dev, "it6505->sink_count: %d",
it6505->sink_count);
it6505_lane_termination_on(it6505); it6505_lane_termination_on(it6505);
it6505_lane_power_on(it6505); it6505_lane_power_on(it6505);
...@@ -2363,6 +2363,9 @@ static void it6505_irq_hpd(struct it6505 *it6505) ...@@ -2363,6 +2363,9 @@ static void it6505_irq_hpd(struct it6505 *it6505)
it6505_lane_off(it6505); it6505_lane_off(it6505);
it6505_link_reset_step_train(it6505); it6505_link_reset_step_train(it6505);
} }
if (it6505->bridge.dev)
drm_helper_hpd_irq_event(it6505->bridge.dev);
} }
static void it6505_irq_hpd_irq(struct it6505 *it6505) static void it6505_irq_hpd_irq(struct it6505 *it6505)
...@@ -2491,8 +2494,7 @@ static irqreturn_t it6505_int_threaded_handler(int unused, void *data) ...@@ -2491,8 +2494,7 @@ static irqreturn_t it6505_int_threaded_handler(int unused, void *data)
}; };
int int_status[3], i; int int_status[3], i;
msleep(100); mutex_lock(&it6505->irq_lock);
mutex_lock(&it6505->extcon_lock);
if (it6505->enable_drv_hold || !it6505->powered) if (it6505->enable_drv_hold || !it6505->powered)
goto unlock; goto unlock;
...@@ -2522,7 +2524,7 @@ static irqreturn_t it6505_int_threaded_handler(int unused, void *data) ...@@ -2522,7 +2524,7 @@ static irqreturn_t it6505_int_threaded_handler(int unused, void *data)
} }
unlock: unlock:
mutex_unlock(&it6505->extcon_lock); mutex_unlock(&it6505->irq_lock);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -2625,26 +2627,14 @@ static enum drm_connector_status it6505_detect(struct it6505 *it6505) ...@@ -2625,26 +2627,14 @@ static enum drm_connector_status it6505_detect(struct it6505 *it6505)
goto unlock; goto unlock;
if (it6505->enable_drv_hold) { if (it6505->enable_drv_hold) {
status = it6505_get_sink_hpd_status(it6505) ? status = it6505->hpd_state ? connector_status_connected :
connector_status_connected : connector_status_disconnected;
connector_status_disconnected;
goto unlock; goto unlock;
} }
if (it6505_get_sink_hpd_status(it6505)) { if (it6505->hpd_state) {
it6505_aux_on(it6505);
it6505_drm_dp_link_probe(&it6505->aux, &it6505->link);
it6505_drm_dp_link_set_power(&it6505->aux, &it6505->link, it6505_drm_dp_link_set_power(&it6505->aux, &it6505->link,
DP_SET_POWER_D0); DP_SET_POWER_D0);
it6505->auto_train_retry = AUTO_TRAIN_RETRY;
if (it6505->dpcd[0] == 0) {
it6505_get_dpcd(it6505, DP_DPCD_REV, it6505->dpcd,
ARRAY_SIZE(it6505->dpcd));
it6505_variable_config(it6505);
it6505_parse_link_capabilities(it6505);
}
dp_sink_count = it6505_dpcd_read(it6505, DP_SINK_COUNT); dp_sink_count = it6505_dpcd_read(it6505, DP_SINK_COUNT);
it6505->sink_count = DP_GET_SINK_COUNT(dp_sink_count); it6505->sink_count = DP_GET_SINK_COUNT(dp_sink_count);
DRM_DEV_DEBUG_DRIVER(dev, "it6505->sink_count:%d branch:%d", DRM_DEV_DEBUG_DRIVER(dev, "it6505->sink_count:%d branch:%d",
...@@ -2711,9 +2701,12 @@ static void it6505_extcon_work(struct work_struct *work) ...@@ -2711,9 +2701,12 @@ static void it6505_extcon_work(struct work_struct *work)
*/ */
if (ret) if (ret)
it6505_poweron(it6505); it6505_poweron(it6505);
complete_all(&it6505->extcon_completion);
} else { } else {
DRM_DEV_DEBUG_DRIVER(dev, "start to power off"); DRM_DEV_DEBUG_DRIVER(dev, "start to power off");
pm_runtime_put_sync(dev); pm_runtime_put_sync(dev);
reinit_completion(&it6505->extcon_completion);
drm_helper_hpd_irq_event(it6505->bridge.dev); drm_helper_hpd_irq_event(it6505->bridge.dev);
memset(it6505->dpcd, 0, sizeof(it6505->dpcd)); memset(it6505->dpcd, 0, sizeof(it6505->dpcd));
...@@ -2871,10 +2864,7 @@ static int it6505_bridge_attach(struct drm_bridge *bridge, ...@@ -2871,10 +2864,7 @@ static int it6505_bridge_attach(struct drm_bridge *bridge,
} }
/* Register aux channel */ /* Register aux channel */
it6505->aux.name = "DP-AUX";
it6505->aux.dev = dev;
it6505->aux.drm_dev = bridge->dev; it6505->aux.drm_dev = bridge->dev;
it6505->aux.transfer = it6505_aux_transfer;
ret = drm_dp_aux_register(&it6505->aux); ret = drm_dp_aux_register(&it6505->aux);
...@@ -3287,6 +3277,7 @@ static int it6505_i2c_probe(struct i2c_client *client, ...@@ -3287,6 +3277,7 @@ static int it6505_i2c_probe(struct i2c_client *client,
if (!it6505) if (!it6505)
return -ENOMEM; return -ENOMEM;
mutex_init(&it6505->irq_lock);
mutex_init(&it6505->extcon_lock); mutex_init(&it6505->extcon_lock);
mutex_init(&it6505->mode_lock); mutex_init(&it6505->mode_lock);
mutex_init(&it6505->aux_lock); mutex_init(&it6505->aux_lock);
...@@ -3342,7 +3333,7 @@ static int it6505_i2c_probe(struct i2c_client *client, ...@@ -3342,7 +3333,7 @@ static int it6505_i2c_probe(struct i2c_client *client,
INIT_WORK(&it6505->link_works, it6505_link_training_work); INIT_WORK(&it6505->link_works, it6505_link_training_work);
INIT_WORK(&it6505->hdcp_wait_ksv_list, it6505_hdcp_wait_ksv_list); INIT_WORK(&it6505->hdcp_wait_ksv_list, it6505_hdcp_wait_ksv_list);
INIT_DELAYED_WORK(&it6505->hdcp_work, it6505_hdcp_work); INIT_DELAYED_WORK(&it6505->hdcp_work, it6505_hdcp_work);
init_completion(&it6505->wait_edid_complete); init_completion(&it6505->extcon_completion);
memset(it6505->dpcd, 0, sizeof(it6505->dpcd)); memset(it6505->dpcd, 0, sizeof(it6505->dpcd));
it6505->powered = false; it6505->powered = false;
it6505->enable_drv_hold = DEFAULT_DRV_HOLD; it6505->enable_drv_hold = DEFAULT_DRV_HOLD;
...@@ -3354,6 +3345,11 @@ static int it6505_i2c_probe(struct i2c_client *client, ...@@ -3354,6 +3345,11 @@ static int it6505_i2c_probe(struct i2c_client *client,
debugfs_init(it6505); debugfs_init(it6505);
pm_runtime_enable(dev); pm_runtime_enable(dev);
it6505->aux.name = "DP-AUX";
it6505->aux.dev = dev;
it6505->aux.transfer = it6505_aux_transfer;
drm_dp_aux_init(&it6505->aux);
it6505->bridge.funcs = &it6505_bridge_funcs; it6505->bridge.funcs = &it6505_bridge_funcs;
it6505->bridge.type = DRM_MODE_CONNECTOR_DisplayPort; it6505->bridge.type = DRM_MODE_CONNECTOR_DisplayPort;
it6505->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID | it6505->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID |
......
...@@ -235,7 +235,7 @@ static void drm_client_buffer_delete(struct drm_client_buffer *buffer) ...@@ -235,7 +235,7 @@ static void drm_client_buffer_delete(struct drm_client_buffer *buffer)
{ {
struct drm_device *dev = buffer->client->dev; struct drm_device *dev = buffer->client->dev;
drm_gem_vunmap(buffer->gem, &buffer->map); drm_gem_vunmap_unlocked(buffer->gem, &buffer->map);
if (buffer->gem) if (buffer->gem)
drm_gem_object_put(buffer->gem); drm_gem_object_put(buffer->gem);
......
...@@ -274,6 +274,7 @@ static int __drm_connector_init(struct drm_device *dev, ...@@ -274,6 +274,7 @@ static int __drm_connector_init(struct drm_device *dev,
INIT_LIST_HEAD(&connector->probed_modes); INIT_LIST_HEAD(&connector->probed_modes);
INIT_LIST_HEAD(&connector->modes); INIT_LIST_HEAD(&connector->modes);
mutex_init(&connector->mutex); mutex_init(&connector->mutex);
mutex_init(&connector->edid_override_mutex);
connector->edid_blob_ptr = NULL; connector->edid_blob_ptr = NULL;
connector->epoch_counter = 0; connector->epoch_counter = 0;
connector->tile_blob_ptr = NULL; connector->tile_blob_ptr = NULL;
...@@ -582,6 +583,9 @@ void drm_connector_cleanup(struct drm_connector *connector) ...@@ -582,6 +583,9 @@ void drm_connector_cleanup(struct drm_connector *connector)
mutex_destroy(&connector->mutex); mutex_destroy(&connector->mutex);
memset(connector, 0, sizeof(*connector)); memset(connector, 0, sizeof(*connector));
if (dev->registered)
drm_sysfs_hotplug_event(dev);
} }
EXPORT_SYMBOL(drm_connector_cleanup); EXPORT_SYMBOL(drm_connector_cleanup);
......
...@@ -56,9 +56,10 @@ struct drm_plane; ...@@ -56,9 +56,10 @@ struct drm_plane;
struct drm_plane_state; struct drm_plane_state;
struct drm_property; struct drm_property;
struct edid; struct edid;
struct fwnode_handle;
struct kref; struct kref;
struct seq_file;
struct work_struct; struct work_struct;
struct fwnode_handle;
/* drm_crtc.c */ /* drm_crtc.c */
int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj, int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj,
...@@ -286,5 +287,17 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, ...@@ -286,5 +287,17 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
/* drm_edid.c */ /* drm_edid.c */
void drm_mode_fixup_1366x768(struct drm_display_mode *mode); void drm_mode_fixup_1366x768(struct drm_display_mode *mode);
int drm_edid_override_show(struct drm_connector *connector, struct seq_file *m);
int drm_edid_override_set(struct drm_connector *connector, const void *edid, size_t size); int drm_edid_override_set(struct drm_connector *connector, const void *edid, size_t size);
int drm_edid_override_reset(struct drm_connector *connector); int drm_edid_override_reset(struct drm_connector *connector);
/* drm_edid_load.c */
#ifdef CONFIG_DRM_LOAD_EDID_FIRMWARE
const struct drm_edid *drm_edid_load_firmware(struct drm_connector *connector);
#else
static inline const struct drm_edid *
drm_edid_load_firmware(struct drm_connector *connector)
{
return ERR_PTR(-ENOENT);
}
#endif
...@@ -328,13 +328,7 @@ static ssize_t connector_write(struct file *file, const char __user *ubuf, ...@@ -328,13 +328,7 @@ static ssize_t connector_write(struct file *file, const char __user *ubuf,
static int edid_show(struct seq_file *m, void *data) static int edid_show(struct seq_file *m, void *data)
{ {
struct drm_connector *connector = m->private; return drm_edid_override_show(m->private, m);
struct drm_property_blob *edid = connector->edid_blob_ptr;
if (connector->override_edid && edid)
seq_write(m, edid->data, edid->length);
return 0;
} }
static int edid_open(struct inode *inode, struct file *file) static int edid_open(struct inode *inode, struct file *file)
......
This diff is collapsed.
...@@ -11,12 +11,13 @@ ...@@ -11,12 +11,13 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <drm/drm_crtc.h> #include <drm/drm_connector.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_drv.h> #include <drm/drm_drv.h>
#include <drm/drm_edid.h> #include <drm/drm_edid.h>
#include <drm/drm_print.h> #include <drm/drm_print.h>
#include "drm_crtc_internal.h"
static char edid_firmware[PATH_MAX]; static char edid_firmware[PATH_MAX];
module_param_string(edid_firmware, edid_firmware, sizeof(edid_firmware), 0644); module_param_string(edid_firmware, edid_firmware, sizeof(edid_firmware), 0644);
MODULE_PARM_DESC(edid_firmware, "Do not probe monitor, use specified EDID blob " MODULE_PARM_DESC(edid_firmware, "Do not probe monitor, use specified EDID blob "
...@@ -159,23 +160,12 @@ static const u8 generic_edid[GENERIC_EDIDS][128] = { ...@@ -159,23 +160,12 @@ static const u8 generic_edid[GENERIC_EDIDS][128] = {
}, },
}; };
static int edid_size(const u8 *edid, int data_size) static const struct drm_edid *edid_load(struct drm_connector *connector, const char *name)
{
if (data_size < EDID_LENGTH)
return 0;
return (edid[0x7e] + 1) * EDID_LENGTH;
}
static void *edid_load(struct drm_connector *connector, const char *name,
const char *connector_name)
{ {
const struct firmware *fw = NULL; const struct firmware *fw = NULL;
const u8 *fwdata; const u8 *fwdata;
u8 *edid; const struct drm_edid *drm_edid;
int fwsize, builtin; int fwsize, builtin;
int i, valid_extensions = 0;
bool print_bad_edid = !connector->bad_edid_counter || drm_debug_enabled(DRM_UT_KMS);
builtin = match_string(generic_edid_name, GENERIC_EDIDS, name); builtin = match_string(generic_edid_name, GENERIC_EDIDS, name);
if (builtin >= 0) { if (builtin >= 0) {
...@@ -185,18 +175,22 @@ static void *edid_load(struct drm_connector *connector, const char *name, ...@@ -185,18 +175,22 @@ static void *edid_load(struct drm_connector *connector, const char *name,
struct platform_device *pdev; struct platform_device *pdev;
int err; int err;
pdev = platform_device_register_simple(connector_name, -1, NULL, 0); pdev = platform_device_register_simple(connector->name, -1, NULL, 0);
if (IS_ERR(pdev)) { if (IS_ERR(pdev)) {
DRM_ERROR("Failed to register EDID firmware platform device " drm_err(connector->dev,
"for connector \"%s\"\n", connector_name); "[CONNECTOR:%d:%s] Failed to register EDID firmware platform device for connector \"%s\"\n",
connector->base.id, connector->name,
connector->name);
return ERR_CAST(pdev); return ERR_CAST(pdev);
} }
err = request_firmware(&fw, name, &pdev->dev); err = request_firmware(&fw, name, &pdev->dev);
platform_device_unregister(pdev); platform_device_unregister(pdev);
if (err) { if (err) {
DRM_ERROR("Requesting EDID firmware \"%s\" failed (err=%d)\n", drm_err(connector->dev,
name, err); "[CONNECTOR:%d:%s] Requesting EDID firmware \"%s\" failed (err=%d)\n",
connector->base.id, connector->name,
name, err);
return ERR_PTR(err); return ERR_PTR(err);
} }
...@@ -204,70 +198,26 @@ static void *edid_load(struct drm_connector *connector, const char *name, ...@@ -204,70 +198,26 @@ static void *edid_load(struct drm_connector *connector, const char *name,
fwsize = fw->size; fwsize = fw->size;
} }
if (edid_size(fwdata, fwsize) != fwsize) { drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] Loaded %s firmware EDID \"%s\"\n",
DRM_ERROR("Size of EDID firmware \"%s\" is invalid " connector->base.id, connector->name,
"(expected %d, got %d\n", name, builtin >= 0 ? "built-in" : "external", name);
edid_size(fwdata, fwsize), (int)fwsize);
edid = ERR_PTR(-EINVAL);
goto out;
}
edid = kmemdup(fwdata, fwsize, GFP_KERNEL);
if (edid == NULL) {
edid = ERR_PTR(-ENOMEM);
goto out;
}
if (!drm_edid_block_valid(edid, 0, print_bad_edid, drm_edid = drm_edid_alloc(fwdata, fwsize);
&connector->edid_corrupt)) { if (!drm_edid_valid(drm_edid)) {
connector->bad_edid_counter++; drm_err(connector->dev, "Invalid firmware EDID \"%s\"\n", name);
DRM_ERROR("Base block of EDID firmware \"%s\" is invalid ", drm_edid_free(drm_edid);
name); drm_edid = ERR_PTR(-EINVAL);
kfree(edid);
edid = ERR_PTR(-EINVAL);
goto out;
} }
for (i = 1; i <= edid[0x7e]; i++) {
if (i != valid_extensions + 1)
memcpy(edid + (valid_extensions + 1) * EDID_LENGTH,
edid + i * EDID_LENGTH, EDID_LENGTH);
if (drm_edid_block_valid(edid + i * EDID_LENGTH, i,
print_bad_edid,
NULL))
valid_extensions++;
}
if (valid_extensions != edid[0x7e]) {
u8 *new_edid;
edid[EDID_LENGTH-1] += edid[0x7e] - valid_extensions;
DRM_INFO("Found %d valid extensions instead of %d in EDID data "
"\"%s\" for connector \"%s\"\n", valid_extensions,
edid[0x7e], name, connector_name);
edid[0x7e] = valid_extensions;
new_edid = krealloc(edid, (valid_extensions + 1) * EDID_LENGTH,
GFP_KERNEL);
if (new_edid)
edid = new_edid;
}
DRM_INFO("Got %s EDID base block and %d extension%s from "
"\"%s\" for connector \"%s\"\n", (builtin >= 0) ? "built-in" :
"external", valid_extensions, valid_extensions == 1 ? "" : "s",
name, connector_name);
out:
release_firmware(fw); release_firmware(fw);
return edid;
return drm_edid;
} }
struct edid *drm_load_edid_firmware(struct drm_connector *connector) const struct drm_edid *drm_edid_load_firmware(struct drm_connector *connector)
{ {
const char *connector_name = connector->name;
char *edidname, *last, *colon, *fwstr, *edidstr, *fallback = NULL; char *edidname, *last, *colon, *fwstr, *edidstr, *fallback = NULL;
struct edid *edid; const struct drm_edid *drm_edid;
if (edid_firmware[0] == '\0') if (edid_firmware[0] == '\0')
return ERR_PTR(-ENOENT); return ERR_PTR(-ENOENT);
...@@ -288,7 +238,7 @@ struct edid *drm_load_edid_firmware(struct drm_connector *connector) ...@@ -288,7 +238,7 @@ struct edid *drm_load_edid_firmware(struct drm_connector *connector)
while ((edidname = strsep(&edidstr, ","))) { while ((edidname = strsep(&edidstr, ","))) {
colon = strchr(edidname, ':'); colon = strchr(edidname, ':');
if (colon != NULL) { if (colon != NULL) {
if (strncmp(connector_name, edidname, colon - edidname)) if (strncmp(connector->name, edidname, colon - edidname))
continue; continue;
edidname = colon + 1; edidname = colon + 1;
break; break;
...@@ -310,8 +260,9 @@ struct edid *drm_load_edid_firmware(struct drm_connector *connector) ...@@ -310,8 +260,9 @@ struct edid *drm_load_edid_firmware(struct drm_connector *connector)
if (*last == '\n') if (*last == '\n')
*last = '\0'; *last = '\0';
edid = edid_load(connector, edidname, connector_name); drm_edid = edid_load(connector, edidname);
kfree(fwstr); kfree(fwstr);
return edid; return drm_edid;
} }
...@@ -606,7 +606,7 @@ int mipi_dsi_turn_on_peripheral(struct mipi_dsi_device *dsi) ...@@ -606,7 +606,7 @@ int mipi_dsi_turn_on_peripheral(struct mipi_dsi_device *dsi)
EXPORT_SYMBOL(mipi_dsi_turn_on_peripheral); EXPORT_SYMBOL(mipi_dsi_turn_on_peripheral);
/* /*
* mipi_dsi_set_maximum_return_packet_size() - specify the maximum size of the * mipi_dsi_set_maximum_return_packet_size() - specify the maximum size of
* the payload in a long packet transmitted from the peripheral back to the * the payload in a long packet transmitted from the peripheral back to the
* host processor * host processor
* @dsi: DSI peripheral device * @dsi: DSI peripheral device
......
...@@ -151,9 +151,6 @@ int drm_mode_getresources(struct drm_device *dev, void *data, ...@@ -151,9 +151,6 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
count = 0; count = 0;
connector_id = u64_to_user_ptr(card_res->connector_id_ptr); connector_id = u64_to_user_ptr(card_res->connector_id_ptr);
drm_for_each_connector_iter(connector, &conn_iter) { drm_for_each_connector_iter(connector, &conn_iter) {
if (connector->registration_state != DRM_CONNECTOR_REGISTERED)
continue;
/* only expose writeback connectors if userspace understands them */ /* only expose writeback connectors if userspace understands them */
if (!file_priv->writeback_connectors && if (!file_priv->writeback_connectors &&
(connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)) (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK))
......
...@@ -367,7 +367,7 @@ static int drm_helper_probe_get_modes(struct drm_connector *connector) ...@@ -367,7 +367,7 @@ static int drm_helper_probe_get_modes(struct drm_connector *connector)
* override/firmware EDID. * override/firmware EDID.
*/ */
if (count == 0 && connector->status == connector_status_connected) if (count == 0 && connector->status == connector_status_connected)
count = drm_add_override_edid_modes(connector); count = drm_edid_override_connector_update(connector);
return count; return count;
} }
......
...@@ -80,7 +80,7 @@ static u32 clip_scaled(int src, int dst, int *clip) ...@@ -80,7 +80,7 @@ static u32 clip_scaled(int src, int dst, int *clip)
* @dst: destination window rectangle * @dst: destination window rectangle
* @clip: clip rectangle * @clip: clip rectangle
* *
* Clip rectangle @dst by rectangle @clip. Clip rectangle @src by the * Clip rectangle @dst by rectangle @clip. Clip rectangle @src by
* the corresponding amounts, retaining the vertical and horizontal scaling * the corresponding amounts, retaining the vertical and horizontal scaling
* factors from @src to @dst. * factors from @src to @dst.
* *
......
...@@ -2355,7 +2355,7 @@ intel_hdmi_unset_edid(struct drm_connector *connector) ...@@ -2355,7 +2355,7 @@ intel_hdmi_unset_edid(struct drm_connector *connector)
} }
static void static void
intel_hdmi_dp_dual_mode_detect(struct drm_connector *connector, bool has_edid) intel_hdmi_dp_dual_mode_detect(struct drm_connector *connector)
{ {
struct drm_i915_private *dev_priv = to_i915(connector->dev); struct drm_i915_private *dev_priv = to_i915(connector->dev);
struct intel_hdmi *hdmi = intel_attached_hdmi(to_intel_connector(connector)); struct intel_hdmi *hdmi = intel_attached_hdmi(to_intel_connector(connector));
...@@ -2371,16 +2371,10 @@ intel_hdmi_dp_dual_mode_detect(struct drm_connector *connector, bool has_edid) ...@@ -2371,16 +2371,10 @@ intel_hdmi_dp_dual_mode_detect(struct drm_connector *connector, bool has_edid)
* CONFIG1 pin, but no such luck on our hardware. * CONFIG1 pin, but no such luck on our hardware.
* *
* The only method left to us is to check the VBT to see * The only method left to us is to check the VBT to see
* if the port is a dual mode capable DP port. But let's * if the port is a dual mode capable DP port.
* only do that when we sucesfully read the EDID, to avoid
* confusing log messages about DP dual mode adaptors when
* there's nothing connected to the port.
*/ */
if (type == DRM_DP_DUAL_MODE_UNKNOWN) { if (type == DRM_DP_DUAL_MODE_UNKNOWN) {
/* An overridden EDID imply that we want this port for testing. if (!connector->force &&
* Make sure not to set limits for that port.
*/
if (has_edid && !connector->override_edid &&
intel_bios_is_port_dp_dual_mode(dev_priv, port)) { intel_bios_is_port_dp_dual_mode(dev_priv, port)) {
drm_dbg_kms(&dev_priv->drm, drm_dbg_kms(&dev_priv->drm,
"Assuming DP dual mode adaptor presence based on VBT\n"); "Assuming DP dual mode adaptor presence based on VBT\n");
...@@ -2435,18 +2429,18 @@ intel_hdmi_set_edid(struct drm_connector *connector) ...@@ -2435,18 +2429,18 @@ intel_hdmi_set_edid(struct drm_connector *connector)
intel_gmbus_force_bit(i2c, false); intel_gmbus_force_bit(i2c, false);
} }
intel_hdmi_dp_dual_mode_detect(connector, edid != NULL);
intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS, wakeref);
to_intel_connector(connector)->detect_edid = edid; to_intel_connector(connector)->detect_edid = edid;
if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) { if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
intel_hdmi->has_audio = drm_detect_monitor_audio(edid); intel_hdmi->has_audio = drm_detect_monitor_audio(edid);
intel_hdmi->has_hdmi_sink = drm_detect_hdmi_monitor(edid); intel_hdmi->has_hdmi_sink = drm_detect_hdmi_monitor(edid);
intel_hdmi_dp_dual_mode_detect(connector);
connected = true; connected = true;
} }
intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS, wakeref);
cec_notifier_set_phys_addr_from_edid(intel_hdmi->cec_notifier, edid); cec_notifier_set_phys_addr_from_edid(intel_hdmi->cec_notifier, edid);
return connected; return connected;
......
...@@ -33,7 +33,6 @@ ...@@ -33,7 +33,6 @@
#include <nvif/if000c.h> #include <nvif/if000c.h>
#include <nvif/if500b.h> #include <nvif/if500b.h>
#include <nvif/if900b.h> #include <nvif/if900b.h>
#include <nvif/if000c.h>
#include <nvhw/class/cla0b5.h> #include <nvhw/class/cla0b5.h>
......
...@@ -1883,8 +1883,10 @@ static const struct edp_panel_entry edp_panels[] = { ...@@ -1883,8 +1883,10 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a5d, &delay_200_500_e50, "NV116WHM-N45"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a5d, &delay_200_500_e50, "NV116WHM-N45"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0ac5, &delay_200_500_e50, "NV116WHM-N4C"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0ac5, &delay_200_500_e50, "NV116WHM-N4C"),
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1139, &delay_200_500_e80_d50, "N116BGE-EA2"),
EDP_PANEL_ENTRY('C', 'M', 'N', 0x114c, &innolux_n116bca_ea1.delay, "N116BCA-EA1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x114c, &innolux_n116bca_ea1.delay, "N116BCA-EA1"),
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1152, &delay_200_500_e80_d50, "N116BCN-EA1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1152, &delay_200_500_e80_d50, "N116BCN-EA1"),
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1153, &delay_200_500_e80_d50, "N116BGE-EA2"),
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1154, &delay_200_500_e80_d50, "N116BCA-EA2"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1154, &delay_200_500_e80_d50, "N116BCA-EA2"),
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1247, &delay_200_500_e80_d50, "N120ACA-EA1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1247, &delay_200_500_e80_d50, "N120ACA-EA1"),
......
...@@ -62,13 +62,13 @@ ...@@ -62,13 +62,13 @@
#define to_drm_sched_job(sched_job) \ #define to_drm_sched_job(sched_job) \
container_of((sched_job), struct drm_sched_job, queue_node) container_of((sched_job), struct drm_sched_job, queue_node)
int drm_sched_policy = DRM_SCHED_POLICY_RR; int drm_sched_policy = DRM_SCHED_POLICY_FIFO;
/** /**
* DOC: sched_policy (int) * DOC: sched_policy (int)
* Used to override default entities scheduling policy in a run queue. * Used to override default entities scheduling policy in a run queue.
*/ */
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."); 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).");
module_param_named(sched_policy, drm_sched_policy, int, 0444); module_param_named(sched_policy, drm_sched_policy, int, 0444);
static __always_inline bool drm_sched_entity_compare_before(struct rb_node *a, static __always_inline bool drm_sched_entity_compare_before(struct rb_node *a,
......
...@@ -736,12 +736,12 @@ static int vc4_gem_object_mmap(struct drm_gem_object *obj, struct vm_area_struct ...@@ -736,12 +736,12 @@ static int vc4_gem_object_mmap(struct drm_gem_object *obj, struct vm_area_struct
struct vc4_bo *bo = to_vc4_bo(obj); struct vc4_bo *bo = to_vc4_bo(obj);
if (bo->validated_shader && (vma->vm_flags & VM_WRITE)) { if (bo->validated_shader && (vma->vm_flags & VM_WRITE)) {
DRM_DEBUG("mmaping of shader BOs for writing not allowed.\n"); DRM_DEBUG("mmapping of shader BOs for writing not allowed.\n");
return -EINVAL; return -EINVAL;
} }
if (bo->madv != VC4_MADV_WILLNEED) { if (bo->madv != VC4_MADV_WILLNEED) {
DRM_DEBUG("mmaping of %s BO not allowed\n", DRM_DEBUG("mmapping of %s BO not allowed\n",
bo->madv == VC4_MADV_DONTNEED ? bo->madv == VC4_MADV_DONTNEED ?
"purgeable" : "purged"); "purgeable" : "purged");
return -EINVAL; return -EINVAL;
......
...@@ -16,13 +16,6 @@ config DRM_VMWGFX ...@@ -16,13 +16,6 @@ config DRM_VMWGFX
virtual hardware. virtual hardware.
The compiled module will be called "vmwgfx.ko". The compiled module will be called "vmwgfx.ko".
config DRM_VMWGFX_FBCON
depends on DRM_VMWGFX && DRM_FBDEV_EMULATION
bool "Enable framebuffer console under vmwgfx by default"
help
Choose this option if you are shipping a new vmwgfx
userspace driver that supports using the kernel driver.
config DRM_VMWGFX_MKSSTATS config DRM_VMWGFX_MKSSTATS
bool "Enable mksGuestStats instrumentation of vmwgfx by default" bool "Enable mksGuestStats instrumentation of vmwgfx by default"
depends on DRM_VMWGFX depends on DRM_VMWGFX
......
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_hashtab.o vmwgfx_kms.o vmwgfx_drv.o \ vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_kms.o vmwgfx_drv.o \
vmwgfx_ioctl.o vmwgfx_resource.o vmwgfx_ttm_buffer.o \ vmwgfx_ioctl.o vmwgfx_resource.o vmwgfx_ttm_buffer.o \
vmwgfx_cmd.o vmwgfx_irq.o vmwgfx_ldu.o vmwgfx_ttm_glue.o \ vmwgfx_cmd.o vmwgfx_irq.o vmwgfx_ldu.o vmwgfx_ttm_glue.o \
vmwgfx_overlay.o vmwgfx_gmrid_manager.o vmwgfx_fence.o \ vmwgfx_overlay.o vmwgfx_gmrid_manager.o vmwgfx_fence.o \
...@@ -12,6 +12,4 @@ vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_hashtab.o vmwgfx_kms.o vmwgfx_d ...@@ -12,6 +12,4 @@ vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_hashtab.o vmwgfx_kms.o vmwgfx_d
vmwgfx_devcaps.o ttm_object.o vmwgfx_system_manager.o \ vmwgfx_devcaps.o ttm_object.o vmwgfx_system_manager.o \
vmwgfx_gem.o vmwgfx_gem.o
vmwgfx-$(CONFIG_DRM_FBDEV_EMULATION) += vmwgfx_fb.o
obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o
/* SPDX-License-Identifier: GPL-2.0 OR MIT */ /* SPDX-License-Identifier: GPL-2.0 OR MIT */
/************************************************************************** /**************************************************************************
* *
* Copyright (c) 2009-2013 VMware, Inc., Palo Alto, CA., USA * Copyright (c) 2009-2022 VMware, Inc., Palo Alto, CA., USA
* All Rights Reserved. * All Rights Reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission is hereby granted, free of charge, to any person obtaining a
...@@ -44,16 +44,20 @@ ...@@ -44,16 +44,20 @@
#define pr_fmt(fmt) "[TTM] " fmt #define pr_fmt(fmt) "[TTM] " fmt
#include "ttm_object.h"
#include "vmwgfx_drv.h"
#include <linux/list.h> #include <linux/list.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/atomic.h> #include <linux/atomic.h>
#include <linux/module.h> #include <linux/module.h>
#include "ttm_object.h" #include <linux/hashtable.h>
#include "vmwgfx_drv.h"
MODULE_IMPORT_NS(DMA_BUF); MODULE_IMPORT_NS(DMA_BUF);
#define VMW_TTM_OBJECT_REF_HT_ORDER 10
/** /**
* struct ttm_object_file * struct ttm_object_file
* *
...@@ -74,16 +78,14 @@ struct ttm_object_file { ...@@ -74,16 +78,14 @@ struct ttm_object_file {
struct ttm_object_device *tdev; struct ttm_object_device *tdev;
spinlock_t lock; spinlock_t lock;
struct list_head ref_list; struct list_head ref_list;
struct vmwgfx_open_hash ref_hash; DECLARE_HASHTABLE(ref_hash, VMW_TTM_OBJECT_REF_HT_ORDER);
struct kref refcount; struct kref refcount;
}; };
/* /*
* struct ttm_object_device * struct ttm_object_device
* *
* @object_lock: lock that protects the object_hash hash table. * @object_lock: lock that protects idr.
*
* @object_hash: hash table for fast lookup of object global names.
* *
* @object_count: Per device object count. * @object_count: Per device object count.
* *
...@@ -92,7 +94,6 @@ struct ttm_object_file { ...@@ -92,7 +94,6 @@ struct ttm_object_file {
struct ttm_object_device { struct ttm_object_device {
spinlock_t object_lock; spinlock_t object_lock;
struct vmwgfx_open_hash object_hash;
atomic_t object_count; atomic_t object_count;
struct dma_buf_ops ops; struct dma_buf_ops ops;
void (*dmabuf_release)(struct dma_buf *dma_buf); void (*dmabuf_release)(struct dma_buf *dma_buf);
...@@ -138,6 +139,36 @@ ttm_object_file_ref(struct ttm_object_file *tfile) ...@@ -138,6 +139,36 @@ ttm_object_file_ref(struct ttm_object_file *tfile)
return tfile; return tfile;
} }
static int ttm_tfile_find_ref_rcu(struct ttm_object_file *tfile,
uint64_t key,
struct vmwgfx_hash_item **p_hash)
{
struct vmwgfx_hash_item *hash;
hash_for_each_possible_rcu(tfile->ref_hash, hash, head, key) {
if (hash->key == key) {
*p_hash = hash;
return 0;
}
}
return -EINVAL;
}
static int ttm_tfile_find_ref(struct ttm_object_file *tfile,
uint64_t key,
struct vmwgfx_hash_item **p_hash)
{
struct vmwgfx_hash_item *hash;
hash_for_each_possible(tfile->ref_hash, hash, head, key) {
if (hash->key == key) {
*p_hash = hash;
return 0;
}
}
return -EINVAL;
}
static void ttm_object_file_destroy(struct kref *kref) static void ttm_object_file_destroy(struct kref *kref)
{ {
struct ttm_object_file *tfile = struct ttm_object_file *tfile =
...@@ -240,37 +271,35 @@ void ttm_base_object_unref(struct ttm_base_object **p_base) ...@@ -240,37 +271,35 @@ void ttm_base_object_unref(struct ttm_base_object **p_base)
* Return: A pointer to the object if successful or NULL otherwise. * Return: A pointer to the object if successful or NULL otherwise.
*/ */
struct ttm_base_object * struct ttm_base_object *
ttm_base_object_noref_lookup(struct ttm_object_file *tfile, uint32_t key) ttm_base_object_noref_lookup(struct ttm_object_file *tfile, uint64_t key)
{ {
struct vmwgfx_hash_item *hash; struct vmwgfx_hash_item *hash;
struct vmwgfx_open_hash *ht = &tfile->ref_hash;
int ret; int ret;
rcu_read_lock(); rcu_read_lock();
ret = vmwgfx_ht_find_item_rcu(ht, key, &hash); ret = ttm_tfile_find_ref_rcu(tfile, key, &hash);
if (ret) { if (ret) {
rcu_read_unlock(); rcu_read_unlock();
return NULL; return NULL;
} }
__release(RCU); __release(RCU);
return drm_hash_entry(hash, struct ttm_ref_object, hash)->obj; return hlist_entry(hash, struct ttm_ref_object, hash)->obj;
} }
EXPORT_SYMBOL(ttm_base_object_noref_lookup); EXPORT_SYMBOL(ttm_base_object_noref_lookup);
struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file *tfile, struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file *tfile,
uint32_t key) uint64_t key)
{ {
struct ttm_base_object *base = NULL; struct ttm_base_object *base = NULL;
struct vmwgfx_hash_item *hash; struct vmwgfx_hash_item *hash;
struct vmwgfx_open_hash *ht = &tfile->ref_hash;
int ret; int ret;
rcu_read_lock(); rcu_read_lock();
ret = vmwgfx_ht_find_item_rcu(ht, key, &hash); ret = ttm_tfile_find_ref_rcu(tfile, key, &hash);
if (likely(ret == 0)) { if (likely(ret == 0)) {
base = drm_hash_entry(hash, struct ttm_ref_object, hash)->obj; base = hlist_entry(hash, struct ttm_ref_object, hash)->obj;
if (!kref_get_unless_zero(&base->refcount)) if (!kref_get_unless_zero(&base->refcount))
base = NULL; base = NULL;
} }
...@@ -280,7 +309,7 @@ struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file *tfile, ...@@ -280,7 +309,7 @@ struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file *tfile,
} }
struct ttm_base_object * struct ttm_base_object *
ttm_base_object_lookup_for_ref(struct ttm_object_device *tdev, uint32_t key) ttm_base_object_lookup_for_ref(struct ttm_object_device *tdev, uint64_t key)
{ {
struct ttm_base_object *base; struct ttm_base_object *base;
...@@ -299,7 +328,6 @@ int ttm_ref_object_add(struct ttm_object_file *tfile, ...@@ -299,7 +328,6 @@ int ttm_ref_object_add(struct ttm_object_file *tfile,
bool *existed, bool *existed,
bool require_existed) bool require_existed)
{ {
struct vmwgfx_open_hash *ht = &tfile->ref_hash;
struct ttm_ref_object *ref; struct ttm_ref_object *ref;
struct vmwgfx_hash_item *hash; struct vmwgfx_hash_item *hash;
int ret = -EINVAL; int ret = -EINVAL;
...@@ -312,10 +340,10 @@ int ttm_ref_object_add(struct ttm_object_file *tfile, ...@@ -312,10 +340,10 @@ int ttm_ref_object_add(struct ttm_object_file *tfile,
while (ret == -EINVAL) { while (ret == -EINVAL) {
rcu_read_lock(); rcu_read_lock();
ret = vmwgfx_ht_find_item_rcu(ht, base->handle, &hash); ret = ttm_tfile_find_ref_rcu(tfile, base->handle, &hash);
if (ret == 0) { if (ret == 0) {
ref = drm_hash_entry(hash, struct ttm_ref_object, hash); ref = hlist_entry(hash, struct ttm_ref_object, hash);
if (kref_get_unless_zero(&ref->kref)) { if (kref_get_unless_zero(&ref->kref)) {
rcu_read_unlock(); rcu_read_unlock();
break; break;
...@@ -337,21 +365,14 @@ int ttm_ref_object_add(struct ttm_object_file *tfile, ...@@ -337,21 +365,14 @@ int ttm_ref_object_add(struct ttm_object_file *tfile,
kref_init(&ref->kref); kref_init(&ref->kref);
spin_lock(&tfile->lock); spin_lock(&tfile->lock);
ret = vmwgfx_ht_insert_item_rcu(ht, &ref->hash); hash_add_rcu(tfile->ref_hash, &ref->hash.head, ref->hash.key);
ret = 0;
if (likely(ret == 0)) {
list_add_tail(&ref->head, &tfile->ref_list);
kref_get(&base->refcount);
spin_unlock(&tfile->lock);
if (existed != NULL)
*existed = false;
break;
}
list_add_tail(&ref->head, &tfile->ref_list);
kref_get(&base->refcount);
spin_unlock(&tfile->lock); spin_unlock(&tfile->lock);
BUG_ON(ret != -EINVAL); if (existed != NULL)
*existed = false;
kfree(ref);
} }
return ret; return ret;
...@@ -363,10 +384,8 @@ ttm_ref_object_release(struct kref *kref) ...@@ -363,10 +384,8 @@ ttm_ref_object_release(struct kref *kref)
struct ttm_ref_object *ref = struct ttm_ref_object *ref =
container_of(kref, struct ttm_ref_object, kref); container_of(kref, struct ttm_ref_object, kref);
struct ttm_object_file *tfile = ref->tfile; struct ttm_object_file *tfile = ref->tfile;
struct vmwgfx_open_hash *ht;
ht = &tfile->ref_hash; hash_del_rcu(&ref->hash.head);
(void)vmwgfx_ht_remove_item_rcu(ht, &ref->hash);
list_del(&ref->head); list_del(&ref->head);
spin_unlock(&tfile->lock); spin_unlock(&tfile->lock);
...@@ -378,18 +397,17 @@ ttm_ref_object_release(struct kref *kref) ...@@ -378,18 +397,17 @@ ttm_ref_object_release(struct kref *kref)
int ttm_ref_object_base_unref(struct ttm_object_file *tfile, int ttm_ref_object_base_unref(struct ttm_object_file *tfile,
unsigned long key) unsigned long key)
{ {
struct vmwgfx_open_hash *ht = &tfile->ref_hash;
struct ttm_ref_object *ref; struct ttm_ref_object *ref;
struct vmwgfx_hash_item *hash; struct vmwgfx_hash_item *hash;
int ret; int ret;
spin_lock(&tfile->lock); spin_lock(&tfile->lock);
ret = vmwgfx_ht_find_item(ht, key, &hash); ret = ttm_tfile_find_ref(tfile, key, &hash);
if (unlikely(ret != 0)) { if (unlikely(ret != 0)) {
spin_unlock(&tfile->lock); spin_unlock(&tfile->lock);
return -EINVAL; return -EINVAL;
} }
ref = drm_hash_entry(hash, struct ttm_ref_object, hash); ref = hlist_entry(hash, struct ttm_ref_object, hash);
kref_put(&ref->kref, ttm_ref_object_release); kref_put(&ref->kref, ttm_ref_object_release);
spin_unlock(&tfile->lock); spin_unlock(&tfile->lock);
return 0; return 0;
...@@ -416,16 +434,13 @@ void ttm_object_file_release(struct ttm_object_file **p_tfile) ...@@ -416,16 +434,13 @@ void ttm_object_file_release(struct ttm_object_file **p_tfile)
} }
spin_unlock(&tfile->lock); spin_unlock(&tfile->lock);
vmwgfx_ht_remove(&tfile->ref_hash);
ttm_object_file_unref(&tfile); ttm_object_file_unref(&tfile);
} }
struct ttm_object_file *ttm_object_file_init(struct ttm_object_device *tdev, struct ttm_object_file *ttm_object_file_init(struct ttm_object_device *tdev)
unsigned int hash_order)
{ {
struct ttm_object_file *tfile = kmalloc(sizeof(*tfile), GFP_KERNEL); struct ttm_object_file *tfile = kmalloc(sizeof(*tfile), GFP_KERNEL);
int ret;
if (unlikely(tfile == NULL)) if (unlikely(tfile == NULL))
return NULL; return NULL;
...@@ -435,34 +450,21 @@ struct ttm_object_file *ttm_object_file_init(struct ttm_object_device *tdev, ...@@ -435,34 +450,21 @@ struct ttm_object_file *ttm_object_file_init(struct ttm_object_device *tdev,
kref_init(&tfile->refcount); kref_init(&tfile->refcount);
INIT_LIST_HEAD(&tfile->ref_list); INIT_LIST_HEAD(&tfile->ref_list);
ret = vmwgfx_ht_create(&tfile->ref_hash, hash_order); hash_init(tfile->ref_hash);
if (ret)
goto out_err;
return tfile; return tfile;
out_err:
vmwgfx_ht_remove(&tfile->ref_hash);
kfree(tfile);
return NULL;
} }
struct ttm_object_device * struct ttm_object_device *
ttm_object_device_init(unsigned int hash_order, ttm_object_device_init(const struct dma_buf_ops *ops)
const struct dma_buf_ops *ops)
{ {
struct ttm_object_device *tdev = kmalloc(sizeof(*tdev), GFP_KERNEL); struct ttm_object_device *tdev = kmalloc(sizeof(*tdev), GFP_KERNEL);
int ret;
if (unlikely(tdev == NULL)) if (unlikely(tdev == NULL))
return NULL; return NULL;
spin_lock_init(&tdev->object_lock); spin_lock_init(&tdev->object_lock);
atomic_set(&tdev->object_count, 0); atomic_set(&tdev->object_count, 0);
ret = vmwgfx_ht_create(&tdev->object_hash, hash_order);
if (ret != 0)
goto out_no_object_hash;
/* /*
* Our base is at VMWGFX_NUM_MOB + 1 because we want to create * Our base is at VMWGFX_NUM_MOB + 1 because we want to create
...@@ -477,10 +479,6 @@ ttm_object_device_init(unsigned int hash_order, ...@@ -477,10 +479,6 @@ ttm_object_device_init(unsigned int hash_order,
tdev->dmabuf_release = tdev->ops.release; tdev->dmabuf_release = tdev->ops.release;
tdev->ops.release = ttm_prime_dmabuf_release; tdev->ops.release = ttm_prime_dmabuf_release;
return tdev; return tdev;
out_no_object_hash:
kfree(tdev);
return NULL;
} }
void ttm_object_device_release(struct ttm_object_device **p_tdev) void ttm_object_device_release(struct ttm_object_device **p_tdev)
...@@ -491,7 +489,6 @@ void ttm_object_device_release(struct ttm_object_device **p_tdev) ...@@ -491,7 +489,6 @@ void ttm_object_device_release(struct ttm_object_device **p_tdev)
WARN_ON_ONCE(!idr_is_empty(&tdev->idr)); WARN_ON_ONCE(!idr_is_empty(&tdev->idr));
idr_destroy(&tdev->idr); idr_destroy(&tdev->idr);
vmwgfx_ht_remove(&tdev->object_hash);
kfree(tdev); kfree(tdev);
} }
......
/************************************************************************** /**************************************************************************
* *
* Copyright (c) 2006-2009 VMware, Inc., Palo Alto, CA., USA * Copyright (c) 2006-2022 VMware, Inc., Palo Alto, CA., USA
* All Rights Reserved. * All Rights Reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission is hereby granted, free of charge, to any person obtaining a
...@@ -42,8 +42,6 @@ ...@@ -42,8 +42,6 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/rcupdate.h> #include <linux/rcupdate.h>
#include "vmwgfx_hashtab.h"
/** /**
* enum ttm_object_type * enum ttm_object_type
* *
...@@ -104,7 +102,7 @@ struct ttm_base_object { ...@@ -104,7 +102,7 @@ struct ttm_base_object {
struct ttm_object_file *tfile; struct ttm_object_file *tfile;
struct kref refcount; struct kref refcount;
void (*refcount_release) (struct ttm_base_object **base); void (*refcount_release) (struct ttm_base_object **base);
u32 handle; u64 handle;
enum ttm_object_type object_type; enum ttm_object_type object_type;
u32 shareable; u32 shareable;
}; };
...@@ -164,7 +162,7 @@ extern int ttm_base_object_init(struct ttm_object_file *tfile, ...@@ -164,7 +162,7 @@ extern int ttm_base_object_init(struct ttm_object_file *tfile,
*/ */
extern struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file extern struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file
*tfile, uint32_t key); *tfile, uint64_t key);
/** /**
* ttm_base_object_lookup_for_ref * ttm_base_object_lookup_for_ref
...@@ -178,7 +176,7 @@ extern struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file ...@@ -178,7 +176,7 @@ extern struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file
*/ */
extern struct ttm_base_object * extern struct ttm_base_object *
ttm_base_object_lookup_for_ref(struct ttm_object_device *tdev, uint32_t key); ttm_base_object_lookup_for_ref(struct ttm_object_device *tdev, uint64_t key);
/** /**
* ttm_base_object_unref * ttm_base_object_unref
...@@ -237,14 +235,12 @@ extern int ttm_ref_object_base_unref(struct ttm_object_file *tfile, ...@@ -237,14 +235,12 @@ extern int ttm_ref_object_base_unref(struct ttm_object_file *tfile,
* ttm_object_file_init - initialize a struct ttm_object file * ttm_object_file_init - initialize a struct ttm_object file
* *
* @tdev: A struct ttm_object device this file is initialized on. * @tdev: A struct ttm_object device this file is initialized on.
* @hash_order: Order of the hash table used to hold the reference objects.
* *
* This is typically called by the file_ops::open function. * This is typically called by the file_ops::open function.
*/ */
extern struct ttm_object_file *ttm_object_file_init(struct ttm_object_device extern struct ttm_object_file *ttm_object_file_init(struct ttm_object_device
*tdev, *tdev);
unsigned int hash_order);
/** /**
* ttm_object_file_release - release data held by a ttm_object_file * ttm_object_file_release - release data held by a ttm_object_file
...@@ -262,7 +258,6 @@ extern void ttm_object_file_release(struct ttm_object_file **p_tfile); ...@@ -262,7 +258,6 @@ extern void ttm_object_file_release(struct ttm_object_file **p_tfile);
/** /**
* ttm_object device init - initialize a struct ttm_object_device * ttm_object device init - initialize a struct ttm_object_device
* *
* @hash_order: Order of hash table used to hash the base objects.
* @ops: DMA buf ops for prime objects of this device. * @ops: DMA buf ops for prime objects of this device.
* *
* This function is typically called on device initialization to prepare * This function is typically called on device initialization to prepare
...@@ -270,8 +265,7 @@ extern void ttm_object_file_release(struct ttm_object_file **p_tfile); ...@@ -270,8 +265,7 @@ extern void ttm_object_file_release(struct ttm_object_file **p_tfile);
*/ */
extern struct ttm_object_device * extern struct ttm_object_device *
ttm_object_device_init(unsigned int hash_order, ttm_object_device_init(const struct dma_buf_ops *ops);
const struct dma_buf_ops *ops);
/** /**
* ttm_object_device_release - release data held by a ttm_object_device * ttm_object_device_release - release data held by a ttm_object_device
...@@ -314,7 +308,7 @@ extern int ttm_prime_handle_to_fd(struct ttm_object_file *tfile, ...@@ -314,7 +308,7 @@ extern int ttm_prime_handle_to_fd(struct ttm_object_file *tfile,
kfree_rcu(__obj, __prime.base.rhead) kfree_rcu(__obj, __prime.base.rhead)
struct ttm_base_object * struct ttm_base_object *
ttm_base_object_noref_lookup(struct ttm_object_file *tfile, uint32_t key); ttm_base_object_noref_lookup(struct ttm_object_file *tfile, uint64_t key);
/** /**
* ttm_base_object_noref_release - release a base object pointer looked up * ttm_base_object_noref_release - release a base object pointer looked up
......
...@@ -807,9 +807,23 @@ int vmw_dumb_create(struct drm_file *file_priv, ...@@ -807,9 +807,23 @@ int vmw_dumb_create(struct drm_file *file_priv,
{ {
struct vmw_private *dev_priv = vmw_priv(dev); struct vmw_private *dev_priv = vmw_priv(dev);
struct vmw_buffer_object *vbo; struct vmw_buffer_object *vbo;
int cpp = DIV_ROUND_UP(args->bpp, 8);
int ret; int ret;
args->pitch = args->width * ((args->bpp + 7) / 8); switch (cpp) {
case 1: /* DRM_FORMAT_C8 */
case 2: /* DRM_FORMAT_RGB565 */
case 4: /* DRM_FORMAT_XRGB8888 */
break;
default:
/*
* Dumb buffers don't allow anything else.
* This is tested via IGT's dumb_buffers
*/
return -EINVAL;
}
args->pitch = args->width * cpp;
args->size = ALIGN(args->pitch * args->height, PAGE_SIZE); args->size = ALIGN(args->pitch * args->height, PAGE_SIZE);
ret = vmw_gem_object_create_with_handle(dev_priv, file_priv, ret = vmw_gem_object_create_with_handle(dev_priv, file_priv,
......
// SPDX-License-Identifier: GPL-2.0 OR MIT // SPDX-License-Identifier: GPL-2.0 OR MIT
/************************************************************************** /**************************************************************************
* *
* Copyright 2014-2015 VMware, Inc., Palo Alto, CA., USA * Copyright 2014-2022 VMware, Inc., Palo Alto, CA., USA
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the * copy of this software and associated documentation files (the
...@@ -28,6 +28,8 @@ ...@@ -28,6 +28,8 @@
#include "vmwgfx_drv.h" #include "vmwgfx_drv.h"
#include "vmwgfx_resource_priv.h" #include "vmwgfx_resource_priv.h"
#include <linux/hashtable.h>
#define VMW_CMDBUF_RES_MAN_HT_ORDER 12 #define VMW_CMDBUF_RES_MAN_HT_ORDER 12
/** /**
...@@ -59,7 +61,7 @@ struct vmw_cmdbuf_res { ...@@ -59,7 +61,7 @@ struct vmw_cmdbuf_res {
* @resources and @list are protected by the cmdbuf mutex for now. * @resources and @list are protected by the cmdbuf mutex for now.
*/ */
struct vmw_cmdbuf_res_manager { struct vmw_cmdbuf_res_manager {
struct vmwgfx_open_hash resources; DECLARE_HASHTABLE(resources, VMW_CMDBUF_RES_MAN_HT_ORDER);
struct list_head list; struct list_head list;
struct vmw_private *dev_priv; struct vmw_private *dev_priv;
}; };
...@@ -82,14 +84,13 @@ vmw_cmdbuf_res_lookup(struct vmw_cmdbuf_res_manager *man, ...@@ -82,14 +84,13 @@ vmw_cmdbuf_res_lookup(struct vmw_cmdbuf_res_manager *man,
u32 user_key) u32 user_key)
{ {
struct vmwgfx_hash_item *hash; struct vmwgfx_hash_item *hash;
int ret;
unsigned long key = user_key | (res_type << 24); unsigned long key = user_key | (res_type << 24);
ret = vmwgfx_ht_find_item(&man->resources, key, &hash); hash_for_each_possible_rcu(man->resources, hash, head, key) {
if (unlikely(ret != 0)) if (hash->key == key)
return ERR_PTR(ret); return hlist_entry(hash, struct vmw_cmdbuf_res, hash)->res;
}
return drm_hash_entry(hash, struct vmw_cmdbuf_res, hash)->res; return ERR_PTR(-EINVAL);
} }
/** /**
...@@ -105,7 +106,7 @@ static void vmw_cmdbuf_res_free(struct vmw_cmdbuf_res_manager *man, ...@@ -105,7 +106,7 @@ static void vmw_cmdbuf_res_free(struct vmw_cmdbuf_res_manager *man,
struct vmw_cmdbuf_res *entry) struct vmw_cmdbuf_res *entry)
{ {
list_del(&entry->head); list_del(&entry->head);
WARN_ON(vmwgfx_ht_remove_item(&man->resources, &entry->hash)); hash_del_rcu(&entry->hash.head);
vmw_resource_unreference(&entry->res); vmw_resource_unreference(&entry->res);
kfree(entry); kfree(entry);
} }
...@@ -159,7 +160,6 @@ void vmw_cmdbuf_res_commit(struct list_head *list) ...@@ -159,7 +160,6 @@ void vmw_cmdbuf_res_commit(struct list_head *list)
void vmw_cmdbuf_res_revert(struct list_head *list) void vmw_cmdbuf_res_revert(struct list_head *list)
{ {
struct vmw_cmdbuf_res *entry, *next; struct vmw_cmdbuf_res *entry, *next;
int ret;
list_for_each_entry_safe(entry, next, list, head) { list_for_each_entry_safe(entry, next, list, head) {
switch (entry->state) { switch (entry->state) {
...@@ -167,8 +167,8 @@ void vmw_cmdbuf_res_revert(struct list_head *list) ...@@ -167,8 +167,8 @@ void vmw_cmdbuf_res_revert(struct list_head *list)
vmw_cmdbuf_res_free(entry->man, entry); vmw_cmdbuf_res_free(entry->man, entry);
break; break;
case VMW_CMDBUF_RES_DEL: case VMW_CMDBUF_RES_DEL:
ret = vmwgfx_ht_insert_item(&entry->man->resources, &entry->hash); hash_add_rcu(entry->man->resources, &entry->hash.head,
BUG_ON(ret); entry->hash.key);
list_move_tail(&entry->head, &entry->man->list); list_move_tail(&entry->head, &entry->man->list);
entry->state = VMW_CMDBUF_RES_COMMITTED; entry->state = VMW_CMDBUF_RES_COMMITTED;
break; break;
...@@ -199,26 +199,20 @@ int vmw_cmdbuf_res_add(struct vmw_cmdbuf_res_manager *man, ...@@ -199,26 +199,20 @@ int vmw_cmdbuf_res_add(struct vmw_cmdbuf_res_manager *man,
struct list_head *list) struct list_head *list)
{ {
struct vmw_cmdbuf_res *cres; struct vmw_cmdbuf_res *cres;
int ret;
cres = kzalloc(sizeof(*cres), GFP_KERNEL); cres = kzalloc(sizeof(*cres), GFP_KERNEL);
if (unlikely(!cres)) if (unlikely(!cres))
return -ENOMEM; return -ENOMEM;
cres->hash.key = user_key | (res_type << 24); cres->hash.key = user_key | (res_type << 24);
ret = vmwgfx_ht_insert_item(&man->resources, &cres->hash); hash_add_rcu(man->resources, &cres->hash.head, cres->hash.key);
if (unlikely(ret != 0)) {
kfree(cres);
goto out_invalid_key;
}
cres->state = VMW_CMDBUF_RES_ADD; cres->state = VMW_CMDBUF_RES_ADD;
cres->res = vmw_resource_reference(res); cres->res = vmw_resource_reference(res);
cres->man = man; cres->man = man;
list_add_tail(&cres->head, list); list_add_tail(&cres->head, list);
out_invalid_key: return 0;
return ret;
} }
/** /**
...@@ -243,24 +237,26 @@ int vmw_cmdbuf_res_remove(struct vmw_cmdbuf_res_manager *man, ...@@ -243,24 +237,26 @@ int vmw_cmdbuf_res_remove(struct vmw_cmdbuf_res_manager *man,
struct list_head *list, struct list_head *list,
struct vmw_resource **res_p) struct vmw_resource **res_p)
{ {
struct vmw_cmdbuf_res *entry; struct vmw_cmdbuf_res *entry = NULL;
struct vmwgfx_hash_item *hash; struct vmwgfx_hash_item *hash;
int ret; unsigned long key = user_key | (res_type << 24);
ret = vmwgfx_ht_find_item(&man->resources, user_key | (res_type << 24), hash_for_each_possible_rcu(man->resources, hash, head, key) {
&hash); if (hash->key == key) {
if (likely(ret != 0)) entry = hlist_entry(hash, struct vmw_cmdbuf_res, hash);
break;
}
}
if (unlikely(!entry))
return -EINVAL; return -EINVAL;
entry = drm_hash_entry(hash, struct vmw_cmdbuf_res, hash);
switch (entry->state) { switch (entry->state) {
case VMW_CMDBUF_RES_ADD: case VMW_CMDBUF_RES_ADD:
vmw_cmdbuf_res_free(man, entry); vmw_cmdbuf_res_free(man, entry);
*res_p = NULL; *res_p = NULL;
break; break;
case VMW_CMDBUF_RES_COMMITTED: case VMW_CMDBUF_RES_COMMITTED:
(void) vmwgfx_ht_remove_item(&man->resources, &entry->hash); hash_del_rcu(&entry->hash.head);
list_del(&entry->head); list_del(&entry->head);
entry->state = VMW_CMDBUF_RES_DEL; entry->state = VMW_CMDBUF_RES_DEL;
list_add_tail(&entry->head, list); list_add_tail(&entry->head, list);
...@@ -287,7 +283,6 @@ struct vmw_cmdbuf_res_manager * ...@@ -287,7 +283,6 @@ struct vmw_cmdbuf_res_manager *
vmw_cmdbuf_res_man_create(struct vmw_private *dev_priv) vmw_cmdbuf_res_man_create(struct vmw_private *dev_priv)
{ {
struct vmw_cmdbuf_res_manager *man; struct vmw_cmdbuf_res_manager *man;
int ret;
man = kzalloc(sizeof(*man), GFP_KERNEL); man = kzalloc(sizeof(*man), GFP_KERNEL);
if (!man) if (!man)
...@@ -295,12 +290,8 @@ vmw_cmdbuf_res_man_create(struct vmw_private *dev_priv) ...@@ -295,12 +290,8 @@ vmw_cmdbuf_res_man_create(struct vmw_private *dev_priv)
man->dev_priv = dev_priv; man->dev_priv = dev_priv;
INIT_LIST_HEAD(&man->list); INIT_LIST_HEAD(&man->list);
ret = vmwgfx_ht_create(&man->resources, VMW_CMDBUF_RES_MAN_HT_ORDER); hash_init(man->resources);
if (ret == 0) return man;
return man;
kfree(man);
return ERR_PTR(ret);
} }
/** /**
...@@ -320,7 +311,6 @@ void vmw_cmdbuf_res_man_destroy(struct vmw_cmdbuf_res_manager *man) ...@@ -320,7 +311,6 @@ void vmw_cmdbuf_res_man_destroy(struct vmw_cmdbuf_res_manager *man)
list_for_each_entry_safe(entry, next, &man->list, head) list_for_each_entry_safe(entry, next, &man->list, head)
vmw_cmdbuf_res_free(man, entry); vmw_cmdbuf_res_free(man, entry);
vmwgfx_ht_remove(&man->resources);
kfree(man); kfree(man);
} }
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <drm/ttm/ttm_placement.h> #include <drm/ttm/ttm_placement.h>
#include "vmwgfx_drv.h" #include "vmwgfx_drv.h"
#include "vmwgfx_mksstat.h"
#include "vmwgfx_resource_priv.h" #include "vmwgfx_resource_priv.h"
#include "vmwgfx_so.h" #include "vmwgfx_so.h"
...@@ -72,12 +73,24 @@ struct vmw_cotable_info { ...@@ -72,12 +73,24 @@ struct vmw_cotable_info {
bool); bool);
}; };
/*
* Getting the initial size right is difficult because it all depends
* on what the userspace is doing. The sizes will be aligned up to
* a PAGE_SIZE so we just want to make sure that for majority of apps
* the initial number of entries doesn't require an immediate resize.
* For all cotables except SVGACOTableDXElementLayoutEntry and
* SVGACOTableDXBlendStateEntry the initial number of entries fits
* within the PAGE_SIZE. For SVGACOTableDXElementLayoutEntry and
* SVGACOTableDXBlendStateEntry we want to reserve two pages,
* because that's what all apps will require initially.
*/
static const struct vmw_cotable_info co_info[] = { static const struct vmw_cotable_info co_info[] = {
{1, sizeof(SVGACOTableDXRTViewEntry), &vmw_view_cotable_list_destroy}, {1, sizeof(SVGACOTableDXRTViewEntry), &vmw_view_cotable_list_destroy},
{1, sizeof(SVGACOTableDXDSViewEntry), &vmw_view_cotable_list_destroy}, {1, sizeof(SVGACOTableDXDSViewEntry), &vmw_view_cotable_list_destroy},
{1, sizeof(SVGACOTableDXSRViewEntry), &vmw_view_cotable_list_destroy}, {1, sizeof(SVGACOTableDXSRViewEntry), &vmw_view_cotable_list_destroy},
{1, sizeof(SVGACOTableDXElementLayoutEntry), NULL}, {PAGE_SIZE/sizeof(SVGACOTableDXElementLayoutEntry) + 1, sizeof(SVGACOTableDXElementLayoutEntry), NULL},
{1, sizeof(SVGACOTableDXBlendStateEntry), NULL}, {PAGE_SIZE/sizeof(SVGACOTableDXBlendStateEntry) + 1, sizeof(SVGACOTableDXBlendStateEntry), NULL},
{1, sizeof(SVGACOTableDXDepthStencilEntry), NULL}, {1, sizeof(SVGACOTableDXDepthStencilEntry), NULL},
{1, sizeof(SVGACOTableDXRasterizerStateEntry), NULL}, {1, sizeof(SVGACOTableDXRasterizerStateEntry), NULL},
{1, sizeof(SVGACOTableDXSamplerEntry), NULL}, {1, sizeof(SVGACOTableDXSamplerEntry), NULL},
...@@ -395,9 +408,12 @@ static int vmw_cotable_resize(struct vmw_resource *res, size_t new_size) ...@@ -395,9 +408,12 @@ static int vmw_cotable_resize(struct vmw_resource *res, size_t new_size)
int ret; int ret;
size_t i; size_t i;
MKS_STAT_TIME_DECL(MKSSTAT_KERN_COTABLE_RESIZE);
MKS_STAT_TIME_PUSH(MKSSTAT_KERN_COTABLE_RESIZE);
ret = vmw_cotable_readback(res); ret = vmw_cotable_readback(res);
if (ret) if (ret)
return ret; goto out_done;
cur_size_read_back = vcotbl->size_read_back; cur_size_read_back = vcotbl->size_read_back;
vcotbl->size_read_back = old_size_read_back; vcotbl->size_read_back = old_size_read_back;
...@@ -411,7 +427,7 @@ static int vmw_cotable_resize(struct vmw_resource *res, size_t new_size) ...@@ -411,7 +427,7 @@ static int vmw_cotable_resize(struct vmw_resource *res, size_t new_size)
true, true, vmw_bo_bo_free, &buf); true, true, vmw_bo_bo_free, &buf);
if (ret) { if (ret) {
DRM_ERROR("Failed initializing new cotable MOB.\n"); DRM_ERROR("Failed initializing new cotable MOB.\n");
return ret; goto out_done;
} }
bo = &buf->base; bo = &buf->base;
...@@ -485,6 +501,8 @@ static int vmw_cotable_resize(struct vmw_resource *res, size_t new_size) ...@@ -485,6 +501,8 @@ static int vmw_cotable_resize(struct vmw_resource *res, size_t new_size)
/* Release the pin acquired in vmw_bo_init */ /* Release the pin acquired in vmw_bo_init */
ttm_bo_unpin(bo); ttm_bo_unpin(bo);
MKS_STAT_TIME_POP(MKSSTAT_KERN_COTABLE_RESIZE);
return 0; return 0;
out_map_new: out_map_new:
...@@ -494,6 +512,9 @@ static int vmw_cotable_resize(struct vmw_resource *res, size_t new_size) ...@@ -494,6 +512,9 @@ static int vmw_cotable_resize(struct vmw_resource *res, size_t new_size)
ttm_bo_unreserve(bo); ttm_bo_unreserve(bo);
vmw_bo_unreference(&buf); vmw_bo_unreference(&buf);
out_done:
MKS_STAT_TIME_POP(MKSSTAT_KERN_COTABLE_RESIZE);
return ret; return ret;
} }
......
...@@ -25,13 +25,17 @@ ...@@ -25,13 +25,17 @@
* *
**************************************************************************/ **************************************************************************/
#include <linux/dma-mapping.h>
#include <linux/module.h> #include "vmwgfx_drv.h"
#include <linux/pci.h>
#include <linux/cc_platform.h> #include "vmwgfx_devcaps.h"
#include "vmwgfx_mksstat.h"
#include "vmwgfx_binding.h"
#include "ttm_object.h"
#include <drm/drm_aperture.h> #include <drm/drm_aperture.h>
#include <drm/drm_drv.h> #include <drm/drm_drv.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_gem_ttm_helper.h> #include <drm/drm_gem_ttm_helper.h>
#include <drm/drm_ioctl.h> #include <drm/drm_ioctl.h>
#include <drm/drm_module.h> #include <drm/drm_module.h>
...@@ -41,17 +45,14 @@ ...@@ -41,17 +45,14 @@
#include <drm/ttm/ttm_placement.h> #include <drm/ttm/ttm_placement.h>
#include <generated/utsrelease.h> #include <generated/utsrelease.h>
#include "ttm_object.h" #include <linux/cc_platform.h>
#include "vmwgfx_binding.h" #include <linux/dma-mapping.h>
#include "vmwgfx_devcaps.h" #include <linux/module.h>
#include "vmwgfx_drv.h" #include <linux/pci.h>
#include "vmwgfx_mksstat.h" #include <linux/version.h>
#define VMWGFX_DRIVER_DESC "Linux drm driver for VMware graphics devices" #define VMWGFX_DRIVER_DESC "Linux drm driver for VMware graphics devices"
#define VMW_MIN_INITIAL_WIDTH 800
#define VMW_MIN_INITIAL_HEIGHT 600
/* /*
* Fully encoded drm commands. Might move to vmw_drm.h * Fully encoded drm commands. Might move to vmw_drm.h
*/ */
...@@ -262,7 +263,6 @@ static const struct pci_device_id vmw_pci_id_list[] = { ...@@ -262,7 +263,6 @@ static const struct pci_device_id vmw_pci_id_list[] = {
}; };
MODULE_DEVICE_TABLE(pci, vmw_pci_id_list); MODULE_DEVICE_TABLE(pci, vmw_pci_id_list);
static int enable_fbdev = IS_ENABLED(CONFIG_DRM_VMWGFX_FBCON);
static int vmw_restrict_iommu; static int vmw_restrict_iommu;
static int vmw_force_coherent; static int vmw_force_coherent;
static int vmw_restrict_dma_mask; static int vmw_restrict_dma_mask;
...@@ -272,8 +272,6 @@ static int vmw_probe(struct pci_dev *, const struct pci_device_id *); ...@@ -272,8 +272,6 @@ static int vmw_probe(struct pci_dev *, const struct pci_device_id *);
static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val, static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val,
void *ptr); void *ptr);
MODULE_PARM_DESC(enable_fbdev, "Enable vmwgfx fbdev");
module_param_named(enable_fbdev, enable_fbdev, int, 0600);
MODULE_PARM_DESC(restrict_iommu, "Try to limit IOMMU usage for TTM pages"); MODULE_PARM_DESC(restrict_iommu, "Try to limit IOMMU usage for TTM pages");
module_param_named(restrict_iommu, vmw_restrict_iommu, int, 0600); module_param_named(restrict_iommu, vmw_restrict_iommu, int, 0600);
MODULE_PARM_DESC(force_coherent, "Force coherent TTM pages"); MODULE_PARM_DESC(force_coherent, "Force coherent TTM pages");
...@@ -623,8 +621,8 @@ static void vmw_get_initial_size(struct vmw_private *dev_priv) ...@@ -623,8 +621,8 @@ static void vmw_get_initial_size(struct vmw_private *dev_priv)
width = vmw_read(dev_priv, SVGA_REG_WIDTH); width = vmw_read(dev_priv, SVGA_REG_WIDTH);
height = vmw_read(dev_priv, SVGA_REG_HEIGHT); height = vmw_read(dev_priv, SVGA_REG_HEIGHT);
width = max_t(uint32_t, width, VMW_MIN_INITIAL_WIDTH); width = max_t(uint32_t, width, VMWGFX_MIN_INITIAL_WIDTH);
height = max_t(uint32_t, height, VMW_MIN_INITIAL_HEIGHT); height = max_t(uint32_t, height, VMWGFX_MIN_INITIAL_HEIGHT);
if (width > dev_priv->fb_max_width || if (width > dev_priv->fb_max_width ||
height > dev_priv->fb_max_height) { height > dev_priv->fb_max_height) {
...@@ -633,8 +631,8 @@ static void vmw_get_initial_size(struct vmw_private *dev_priv) ...@@ -633,8 +631,8 @@ static void vmw_get_initial_size(struct vmw_private *dev_priv)
* This is a host error and shouldn't occur. * This is a host error and shouldn't occur.
*/ */
width = VMW_MIN_INITIAL_WIDTH; width = VMWGFX_MIN_INITIAL_WIDTH;
height = VMW_MIN_INITIAL_HEIGHT; height = VMWGFX_MIN_INITIAL_HEIGHT;
} }
dev_priv->initial_width = width; dev_priv->initial_width = width;
...@@ -806,6 +804,43 @@ static int vmw_detect_version(struct vmw_private *dev) ...@@ -806,6 +804,43 @@ static int vmw_detect_version(struct vmw_private *dev)
return 0; return 0;
} }
static void vmw_write_driver_id(struct vmw_private *dev)
{
if ((dev->capabilities2 & SVGA_CAP2_DX2) != 0) {
vmw_write(dev, SVGA_REG_GUEST_DRIVER_ID,
SVGA_REG_GUEST_DRIVER_ID_LINUX);
vmw_write(dev, SVGA_REG_GUEST_DRIVER_VERSION1,
LINUX_VERSION_MAJOR << 24 |
LINUX_VERSION_PATCHLEVEL << 16 |
LINUX_VERSION_SUBLEVEL);
vmw_write(dev, SVGA_REG_GUEST_DRIVER_VERSION2,
VMWGFX_DRIVER_MAJOR << 24 |
VMWGFX_DRIVER_MINOR << 16 |
VMWGFX_DRIVER_PATCHLEVEL);
vmw_write(dev, SVGA_REG_GUEST_DRIVER_VERSION3, 0);
vmw_write(dev, SVGA_REG_GUEST_DRIVER_ID,
SVGA_REG_GUEST_DRIVER_ID_SUBMIT);
}
}
static void vmw_sw_context_init(struct vmw_private *dev_priv)
{
struct vmw_sw_context *sw_context = &dev_priv->ctx;
hash_init(sw_context->res_ht);
}
static void vmw_sw_context_fini(struct vmw_private *dev_priv)
{
struct vmw_sw_context *sw_context = &dev_priv->ctx;
vfree(sw_context->cmd_bounce);
if (sw_context->staged_bindings)
vmw_binding_state_free(sw_context->staged_bindings);
}
static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id) static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id)
{ {
int ret; int ret;
...@@ -815,6 +850,8 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id) ...@@ -815,6 +850,8 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id)
dev_priv->drm.dev_private = dev_priv; dev_priv->drm.dev_private = dev_priv;
vmw_sw_context_init(dev_priv);
mutex_init(&dev_priv->cmdbuf_mutex); mutex_init(&dev_priv->cmdbuf_mutex);
mutex_init(&dev_priv->binding_mutex); mutex_init(&dev_priv->binding_mutex);
spin_lock_init(&dev_priv->resource_lock); spin_lock_init(&dev_priv->resource_lock);
...@@ -844,9 +881,6 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id) ...@@ -844,9 +881,6 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id)
dev_priv->assume_16bpp = !!vmw_assume_16bpp; dev_priv->assume_16bpp = !!vmw_assume_16bpp;
dev_priv->enable_fb = enable_fbdev;
dev_priv->capabilities = vmw_read(dev_priv, SVGA_REG_CAPABILITIES); dev_priv->capabilities = vmw_read(dev_priv, SVGA_REG_CAPABILITIES);
vmw_print_bitmap(&dev_priv->drm, "Capabilities", vmw_print_bitmap(&dev_priv->drm, "Capabilities",
dev_priv->capabilities, dev_priv->capabilities,
...@@ -970,7 +1004,7 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id) ...@@ -970,7 +1004,7 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id)
goto out_err0; goto out_err0;
} }
dev_priv->tdev = ttm_object_device_init(12, &vmw_prime_dmabuf_ops); dev_priv->tdev = ttm_object_device_init(&vmw_prime_dmabuf_ops);
if (unlikely(dev_priv->tdev == NULL)) { if (unlikely(dev_priv->tdev == NULL)) {
drm_err(&dev_priv->drm, drm_err(&dev_priv->drm,
...@@ -1091,12 +1125,7 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id) ...@@ -1091,12 +1125,7 @@ static int vmw_driver_load(struct vmw_private *dev_priv, u32 pci_id)
vmw_host_printf("vmwgfx: Module Version: %d.%d.%d (kernel: %s)", vmw_host_printf("vmwgfx: Module Version: %d.%d.%d (kernel: %s)",
VMWGFX_DRIVER_MAJOR, VMWGFX_DRIVER_MINOR, VMWGFX_DRIVER_MAJOR, VMWGFX_DRIVER_MINOR,
VMWGFX_DRIVER_PATCHLEVEL, UTS_RELEASE); VMWGFX_DRIVER_PATCHLEVEL, UTS_RELEASE);
vmw_write_driver_id(dev_priv);
if (dev_priv->enable_fb) {
vmw_fifo_resource_inc(dev_priv);
vmw_svga_enable(dev_priv);
vmw_fb_init(dev_priv);
}
dev_priv->pm_nb.notifier_call = vmwgfx_pm_notifier; dev_priv->pm_nb.notifier_call = vmwgfx_pm_notifier;
register_pm_notifier(&dev_priv->pm_nb); register_pm_notifier(&dev_priv->pm_nb);
...@@ -1143,15 +1172,10 @@ static void vmw_driver_unload(struct drm_device *dev) ...@@ -1143,15 +1172,10 @@ static void vmw_driver_unload(struct drm_device *dev)
unregister_pm_notifier(&dev_priv->pm_nb); unregister_pm_notifier(&dev_priv->pm_nb);
if (dev_priv->ctx.res_ht_initialized) vmw_sw_context_fini(dev_priv);
vmwgfx_ht_remove(&dev_priv->ctx.res_ht); vmw_fifo_resource_dec(dev_priv);
vfree(dev_priv->ctx.cmd_bounce);
if (dev_priv->enable_fb) { vmw_svga_disable(dev_priv);
vmw_fb_off(dev_priv);
vmw_fb_close(dev_priv);
vmw_fifo_resource_dec(dev_priv);
vmw_svga_disable(dev_priv);
}
vmw_kms_close(dev_priv); vmw_kms_close(dev_priv);
vmw_overlay_close(dev_priv); vmw_overlay_close(dev_priv);
...@@ -1173,8 +1197,6 @@ static void vmw_driver_unload(struct drm_device *dev) ...@@ -1173,8 +1197,6 @@ static void vmw_driver_unload(struct drm_device *dev)
vmw_irq_uninstall(&dev_priv->drm); vmw_irq_uninstall(&dev_priv->drm);
ttm_object_device_release(&dev_priv->tdev); ttm_object_device_release(&dev_priv->tdev);
if (dev_priv->ctx.staged_bindings)
vmw_binding_state_free(dev_priv->ctx.staged_bindings);
for (i = vmw_res_context; i < vmw_res_max; ++i) for (i = vmw_res_context; i < vmw_res_max; ++i)
idr_destroy(&dev_priv->res_idr[i]); idr_destroy(&dev_priv->res_idr[i]);
...@@ -1203,7 +1225,7 @@ static int vmw_driver_open(struct drm_device *dev, struct drm_file *file_priv) ...@@ -1203,7 +1225,7 @@ static int vmw_driver_open(struct drm_device *dev, struct drm_file *file_priv)
if (unlikely(!vmw_fp)) if (unlikely(!vmw_fp))
return ret; return ret;
vmw_fp->tfile = ttm_object_file_init(dev_priv->tdev, 10); vmw_fp->tfile = ttm_object_file_init(dev_priv->tdev);
if (unlikely(vmw_fp->tfile == NULL)) if (unlikely(vmw_fp->tfile == NULL))
goto out_no_tfile; goto out_no_tfile;
...@@ -1291,8 +1313,6 @@ static void vmw_master_drop(struct drm_device *dev, ...@@ -1291,8 +1313,6 @@ static void vmw_master_drop(struct drm_device *dev,
struct vmw_private *dev_priv = vmw_priv(dev); struct vmw_private *dev_priv = vmw_priv(dev);
vmw_kms_legacy_hotspot_clear(dev_priv); vmw_kms_legacy_hotspot_clear(dev_priv);
if (!dev_priv->enable_fb)
vmw_svga_disable(dev_priv);
} }
/** /**
...@@ -1485,25 +1505,19 @@ static int vmw_pm_freeze(struct device *kdev) ...@@ -1485,25 +1505,19 @@ static int vmw_pm_freeze(struct device *kdev)
DRM_ERROR("Failed to freeze modesetting.\n"); DRM_ERROR("Failed to freeze modesetting.\n");
return ret; return ret;
} }
if (dev_priv->enable_fb)
vmw_fb_off(dev_priv);
vmw_execbuf_release_pinned_bo(dev_priv); vmw_execbuf_release_pinned_bo(dev_priv);
vmw_resource_evict_all(dev_priv); vmw_resource_evict_all(dev_priv);
vmw_release_device_early(dev_priv); vmw_release_device_early(dev_priv);
while (ttm_device_swapout(&dev_priv->bdev, &ctx, GFP_KERNEL) > 0); while (ttm_device_swapout(&dev_priv->bdev, &ctx, GFP_KERNEL) > 0);
if (dev_priv->enable_fb) vmw_fifo_resource_dec(dev_priv);
vmw_fifo_resource_dec(dev_priv);
if (atomic_read(&dev_priv->num_fifo_resources) != 0) { if (atomic_read(&dev_priv->num_fifo_resources) != 0) {
DRM_ERROR("Can't hibernate while 3D resources are active.\n"); DRM_ERROR("Can't hibernate while 3D resources are active.\n");
if (dev_priv->enable_fb) vmw_fifo_resource_inc(dev_priv);
vmw_fifo_resource_inc(dev_priv);
WARN_ON(vmw_request_device_late(dev_priv)); WARN_ON(vmw_request_device_late(dev_priv));
dev_priv->suspend_locked = false; dev_priv->suspend_locked = false;
if (dev_priv->suspend_state) if (dev_priv->suspend_state)
vmw_kms_resume(dev); vmw_kms_resume(dev);
if (dev_priv->enable_fb)
vmw_fb_on(dev_priv);
return -EBUSY; return -EBUSY;
} }
...@@ -1523,24 +1537,19 @@ static int vmw_pm_restore(struct device *kdev) ...@@ -1523,24 +1537,19 @@ static int vmw_pm_restore(struct device *kdev)
vmw_detect_version(dev_priv); vmw_detect_version(dev_priv);
if (dev_priv->enable_fb) vmw_fifo_resource_inc(dev_priv);
vmw_fifo_resource_inc(dev_priv);
ret = vmw_request_device(dev_priv); ret = vmw_request_device(dev_priv);
if (ret) if (ret)
return ret; return ret;
if (dev_priv->enable_fb) __vmw_svga_enable(dev_priv);
__vmw_svga_enable(dev_priv);
vmw_fence_fifo_up(dev_priv->fman); vmw_fence_fifo_up(dev_priv->fman);
dev_priv->suspend_locked = false; dev_priv->suspend_locked = false;
if (dev_priv->suspend_state) if (dev_priv->suspend_state)
vmw_kms_resume(&dev_priv->drm); vmw_kms_resume(&dev_priv->drm);
if (dev_priv->enable_fb)
vmw_fb_on(dev_priv);
return 0; return 0;
} }
...@@ -1631,6 +1640,10 @@ static int vmw_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -1631,6 +1640,10 @@ static int vmw_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (ret) if (ret)
goto out_unload; goto out_unload;
vmw_fifo_resource_inc(vmw);
vmw_svga_enable(vmw);
drm_fbdev_generic_setup(&vmw->drm, 0);
vmw_debugfs_gem_init(vmw); vmw_debugfs_gem_init(vmw);
vmw_debugfs_resource_managers_init(vmw); vmw_debugfs_resource_managers_init(vmw);
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <linux/suspend.h> #include <linux/suspend.h>
#include <linux/sync_file.h> #include <linux/sync_file.h>
#include <linux/hashtable.h>
#include <drm/drm_auth.h> #include <drm/drm_auth.h>
#include <drm/drm_device.h> #include <drm/drm_device.h>
...@@ -42,7 +43,6 @@ ...@@ -42,7 +43,6 @@
#include "ttm_object.h" #include "ttm_object.h"
#include "vmwgfx_fence.h" #include "vmwgfx_fence.h"
#include "vmwgfx_hashtab.h"
#include "vmwgfx_reg.h" #include "vmwgfx_reg.h"
#include "vmwgfx_validation.h" #include "vmwgfx_validation.h"
...@@ -62,6 +62,9 @@ ...@@ -62,6 +62,9 @@
#define VMWGFX_MAX_DISPLAYS 16 #define VMWGFX_MAX_DISPLAYS 16
#define VMWGFX_CMD_BOUNCE_INIT_SIZE 32768 #define VMWGFX_CMD_BOUNCE_INIT_SIZE 32768
#define VMWGFX_MIN_INITIAL_WIDTH 1280
#define VMWGFX_MIN_INITIAL_HEIGHT 800
#define VMWGFX_PCI_ID_SVGA2 0x0405 #define VMWGFX_PCI_ID_SVGA2 0x0405
#define VMWGFX_PCI_ID_SVGA3 0x0406 #define VMWGFX_PCI_ID_SVGA3 0x0406
...@@ -93,6 +96,7 @@ ...@@ -93,6 +96,7 @@
#define VMW_RES_STREAM ttm_driver_type2 #define VMW_RES_STREAM ttm_driver_type2
#define VMW_RES_FENCE ttm_driver_type3 #define VMW_RES_FENCE ttm_driver_type3
#define VMW_RES_SHADER ttm_driver_type4 #define VMW_RES_SHADER ttm_driver_type4
#define VMW_RES_HT_ORDER 12
#define MKSSTAT_CAPACITY_LOG2 5U #define MKSSTAT_CAPACITY_LOG2 5U
#define MKSSTAT_CAPACITY (1U << MKSSTAT_CAPACITY_LOG2) #define MKSSTAT_CAPACITY (1U << MKSSTAT_CAPACITY_LOG2)
...@@ -102,6 +106,11 @@ struct vmw_fpriv { ...@@ -102,6 +106,11 @@ struct vmw_fpriv {
bool gb_aware; /* user-space is guest-backed aware */ bool gb_aware; /* user-space is guest-backed aware */
}; };
struct vmwgfx_hash_item {
struct hlist_node head;
unsigned long key;
};
/** /**
* struct vmw_buffer_object - TTM buffer object with vmwgfx additions * struct vmw_buffer_object - TTM buffer object with vmwgfx additions
* @base: The TTM buffer object * @base: The TTM buffer object
...@@ -425,8 +434,7 @@ struct vmw_ctx_validation_info; ...@@ -425,8 +434,7 @@ struct vmw_ctx_validation_info;
* @ctx: The validation context * @ctx: The validation context
*/ */
struct vmw_sw_context{ struct vmw_sw_context{
struct vmwgfx_open_hash res_ht; DECLARE_HASHTABLE(res_ht, VMW_RES_HT_ORDER);
bool res_ht_initialized;
bool kernel; bool kernel;
struct vmw_fpriv *fp; struct vmw_fpriv *fp;
struct drm_file *filp; struct drm_file *filp;
...@@ -546,7 +554,6 @@ struct vmw_private { ...@@ -546,7 +554,6 @@ struct vmw_private {
* Framebuffer info. * Framebuffer info.
*/ */
void *fb_info;
enum vmw_display_unit_type active_display_unit; enum vmw_display_unit_type active_display_unit;
struct vmw_legacy_display *ldu_priv; struct vmw_legacy_display *ldu_priv;
struct vmw_overlay *overlay_priv; struct vmw_overlay *overlay_priv;
...@@ -605,8 +612,6 @@ struct vmw_private { ...@@ -605,8 +612,6 @@ struct vmw_private {
struct mutex cmdbuf_mutex; struct mutex cmdbuf_mutex;
struct mutex binding_mutex; struct mutex binding_mutex;
bool enable_fb;
/** /**
* PM management. * PM management.
*/ */
...@@ -1184,35 +1189,6 @@ extern void vmw_generic_waiter_add(struct vmw_private *dev_priv, u32 flag, ...@@ -1184,35 +1189,6 @@ extern void vmw_generic_waiter_add(struct vmw_private *dev_priv, u32 flag,
extern void vmw_generic_waiter_remove(struct vmw_private *dev_priv, extern void vmw_generic_waiter_remove(struct vmw_private *dev_priv,
u32 flag, int *waiter_count); u32 flag, int *waiter_count);
/**
* Kernel framebuffer - vmwgfx_fb.c
*/
#ifdef CONFIG_DRM_FBDEV_EMULATION
int vmw_fb_init(struct vmw_private *vmw_priv);
int vmw_fb_close(struct vmw_private *dev_priv);
int vmw_fb_off(struct vmw_private *vmw_priv);
int vmw_fb_on(struct vmw_private *vmw_priv);
#else
static inline int vmw_fb_init(struct vmw_private *vmw_priv)
{
return 0;
}
static inline int vmw_fb_close(struct vmw_private *dev_priv)
{
return 0;
}
static inline int vmw_fb_off(struct vmw_private *vmw_priv)
{
return 0;
}
static inline int vmw_fb_on(struct vmw_private *vmw_priv)
{
return 0;
}
#endif
/** /**
* Kernel modesetting - vmwgfx_kms.c * Kernel modesetting - vmwgfx_kms.c
*/ */
...@@ -1232,9 +1208,6 @@ int vmw_kms_write_svga(struct vmw_private *vmw_priv, ...@@ -1232,9 +1208,6 @@ int vmw_kms_write_svga(struct vmw_private *vmw_priv,
bool vmw_kms_validate_mode_vram(struct vmw_private *dev_priv, bool vmw_kms_validate_mode_vram(struct vmw_private *dev_priv,
uint32_t pitch, uint32_t pitch,
uint32_t height); uint32_t height);
u32 vmw_get_vblank_counter(struct drm_crtc *crtc);
int vmw_enable_vblank(struct drm_crtc *crtc);
void vmw_disable_vblank(struct drm_crtc *crtc);
int vmw_kms_present(struct vmw_private *dev_priv, int vmw_kms_present(struct vmw_private *dev_priv,
struct drm_file *file_priv, struct drm_file *file_priv,
struct vmw_framebuffer *vfb, struct vmw_framebuffer *vfb,
......
// SPDX-License-Identifier: GPL-2.0 OR MIT // SPDX-License-Identifier: GPL-2.0 OR MIT
/************************************************************************** /**************************************************************************
* *
* Copyright 2009 - 2015 VMware, Inc., Palo Alto, CA., USA * Copyright 2009 - 2022 VMware, Inc., Palo Alto, CA., USA
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the * copy of this software and associated documentation files (the
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
* *
**************************************************************************/ **************************************************************************/
#include <linux/sync_file.h> #include <linux/sync_file.h>
#include <linux/hashtable.h>
#include "vmwgfx_drv.h" #include "vmwgfx_drv.h"
#include "vmwgfx_reg.h" #include "vmwgfx_reg.h"
...@@ -34,7 +35,6 @@ ...@@ -34,7 +35,6 @@
#include "vmwgfx_binding.h" #include "vmwgfx_binding.h"
#include "vmwgfx_mksstat.h" #include "vmwgfx_mksstat.h"
#define VMW_RES_HT_ORDER 12
/* /*
* Helper macro to get dx_ctx_node if available otherwise print an error * Helper macro to get dx_ctx_node if available otherwise print an error
...@@ -3869,7 +3869,6 @@ int vmw_execbuf_fence_commands(struct drm_file *file_priv, ...@@ -3869,7 +3869,6 @@ int vmw_execbuf_fence_commands(struct drm_file *file_priv,
* @fence: Pointer to the fenc object. * @fence: Pointer to the fenc object.
* @fence_handle: User-space fence handle. * @fence_handle: User-space fence handle.
* @out_fence_fd: exported file descriptor for the fence. -1 if not used * @out_fence_fd: exported file descriptor for the fence. -1 if not used
* @sync_file: Only used to clean up in case of an error in this function.
* *
* This function copies fence information to user-space. If copying fails, the * This function copies fence information to user-space. If copying fails, the
* user-space struct drm_vmw_fence_rep::error member is hopefully left * user-space struct drm_vmw_fence_rep::error member is hopefully left
...@@ -4101,7 +4100,7 @@ int vmw_execbuf_process(struct drm_file *file_priv, ...@@ -4101,7 +4100,7 @@ int vmw_execbuf_process(struct drm_file *file_priv,
int ret; int ret;
int32_t out_fence_fd = -1; int32_t out_fence_fd = -1;
struct sync_file *sync_file = NULL; struct sync_file *sync_file = NULL;
DECLARE_VAL_CONTEXT(val_ctx, &sw_context->res_ht, 1); DECLARE_VAL_CONTEXT(val_ctx, sw_context, 1);
if (flags & DRM_VMW_EXECBUF_FLAG_EXPORT_FENCE_FD) { if (flags & DRM_VMW_EXECBUF_FLAG_EXPORT_FENCE_FD) {
out_fence_fd = get_unused_fd_flags(O_CLOEXEC); out_fence_fd = get_unused_fd_flags(O_CLOEXEC);
...@@ -4164,14 +4163,6 @@ int vmw_execbuf_process(struct drm_file *file_priv, ...@@ -4164,14 +4163,6 @@ int vmw_execbuf_process(struct drm_file *file_priv,
if (sw_context->staged_bindings) if (sw_context->staged_bindings)
vmw_binding_state_reset(sw_context->staged_bindings); vmw_binding_state_reset(sw_context->staged_bindings);
if (!sw_context->res_ht_initialized) {
ret = vmwgfx_ht_create(&sw_context->res_ht, VMW_RES_HT_ORDER);
if (unlikely(ret != 0))
goto out_unlock;
sw_context->res_ht_initialized = true;
}
INIT_LIST_HEAD(&sw_context->staged_cmd_res); INIT_LIST_HEAD(&sw_context->staged_cmd_res);
sw_context->ctx = &val_ctx; sw_context->ctx = &val_ctx;
ret = vmw_execbuf_tie_context(dev_priv, sw_context, dx_context_handle); ret = vmw_execbuf_tie_context(dev_priv, sw_context, dx_context_handle);
......
This diff is collapsed.
/*
* Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND. USA.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* Simple open hash tab implementation.
*
* Authors:
* Thomas Hellström <thomas-at-tungstengraphics-dot-com>
*/
#include <linux/export.h>
#include <linux/hash.h>
#include <linux/mm.h>
#include <linux/rculist.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <drm/drm_print.h>
#include "vmwgfx_hashtab.h"
int vmwgfx_ht_create(struct vmwgfx_open_hash *ht, unsigned int order)
{
unsigned int size = 1 << order;
ht->order = order;
ht->table = NULL;
if (size <= PAGE_SIZE / sizeof(*ht->table))
ht->table = kcalloc(size, sizeof(*ht->table), GFP_KERNEL);
else
ht->table = vzalloc(array_size(size, sizeof(*ht->table)));
if (!ht->table) {
DRM_ERROR("Out of memory for hash table\n");
return -ENOMEM;
}
return 0;
}
void vmwgfx_ht_verbose_list(struct vmwgfx_open_hash *ht, unsigned long key)
{
struct vmwgfx_hash_item *entry;
struct hlist_head *h_list;
unsigned int hashed_key;
int count = 0;
hashed_key = hash_long(key, ht->order);
DRM_DEBUG("Key is 0x%08lx, Hashed key is 0x%08x\n", key, hashed_key);
h_list = &ht->table[hashed_key];
hlist_for_each_entry(entry, h_list, head)
DRM_DEBUG("count %d, key: 0x%08lx\n", count++, entry->key);
}
static struct hlist_node *vmwgfx_ht_find_key(struct vmwgfx_open_hash *ht, unsigned long key)
{
struct vmwgfx_hash_item *entry;
struct hlist_head *h_list;
unsigned int hashed_key;
hashed_key = hash_long(key, ht->order);
h_list = &ht->table[hashed_key];
hlist_for_each_entry(entry, h_list, head) {
if (entry->key == key)
return &entry->head;
if (entry->key > key)
break;
}
return NULL;
}
static struct hlist_node *vmwgfx_ht_find_key_rcu(struct vmwgfx_open_hash *ht, unsigned long key)
{
struct vmwgfx_hash_item *entry;
struct hlist_head *h_list;
unsigned int hashed_key;
hashed_key = hash_long(key, ht->order);
h_list = &ht->table[hashed_key];
hlist_for_each_entry_rcu(entry, h_list, head) {
if (entry->key == key)
return &entry->head;
if (entry->key > key)
break;
}
return NULL;
}
int vmwgfx_ht_insert_item(struct vmwgfx_open_hash *ht, struct vmwgfx_hash_item *item)
{
struct vmwgfx_hash_item *entry;
struct hlist_head *h_list;
struct hlist_node *parent;
unsigned int hashed_key;
unsigned long key = item->key;
hashed_key = hash_long(key, ht->order);
h_list = &ht->table[hashed_key];
parent = NULL;
hlist_for_each_entry(entry, h_list, head) {
if (entry->key == key)
return -EINVAL;
if (entry->key > key)
break;
parent = &entry->head;
}
if (parent)
hlist_add_behind_rcu(&item->head, parent);
else
hlist_add_head_rcu(&item->head, h_list);
return 0;
}
/*
* Just insert an item and return any "bits" bit key that hasn't been
* used before.
*/
int vmwgfx_ht_just_insert_please(struct vmwgfx_open_hash *ht, struct vmwgfx_hash_item *item,
unsigned long seed, int bits, int shift,
unsigned long add)
{
int ret;
unsigned long mask = (1UL << bits) - 1;
unsigned long first, unshifted_key;
unshifted_key = hash_long(seed, bits);
first = unshifted_key;
do {
item->key = (unshifted_key << shift) + add;
ret = vmwgfx_ht_insert_item(ht, item);
if (ret)
unshifted_key = (unshifted_key + 1) & mask;
} while (ret && (unshifted_key != first));
if (ret) {
DRM_ERROR("Available key bit space exhausted\n");
return -EINVAL;
}
return 0;
}
int vmwgfx_ht_find_item(struct vmwgfx_open_hash *ht, unsigned long key,
struct vmwgfx_hash_item **item)
{
struct hlist_node *list;
list = vmwgfx_ht_find_key_rcu(ht, key);
if (!list)
return -EINVAL;
*item = hlist_entry(list, struct vmwgfx_hash_item, head);
return 0;
}
int vmwgfx_ht_remove_key(struct vmwgfx_open_hash *ht, unsigned long key)
{
struct hlist_node *list;
list = vmwgfx_ht_find_key(ht, key);
if (list) {
hlist_del_init_rcu(list);
return 0;
}
return -EINVAL;
}
int vmwgfx_ht_remove_item(struct vmwgfx_open_hash *ht, struct vmwgfx_hash_item *item)
{
hlist_del_init_rcu(&item->head);
return 0;
}
void vmwgfx_ht_remove(struct vmwgfx_open_hash *ht)
{
if (ht->table) {
kvfree(ht->table);
ht->table = NULL;
}
}
/*
* Copyright 2006 Tungsten Graphics, Inc., Bismack, ND. USA.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* Simple open hash tab implementation.
*
* Authors:
* Thomas Hellström <thomas-at-tungstengraphics-dot-com>
*/
/*
* TODO: Replace this hashtable with Linux' generic implementation
* from <linux/hashtable.h>.
*/
#ifndef VMWGFX_HASHTAB_H
#define VMWGFX_HASHTAB_H
#include <linux/list.h>
#define drm_hash_entry(_ptr, _type, _member) container_of(_ptr, _type, _member)
struct vmwgfx_hash_item {
struct hlist_node head;
unsigned long key;
};
struct vmwgfx_open_hash {
struct hlist_head *table;
u8 order;
};
int vmwgfx_ht_create(struct vmwgfx_open_hash *ht, unsigned int order);
int vmwgfx_ht_insert_item(struct vmwgfx_open_hash *ht, struct vmwgfx_hash_item *item);
int vmwgfx_ht_just_insert_please(struct vmwgfx_open_hash *ht, struct vmwgfx_hash_item *item,
unsigned long seed, int bits, int shift,
unsigned long add);
int vmwgfx_ht_find_item(struct vmwgfx_open_hash *ht, unsigned long key,
struct vmwgfx_hash_item **item);
void vmwgfx_ht_verbose_list(struct vmwgfx_open_hash *ht, unsigned long key);
int vmwgfx_ht_remove_key(struct vmwgfx_open_hash *ht, unsigned long key);
int vmwgfx_ht_remove_item(struct vmwgfx_open_hash *ht, struct vmwgfx_hash_item *item);
void vmwgfx_ht_remove(struct vmwgfx_open_hash *ht);
/*
* RCU-safe interface
*
* The user of this API needs to make sure that two or more instances of the
* hash table manipulation functions are never run simultaneously.
* The lookup function vmwgfx_ht_find_item_rcu may, however, run simultaneously
* with any of the manipulation functions as long as it's called from within
* an RCU read-locked section.
*/
#define vmwgfx_ht_insert_item_rcu vmwgfx_ht_insert_item
#define vmwgfx_ht_just_insert_please_rcu vmwgfx_ht_just_insert_please
#define vmwgfx_ht_remove_key_rcu vmwgfx_ht_remove_key
#define vmwgfx_ht_remove_item_rcu vmwgfx_ht_remove_item
#define vmwgfx_ht_find_item_rcu vmwgfx_ht_find_item
#endif
This diff is collapsed.
...@@ -272,6 +272,14 @@ struct vmw_crtc_state { ...@@ -272,6 +272,14 @@ struct vmw_crtc_state {
struct drm_crtc_state base; struct drm_crtc_state base;
}; };
struct vmw_cursor_plane_state {
struct ttm_buffer_object *bo;
struct ttm_bo_kmap_obj map;
bool mapped;
s32 hotspot_x;
s32 hotspot_y;
};
/** /**
* Derived class for plane state object * Derived class for plane state object
* *
...@@ -295,13 +303,8 @@ struct vmw_plane_state { ...@@ -295,13 +303,8 @@ struct vmw_plane_state {
/* For CPU Blit */ /* For CPU Blit */
unsigned int cpp; unsigned int cpp;
/* CursorMob flipping index; -1 if cursor mobs not used */ bool surf_mapped;
unsigned int cursor_mob_idx; struct vmw_cursor_plane_state cursor;
/* Currently-active CursorMob */
struct ttm_buffer_object *cm_bo;
/* CursorMob kmap_obj; expected valid at cursor_plane_atomic_update
IFF currently-active CursorMob above is valid */
struct ttm_bo_kmap_obj cm_map;
}; };
...@@ -338,11 +341,12 @@ struct vmw_connector_state { ...@@ -338,11 +341,12 @@ struct vmw_connector_state {
* Derived class for cursor plane object * Derived class for cursor plane object
* *
* @base DRM plane object * @base DRM plane object
* @cursor_mob array of two MOBs for CursorMob flipping * @cursor.cursor_mobs Cursor mobs available for re-use
*/ */
struct vmw_cursor_plane { struct vmw_cursor_plane {
struct drm_plane base; struct drm_plane base;
struct ttm_buffer_object *cursor_mob[2];
struct ttm_buffer_object *cursor_mobs[3];
}; };
/** /**
...@@ -458,13 +462,6 @@ vmw_kms_new_framebuffer(struct vmw_private *dev_priv, ...@@ -458,13 +462,6 @@ vmw_kms_new_framebuffer(struct vmw_private *dev_priv,
struct vmw_surface *surface, struct vmw_surface *surface,
bool only_2d, bool only_2d,
const struct drm_mode_fb_cmd2 *mode_cmd); const struct drm_mode_fb_cmd2 *mode_cmd);
int vmw_kms_fbdev_init_data(struct vmw_private *dev_priv,
unsigned unit,
u32 max_width,
u32 max_height,
struct drm_connector **p_con,
struct drm_crtc **p_crtc,
struct drm_display_mode **p_mode);
void vmw_guess_mode_timing(struct drm_display_mode *mode); void vmw_guess_mode_timing(struct drm_display_mode *mode);
void vmw_kms_update_implicit_fb(struct vmw_private *dev_priv); void vmw_kms_update_implicit_fb(struct vmw_private *dev_priv);
void vmw_kms_create_implicit_placement_property(struct vmw_private *dev_priv); void vmw_kms_create_implicit_placement_property(struct vmw_private *dev_priv);
...@@ -472,8 +469,6 @@ void vmw_kms_create_implicit_placement_property(struct vmw_private *dev_priv); ...@@ -472,8 +469,6 @@ void vmw_kms_create_implicit_placement_property(struct vmw_private *dev_priv);
/* Universal Plane Helpers */ /* Universal Plane Helpers */
void vmw_du_primary_plane_destroy(struct drm_plane *plane); void vmw_du_primary_plane_destroy(struct drm_plane *plane);
void vmw_du_cursor_plane_destroy(struct drm_plane *plane); void vmw_du_cursor_plane_destroy(struct drm_plane *plane);
int vmw_du_create_cursor_mob_array(struct vmw_cursor_plane *vcp);
void vmw_du_destroy_cursor_mob_array(struct vmw_cursor_plane *vcp);
/* Atomic Helpers */ /* Atomic Helpers */
int vmw_du_primary_plane_atomic_check(struct drm_plane *plane, int vmw_du_primary_plane_atomic_check(struct drm_plane *plane,
......
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
#include <drm/drm_atomic.h> #include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h> #include <drm/drm_atomic_helper.h>
#include <drm/drm_fourcc.h> #include <drm/drm_fourcc.h>
#include <drm/drm_vblank.h>
#include "vmwgfx_kms.h" #include "vmwgfx_kms.h"
...@@ -235,9 +234,6 @@ static const struct drm_crtc_funcs vmw_legacy_crtc_funcs = { ...@@ -235,9 +234,6 @@ static const struct drm_crtc_funcs vmw_legacy_crtc_funcs = {
.atomic_duplicate_state = vmw_du_crtc_duplicate_state, .atomic_duplicate_state = vmw_du_crtc_duplicate_state,
.atomic_destroy_state = vmw_du_crtc_destroy_state, .atomic_destroy_state = vmw_du_crtc_destroy_state,
.set_config = drm_atomic_helper_set_config, .set_config = drm_atomic_helper_set_config,
.get_vblank_counter = vmw_get_vblank_counter,
.enable_vblank = vmw_enable_vblank,
.disable_vblank = vmw_disable_vblank,
}; };
...@@ -507,10 +503,6 @@ int vmw_kms_ldu_init_display(struct vmw_private *dev_priv) ...@@ -507,10 +503,6 @@ int vmw_kms_ldu_init_display(struct vmw_private *dev_priv)
dev_priv->ldu_priv->last_num_active = 0; dev_priv->ldu_priv->last_num_active = 0;
dev_priv->ldu_priv->fb = NULL; dev_priv->ldu_priv->fb = NULL;
ret = drm_vblank_init(dev, num_display_units);
if (ret != 0)
goto err_free;
vmw_kms_create_implicit_placement_property(dev_priv); vmw_kms_create_implicit_placement_property(dev_priv);
for (i = 0; i < num_display_units; ++i) { for (i = 0; i < num_display_units; ++i) {
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#define _VMWGFX_MKSSTAT_H_ #define _VMWGFX_MKSSTAT_H_
#include <asm/page.h> #include <asm/page.h>
#include <linux/kconfig.h>
/* Reservation marker for mksstat pid's */ /* Reservation marker for mksstat pid's */
#define MKSSTAT_PID_RESERVED -1 #define MKSSTAT_PID_RESERVED -1
...@@ -41,6 +42,7 @@ ...@@ -41,6 +42,7 @@
typedef enum { typedef enum {
MKSSTAT_KERN_EXECBUF, /* vmw_execbuf_ioctl */ MKSSTAT_KERN_EXECBUF, /* vmw_execbuf_ioctl */
MKSSTAT_KERN_COTABLE_RESIZE,
MKSSTAT_KERN_COUNT /* Reserved entry; always last */ MKSSTAT_KERN_COUNT /* Reserved entry; always last */
} mksstat_kern_stats_t; } mksstat_kern_stats_t;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -1550,12 +1550,20 @@ struct drm_connector { ...@@ -1550,12 +1550,20 @@ struct drm_connector {
struct drm_cmdline_mode cmdline_mode; struct drm_cmdline_mode cmdline_mode;
/** @force: a DRM_FORCE_<foo> state for forced mode sets */ /** @force: a DRM_FORCE_<foo> state for forced mode sets */
enum drm_connector_force force; enum drm_connector_force force;
/**
* @edid_override: Override EDID set via debugfs.
*
* Do not modify or access outside of the drm_edid_override_* family of
* functions.
*/
const struct drm_edid *edid_override;
/** /**
* @override_edid: has the EDID been overwritten through debugfs for * @edid_override_mutex: Protect access to edid_override.
* testing? Do not modify outside of drm_edid_override_set() and
* drm_edid_override_reset().
*/ */
bool override_edid; struct mutex edid_override_mutex;
/** @epoch_counter: used to detect any other changes in connector, besides status */ /** @epoch_counter: used to detect any other changes in connector, besides status */
u64 epoch_counter; u64 epoch_counter;
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment