diff mbox

[v7,05/10] drm/dp_mst: Make drm_dp_mst_topology_state subclassable

Message ID 20180411225501.26751-6-lyude@redhat.com (mailing list archive)
State New, archived
Headers show

Commit Message

Lyude Paul April 11, 2018, 10:54 p.m. UTC
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 mbox

Patch

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);