* [PATCH v7 05/10] drm/dp_mst: Make drm_dp_mst_topology_state subclassable
2018-04-11 22:54 [PATCH v7 00/10] drm/i915: Implement proper fallback training for MST Lyude Paul
@ 2018-04-11 22:54 ` Lyude Paul
0 siblings, 0 replies; 2+ messages in thread
From: Lyude Paul @ 2018-04-11 22:54 UTC (permalink / raw)
To: intel-gfx
Cc: Manasi Navare, Ville Syrjälä, Alex Deucher,
Christian König, David (ChunMing) Zhou, David Airlie,
Gustavo Padovan, Maarten Lankhorst, Sean Paul, Jani Nikula,
Joonas Lahtinen, Rodrigo Vivi, Ben Skeggs, Harry Wentland,
Andrey Grodzovsky, Tony Cheng, Leo (Sunpeng) Li
This is useful for drivers (which will probably be all of them soon)
which need to track state that is exclusive to the topology, and not a
specific connector on said topology. This includes things such as the
link rate and lane count that are shared by all of the connectors on the
topology.
Signed-off-by: Lyude Paul <lyude@redhat.com>
Cc: Manasi Navare <manasi.d.navare@intel.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
V7:
- Fix CHECKPATCH errors
Signed-off-by: Lyude Paul <lyude@redhat.com>
---
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 14 +++-
.../amd/display/amdgpu_dm/amdgpu_dm_mst_types.c | 46 ++++++++---
.../amd/display/amdgpu_dm/amdgpu_dm_mst_types.h | 4 +-
drivers/gpu/drm/drm_dp_mst_topology.c | 95 +++++++++++++++++-----
drivers/gpu/drm/i915/intel_dp_mst.c | 13 ++-
drivers/gpu/drm/nouveau/nv50_display.c | 17 +++-
drivers/gpu/drm/radeon/radeon_dp_mst.c | 13 ++-
include/drm/drm_dp_mst_helper.h | 8 ++
8 files changed, 173 insertions(+), 37 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index e42a28e3adc5..2c3660c36732 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -3626,9 +3626,17 @@ static int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm,
drm_connector_register(&aconnector->base);
- if (connector_type == DRM_MODE_CONNECTOR_DisplayPort
- || connector_type == DRM_MODE_CONNECTOR_eDP)
- amdgpu_dm_initialize_dp_connector(dm, aconnector);
+ if (connector_type == DRM_MODE_CONNECTOR_DisplayPort ||
+ connector_type == DRM_MODE_CONNECTOR_eDP) {
+ res = amdgpu_dm_initialize_dp_connector(dm, aconnector);
+ if (res) {
+ drm_connector_unregister(&aconnector->base);
+ drm_connector_cleanup(&aconnector->base);
+ aconnector->connector_id = -1;
+
+ goto out_free;
+ }
+ }
#if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) ||\
defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
index 8291d74f26bc..dcaa92d12cbc 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
@@ -475,22 +475,48 @@ static const struct drm_dp_mst_topology_cbs dm_mst_cbs = {
.register_connector = dm_dp_mst_register_connector
};
-void amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm,
- struct amdgpu_dm_connector *aconnector)
+static const struct drm_private_state_funcs dm_mst_state_funcs = {
+ .atomic_duplicate_state = drm_atomic_dp_mst_duplicate_topology_state,
+ .atomic_destroy_state = drm_atomic_dp_mst_destroy_topology_state,
+};
+
+int amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm,
+ struct amdgpu_dm_connector *aconnector)
{
+ struct drm_dp_mst_topology_state *state =
+ kzalloc(sizeof(*state), GFP_KERNEL);
+ int ret = 0;
+
+ if (!state)
+ return -ENOMEM;
+
aconnector->dm_dp_aux.aux.name = "dmdc";
aconnector->dm_dp_aux.aux.dev = dm->adev->dev;
aconnector->dm_dp_aux.aux.transfer = dm_dp_aux_transfer;
aconnector->dm_dp_aux.ddc_service = aconnector->dc_link->ddc;
- drm_dp_aux_register(&aconnector->dm_dp_aux.aux);
+ ret = drm_dp_aux_register(&aconnector->dm_dp_aux.aux);
+ if (ret)
+ goto err_aux;
+
aconnector->mst_mgr.cbs = &dm_mst_cbs;
- drm_dp_mst_topology_mgr_init(
- &aconnector->mst_mgr,
- dm->adev->ddev,
- &aconnector->dm_dp_aux.aux,
- 16,
- 4,
- aconnector->connector_id);
+ aconnector->mst_mgr.funcs = &dm_mst_state_funcs;
+ ret = drm_dp_mst_topology_mgr_init(&aconnector->mst_mgr,
+ state,
+ dm->adev->ddev,
+ &aconnector->dm_dp_aux.aux,
+ 16,
+ 4,
+ aconnector->connector_id);
+ if (ret)
+ goto err_mst;
+
+ return 0;
+
+err_mst:
+ drm_dp_aux_unregister(&aconnector->dm_dp_aux.aux);
+err_aux:
+ kfree(state);
+ return ret;
}
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
index 8cf51da26657..d28fb456d2d5 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
@@ -29,8 +29,8 @@
struct amdgpu_display_manager;
struct amdgpu_dm_connector;
-void amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm,
- struct amdgpu_dm_connector *aconnector);
+int amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm,
+ struct amdgpu_dm_connector *aconnector);
void dm_dp_mst_dc_sink_create(struct drm_connector *connector);
#endif
diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c
index ba67f1782a04..fbd7888ebca8 100644
--- a/drivers/gpu/drm/drm_dp_mst_topology.c
+++ b/drivers/gpu/drm/drm_dp_mst_topology.c
@@ -3100,33 +3100,90 @@ static void drm_dp_destroy_connector_work(struct work_struct *work)
(*mgr->cbs->hotplug)(mgr);
}
-static struct drm_private_state *
-drm_dp_mst_duplicate_state(struct drm_private_obj *obj)
+/**
+ * drm_atomic_dp_mst_duplicate_topology_state - default
+ * drm_dp_mst_topology_state duplicate handler
+ *
+ * For drivers which don't yet subclass drm_dp_mst_topology_state
+ *
+ * RETURNS: the duplicated state on success, or an error code embedded into a
+ * pointer value otherwise.
+ */
+struct drm_private_state *
+drm_atomic_dp_mst_duplicate_topology_state(struct drm_private_obj *obj)
{
+ struct drm_dp_mst_topology_mgr *mgr = to_dp_mst_topology_mgr(obj);
struct drm_dp_mst_topology_state *state;
+ int ret;
state = kmemdup(obj->state, sizeof(*state), GFP_KERNEL);
if (!state)
return NULL;
- __drm_atomic_helper_private_obj_duplicate_state(obj, &state->base);
+ ret = __drm_atomic_dp_mst_duplicate_topology_state(mgr, state);
+ if (ret) {
+ kfree(state);
+ return NULL;
+ }
return &state->base;
}
+EXPORT_SYMBOL(drm_atomic_dp_mst_duplicate_topology_state);
+
+/**
+ * __drm_atomic_dp_mst_duplicate_topology_state - default
+ * drm_dp_mst_topology_state duplicate hook
+ *
+ * Copies atomic state from an MST topology's current state. This is useful
+ * for drivers that subclass the MST topology state.
+ *
+ * RETURNS: 0 on success, negative error code on failure.
+ */
+int
+__drm_atomic_dp_mst_duplicate_topology_state(struct drm_dp_mst_topology_mgr *mgr,
+ struct drm_dp_mst_topology_state *state)
+{
+ struct drm_private_obj *obj = &mgr->base;
+
+ memcpy(state, obj->state, sizeof(*state));
+
+ __drm_atomic_helper_private_obj_duplicate_state(&mgr->base,
+ &state->base);
+ return 0;
+}
+EXPORT_SYMBOL(__drm_atomic_dp_mst_duplicate_topology_state);
-static void drm_dp_mst_destroy_state(struct drm_private_obj *obj,
- struct drm_private_state *state)
+/**
+ * drm_atomic_dp_mst_destroy_topology_state - default
+ * drm_dp_mst_topology_state destroy handler
+ *
+ * For drivers which don't yet subclass drm_dp_mst_topology_state.
+ */
+void
+drm_atomic_dp_mst_destroy_topology_state(struct drm_private_obj *obj,
+ struct drm_private_state *state)
{
struct drm_dp_mst_topology_state *mst_state =
to_dp_mst_topology_state(state);
+ __drm_atomic_dp_mst_destroy_topology_state(mst_state);
+
kfree(mst_state);
}
+EXPORT_SYMBOL(drm_atomic_dp_mst_destroy_topology_state);
-static const struct drm_private_state_funcs mst_state_funcs = {
- .atomic_duplicate_state = drm_dp_mst_duplicate_state,
- .atomic_destroy_state = drm_dp_mst_destroy_state,
-};
+/**
+ * __drm_atomic_dp_mst_destroy_topology_state - default
+ * drm_dp_mst_topology_state destroy hook
+ *
+ * Frees the resources associated with the given drm_dp_mst_topology_state.
+ * This is useful for drivers that subclass the MST topology state.
+ */
+void
+__drm_atomic_dp_mst_destroy_topology_state(struct drm_dp_mst_topology_state *state)
+{
+}
+EXPORT_SYMBOL(__drm_atomic_dp_mst_destroy_topology_state);
/**
* drm_atomic_dp_mst_get_topology_state: get MST topology state
@@ -3157,21 +3214,25 @@ EXPORT_SYMBOL(drm_atomic_dp_mst_get_topology_state);
/**
* drm_dp_mst_topology_mgr_init - initialise a topology manager
* @mgr: manager struct to initialise
+ * @state: atomic topology state to init, allocated by the driver
* @dev: device providing this structure - for i2c addition.
* @aux: DP helper aux channel to talk to this device
* @max_dpcd_transaction_bytes: hw specific DPCD transaction limit
* @max_payloads: maximum number of payloads this GPU can source
* @conn_base_id: the connector object ID the MST device is connected to.
*
+ * Note that this function doesn't take care of allocating the atomic MST
+ * state, this must be handled by the caller before calling
+ * drm_dp_mst_topology_mgr_init().
+ *
* Return 0 for success, or negative error code on failure
*/
int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr,
+ struct drm_dp_mst_topology_state *state,
struct drm_device *dev, struct drm_dp_aux *aux,
int max_dpcd_transaction_bytes,
int max_payloads, int conn_base_id)
{
- struct drm_dp_mst_topology_state *mst_state;
-
mutex_init(&mgr->lock);
mutex_init(&mgr->qlock);
mutex_init(&mgr->payload_lock);
@@ -3200,18 +3261,14 @@ int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr,
if (test_calc_pbn_mode() < 0)
DRM_ERROR("MST PBN self-test failed\n");
- mst_state = kzalloc(sizeof(*mst_state), GFP_KERNEL);
- if (mst_state == NULL)
- return -ENOMEM;
-
- mst_state->mgr = mgr;
+ state->mgr = mgr;
/* max. time slots - one slot for MTP header */
- mst_state->avail_slots = 63;
+ state->avail_slots = 63;
drm_atomic_private_obj_init(&mgr->base,
- &mst_state->base,
- &mst_state_funcs);
+ &state->base,
+ mgr->funcs);
return 0;
}
diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c
index 9e6956c08688..cf844cfd2bb0 100644
--- a/drivers/gpu/drm/i915/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/intel_dp_mst.c
@@ -587,19 +587,30 @@ intel_dp_create_fake_mst_encoders(struct intel_digital_port *intel_dig_port)
return true;
}
+static const struct drm_private_state_funcs mst_state_funcs = {
+ .atomic_destroy_state = drm_atomic_dp_mst_destroy_topology_state,
+ .atomic_duplicate_state = drm_atomic_dp_mst_duplicate_topology_state,
+};
+
int
intel_dp_mst_encoder_init(struct intel_digital_port *intel_dig_port, int conn_base_id)
{
struct intel_dp *intel_dp = &intel_dig_port->dp;
+ struct drm_dp_mst_topology_state *mst_state;
struct drm_device *dev = intel_dig_port->base.base.dev;
int ret;
+ mst_state = kzalloc(sizeof(*mst_state), GFP_KERNEL);
+ if (!mst_state)
+ return -ENOMEM;
+
intel_dp->can_mst = true;
intel_dp->mst_mgr.cbs = &mst_cbs;
+ intel_dp->mst_mgr.funcs = &mst_state_funcs;
/* create encoders */
intel_dp_create_fake_mst_encoders(intel_dig_port);
- ret = drm_dp_mst_topology_mgr_init(&intel_dp->mst_mgr, dev,
+ ret = drm_dp_mst_topology_mgr_init(&intel_dp->mst_mgr, mst_state, dev,
&intel_dp->aux, 16, 3, conn_base_id);
if (ret) {
intel_dp->can_mst = false;
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index 8bd739cfd00d..200db30a9c43 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -3310,6 +3310,12 @@ nv50_mstm = {
.hotplug = nv50_mstm_hotplug,
};
+static const struct drm_private_state_funcs
+nv50_mst_state_funcs = {
+ .atomic_duplicate_state = drm_atomic_dp_mst_duplicate_topology_state,
+ .atomic_destroy_state = drm_atomic_dp_mst_destroy_topology_state,
+};
+
void
nv50_mstm_service(struct nv50_mstm *mstm)
{
@@ -3438,6 +3444,7 @@ nv50_mstm_new(struct nouveau_encoder *outp, struct drm_dp_aux *aux, int aux_max,
{
const int max_payloads = hweight8(outp->dcb->heads);
struct drm_device *dev = outp->base.base.dev;
+ struct drm_dp_mst_topology_state *state;
struct nv50_mstm *mstm;
int ret, i;
u8 dpcd;
@@ -3454,10 +3461,18 @@ nv50_mstm_new(struct nouveau_encoder *outp, struct drm_dp_aux *aux, int aux_max,
if (!(mstm = *pmstm = kzalloc(sizeof(*mstm), GFP_KERNEL)))
return -ENOMEM;
+
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (!state) {
+ kfree(mstm);
+ return -ENOMEM;
+ }
mstm->outp = outp;
mstm->mgr.cbs = &nv50_mstm;
+ mstm->mgr.funcs = &nv50_mst_state_funcs;
- ret = drm_dp_mst_topology_mgr_init(&mstm->mgr, dev, aux, aux_max,
+ ret = drm_dp_mst_topology_mgr_init(&mstm->mgr, state, dev,
+ aux, aux_max,
max_payloads, conn_base_id);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/radeon/radeon_dp_mst.c b/drivers/gpu/drm/radeon/radeon_dp_mst.c
index cd8a3ee16649..6edf52404256 100644
--- a/drivers/gpu/drm/radeon/radeon_dp_mst.c
+++ b/drivers/gpu/drm/radeon/radeon_dp_mst.c
@@ -335,6 +335,11 @@ static const struct drm_dp_mst_topology_cbs mst_cbs = {
.hotplug = radeon_dp_mst_hotplug,
};
+static const struct drm_private_state_funcs mst_state_funcs = {
+ .atomic_duplicate_state = drm_atomic_dp_mst_duplicate_topology_state,
+ .atomic_destroy_state = drm_atomic_dp_mst_destroy_topology_state,
+};
+
static struct
radeon_connector *radeon_mst_find_connector(struct drm_encoder *encoder)
{
@@ -657,12 +662,18 @@ int
radeon_dp_mst_init(struct radeon_connector *radeon_connector)
{
struct drm_device *dev = radeon_connector->base.dev;
+ struct drm_dp_mst_topology_state *state =
+ kzalloc(sizeof(*state), GFP_KERNEL);
+ if (!state)
+ return -ENOMEM;
if (!radeon_connector->ddc_bus->has_aux)
return 0;
radeon_connector->mst_mgr.cbs = &mst_cbs;
- return drm_dp_mst_topology_mgr_init(&radeon_connector->mst_mgr, dev,
+ radeon_connector->mst_mgr.funcs = &mst_state_funcs;
+ return drm_dp_mst_topology_mgr_init(&radeon_connector->mst_mgr,
+ state, dev,
&radeon_connector->ddc_bus->aux, 16, 6,
radeon_connector->base.base.id);
}
diff --git a/include/drm/drm_dp_mst_helper.h b/include/drm/drm_dp_mst_helper.h
index 5ca77dcf4f90..ad1aaec8d514 100644
--- a/include/drm/drm_dp_mst_helper.h
+++ b/include/drm/drm_dp_mst_helper.h
@@ -565,6 +565,7 @@ struct drm_dp_mst_topology_mgr {
};
int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr,
+ struct drm_dp_mst_topology_state *state,
struct drm_device *dev, struct drm_dp_aux *aux,
int max_dpcd_transaction_bytes,
int max_payloads, int conn_base_id);
@@ -621,6 +622,13 @@ int drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr);
struct drm_dp_mst_topology_state *
drm_atomic_dp_mst_get_topology_state(struct drm_atomic_state *state,
struct drm_dp_mst_topology_mgr *mgr);
+struct drm_private_state *drm_atomic_dp_mst_duplicate_topology_state(struct drm_private_obj *obj);
+int __drm_atomic_dp_mst_duplicate_topology_state(struct drm_dp_mst_topology_mgr *mgr,
+ struct drm_dp_mst_topology_state *state);
+void drm_atomic_dp_mst_destroy_topology_state(struct drm_private_obj *obj,
+ struct drm_private_state *state);
+void __drm_atomic_dp_mst_destroy_topology_state(struct drm_dp_mst_topology_state *state);
+
int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state,
struct drm_dp_mst_topology_mgr *mgr,
struct drm_dp_mst_port *port, int pbn);
--
2.14.3
^ permalink raw reply related [flat|nested] 2+ messages in thread