[PATCH v10 36/40] misc/mei/hdcp: Component framework for I915 Interface
Ramalingam C
ramalingam.c at intel.com
Tue Jan 8 17:15:02 UTC 2019
Mei hdcp driver is designed as component slave for the I915 component
master.
v2: Rebased.
v3:
Notifier chain is adopted for cldev state update [Tomas]
v4:
Made static dummy functions as inline in mei_hdcp.h
API for polling client device status
IS_ENABLED used in header, for config status for mei_hdcp.
v5:
Replacing the notifier with component framework. [Daniel]
v6:
Rebased on the I915 comp master redesign.
v7:
mei_hdcp_component_registered is made static [Uma]
Need for global static variable mei_cldev is removed.
v8:
comp_del only on module_unload
master_comp->mei_dev is removed at driver->remove()
mutex is added for the comp add, del and ops.
Signed-off-by: Ramalingam C <ramalingam.c at intel.com>
Reviewed-by: Uma Shankar <uma.shankar at intel.com>
---
drivers/misc/mei/hdcp/mei_hdcp.c | 172 +++++++++++++++++++++++++++++++++++++--
1 file changed, 167 insertions(+), 5 deletions(-)
diff --git a/drivers/misc/mei/hdcp/mei_hdcp.c b/drivers/misc/mei/hdcp/mei_hdcp.c
index 2807cf5767b7..381664eb288d 100644
--- a/drivers/misc/mei/hdcp/mei_hdcp.c
+++ b/drivers/misc/mei/hdcp/mei_hdcp.c
@@ -23,11 +23,24 @@
#include <linux/slab.h>
#include <linux/uuid.h>
#include <linux/mei_cl_bus.h>
+#include <linux/component.h>
#include <drm/drm_connector.h>
#include <drm/i915_component.h>
#include "mei_hdcp.h"
+static struct {
+ struct i915_component_master *master_comp;
+
+ /*
+ * Mutex to protect the component addition, deletion, master_comp update
+ * and usage.
+ */
+ struct mutex mutex;
+ bool comp_registered;
+ struct device *orig_dev;
+} mei_data;
+
/**
* mei_initiate_hdcp2_session() - Initiate a Wired HDCP2.2 Tx Session in ME FW
* @dev: device corresponding to the mei_cl_device
@@ -49,6 +62,7 @@ mei_initiate_hdcp2_session(struct device *dev, struct hdcp_port_data *data,
if (!dev || !data || !ake_data)
return -EINVAL;
+ mutex_lock(&mei_data.mutex);
cldev = to_mei_cl_device(dev);
session_init_in.header.api_version = HDCP_API_VERSION;
@@ -65,6 +79,7 @@ mei_initiate_hdcp2_session(struct device *dev, struct hdcp_port_data *data,
sizeof(session_init_in));
if (byte < 0) {
dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte);
+ mutex_unlock(&mei_data.mutex);
return byte;
}
@@ -72,6 +87,7 @@ mei_initiate_hdcp2_session(struct device *dev, struct hdcp_port_data *data,
sizeof(session_init_out));
if (byte < 0) {
dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte);
+ mutex_unlock(&mei_data.mutex);
return byte;
}
@@ -79,12 +95,14 @@ mei_initiate_hdcp2_session(struct device *dev, struct hdcp_port_data *data,
dev_dbg(dev, "ME cmd 0x%08X Failed. Status: 0x%X\n",
WIRED_INITIATE_HDCP2_SESSION,
session_init_out.header.status);
+ mutex_unlock(&mei_data.mutex);
return -EIO;
}
ake_data->msg_id = HDCP_2_2_AKE_INIT;
ake_data->tx_caps = session_init_out.tx_caps;
memcpy(ake_data->r_tx, session_init_out.r_tx, HDCP_2_2_RTX_LEN);
+ mutex_unlock(&mei_data.mutex);
return 0;
}
@@ -117,6 +135,7 @@ mei_verify_receiver_cert_prepare_km(struct device *dev,
if (!dev || !data || !rx_cert || !km_stored || !ek_pub_km || !msg_sz)
return -EINVAL;
+ mutex_lock(&mei_data.mutex);
cldev = to_mei_cl_device(dev);
verify_rxcert_in.header.api_version = HDCP_API_VERSION;
@@ -136,6 +155,7 @@ mei_verify_receiver_cert_prepare_km(struct device *dev,
sizeof(verify_rxcert_in));
if (byte < 0) {
dev_dbg(dev, "mei_cldev_send failed: %zd\n", byte);
+ mutex_unlock(&mei_data.mutex);
return byte;
}
@@ -143,6 +163,7 @@ mei_verify_receiver_cert_prepare_km(struct device *dev,
sizeof(verify_rxcert_out));
if (byte < 0) {
dev_dbg(dev, "mei_cldev_recv failed: %zd\n", byte);
+ mutex_unlock(&mei_data.mutex);
return byte;
}
@@ -150,6 +171,7 @@ mei_verify_receiver_cert_prepare_km(struct device *dev,
dev_dbg(dev, "ME cmd 0x%08X Failed. Status: 0x%X\n",
WIRED_VERIFY_RECEIVER_CERT,
verify_rxcert_out.header.status);
+ mutex_unlock(&mei_data.mutex);
return -EIO;
}
@@ -164,6 +186,7 @@ mei_verify_receiver_cert_prepare_km(struct device *dev,
memcpy(ek_pub_km->e_kpub_km, &verify_rxcert_out.ekm_buff,
sizeof(verify_rxcert_out.ekm_buff));
+ mutex_unlock(&mei_data.mutex);
return 0;
}
@@ -187,6 +210,7 @@ static int mei_verify_hprime(struct device *dev, struct hdcp_port_data *data,
if (!dev || !data || !rx_hprime)
return -EINVAL;
+ mutex_lock(&mei_data.mutex);
cldev = to_mei_cl_device(dev);
send_hprime_in.header.api_version = HDCP_API_VERSION;
@@ -204,6 +228,7 @@ static int mei_verify_hprime(struct device *dev, struct hdcp_port_data *data,
sizeof(send_hprime_in));
if (byte < 0) {
dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte);
+ mutex_unlock(&mei_data.mutex);
return byte;
}
@@ -211,14 +236,17 @@ static int mei_verify_hprime(struct device *dev, struct hdcp_port_data *data,
sizeof(send_hprime_out));
if (byte < 0) {
dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte);
+ mutex_unlock(&mei_data.mutex);
return byte;
}
if (send_hprime_out.header.status != ME_HDCP_STATUS_SUCCESS) {
dev_dbg(dev, "ME cmd 0x%08X Failed. Status: 0x%X\n",
WIRED_AKE_SEND_HPRIME, send_hprime_out.header.status);
+ mutex_unlock(&mei_data.mutex);
return -EIO;
}
+ mutex_unlock(&mei_data.mutex);
return 0;
}
@@ -243,6 +271,7 @@ mei_store_pairing_info(struct device *dev, struct hdcp_port_data *data,
if (!dev || !data || !pairing_info)
return -EINVAL;
+ mutex_lock(&mei_data.mutex);
cldev = to_mei_cl_device(dev);
pairing_info_in.header.api_version = HDCP_API_VERSION;
@@ -261,6 +290,7 @@ mei_store_pairing_info(struct device *dev, struct hdcp_port_data *data,
sizeof(pairing_info_in));
if (byte < 0) {
dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte);
+ mutex_unlock(&mei_data.mutex);
return byte;
}
@@ -268,6 +298,7 @@ mei_store_pairing_info(struct device *dev, struct hdcp_port_data *data,
sizeof(pairing_info_out));
if (byte < 0) {
dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte);
+ mutex_unlock(&mei_data.mutex);
return byte;
}
@@ -275,8 +306,10 @@ mei_store_pairing_info(struct device *dev, struct hdcp_port_data *data,
dev_dbg(dev, "ME cmd 0x%08X failed. Status: 0x%X\n",
WIRED_AKE_SEND_PAIRING_INFO,
pairing_info_out.header.status);
+ mutex_unlock(&mei_data.mutex);
return -EIO;
}
+ mutex_unlock(&mei_data.mutex);
return 0;
}
@@ -301,6 +334,7 @@ mei_initiate_locality_check(struct device *dev, struct hdcp_port_data *data,
if (!dev || !data || !lc_init_data)
return -EINVAL;
+ mutex_lock(&mei_data.mutex);
cldev = to_mei_cl_device(dev);
lc_init_in.header.api_version = HDCP_API_VERSION;
@@ -314,23 +348,27 @@ mei_initiate_locality_check(struct device *dev, struct hdcp_port_data *data,
byte = mei_cldev_send(cldev, (u8 *)&lc_init_in, sizeof(lc_init_in));
if (byte < 0) {
dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte);
+ mutex_unlock(&mei_data.mutex);
return byte;
}
byte = mei_cldev_recv(cldev, (u8 *)&lc_init_out, sizeof(lc_init_out));
if (byte < 0) {
dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte);
+ mutex_unlock(&mei_data.mutex);
return byte;
}
if (lc_init_out.header.status != ME_HDCP_STATUS_SUCCESS) {
dev_dbg(dev, "ME cmd 0x%08X Failed. status: 0x%X\n",
WIRED_INIT_LOCALITY_CHECK, lc_init_out.header.status);
+ mutex_unlock(&mei_data.mutex);
return -EIO;
}
lc_init_data->msg_id = HDCP_2_2_LC_INIT;
memcpy(lc_init_data->r_n, lc_init_out.r_n, HDCP_2_2_RN_LEN);
+ mutex_unlock(&mei_data.mutex);
return 0;
}
@@ -354,6 +392,7 @@ static int mei_verify_lprime(struct device *dev, struct hdcp_port_data *data,
if (!dev || !data || !rx_lprime)
return -EINVAL;
+ mutex_lock(&mei_data.mutex);
cldev = to_mei_cl_device(dev);
verify_lprime_in.header.api_version = HDCP_API_VERSION;
@@ -372,6 +411,7 @@ static int mei_verify_lprime(struct device *dev, struct hdcp_port_data *data,
sizeof(verify_lprime_in));
if (byte < 0) {
dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte);
+ mutex_unlock(&mei_data.mutex);
return byte;
}
@@ -379,6 +419,7 @@ static int mei_verify_lprime(struct device *dev, struct hdcp_port_data *data,
sizeof(verify_lprime_out));
if (byte < 0) {
dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte);
+ mutex_unlock(&mei_data.mutex);
return byte;
}
@@ -386,8 +427,10 @@ static int mei_verify_lprime(struct device *dev, struct hdcp_port_data *data,
dev_dbg(dev, "ME cmd 0x%08X failed. status: 0x%X\n",
WIRED_VALIDATE_LOCALITY,
verify_lprime_out.header.status);
+ mutex_unlock(&mei_data.mutex);
return -EIO;
}
+ mutex_unlock(&mei_data.mutex);
return 0;
}
@@ -411,6 +454,7 @@ static int mei_get_session_key(struct device *dev, struct hdcp_port_data *data,
if (!dev || !data || !ske_data)
return -EINVAL;
+ mutex_lock(&mei_data.mutex);
cldev = to_mei_cl_device(dev);
get_skey_in.header.api_version = HDCP_API_VERSION;
@@ -424,6 +468,7 @@ static int mei_get_session_key(struct device *dev, struct hdcp_port_data *data,
byte = mei_cldev_send(cldev, (u8 *)&get_skey_in, sizeof(get_skey_in));
if (byte < 0) {
dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte);
+ mutex_unlock(&mei_data.mutex);
return byte;
}
@@ -431,12 +476,14 @@ static int mei_get_session_key(struct device *dev, struct hdcp_port_data *data,
if (byte < 0) {
dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte);
+ mutex_unlock(&mei_data.mutex);
return byte;
}
if (get_skey_out.header.status != ME_HDCP_STATUS_SUCCESS) {
dev_dbg(dev, "ME cmd 0x%08X failed. status: 0x%X\n",
WIRED_GET_SESSION_KEY, get_skey_out.header.status);
+ mutex_unlock(&mei_data.mutex);
return -EIO;
}
@@ -444,6 +491,7 @@ static int mei_get_session_key(struct device *dev, struct hdcp_port_data *data,
memcpy(ske_data->e_dkey_ks, get_skey_out.e_dkey_ks,
HDCP_2_2_E_DKEY_KS_LEN);
memcpy(ske_data->riv, get_skey_out.r_iv, HDCP_2_2_RIV_LEN);
+ mutex_unlock(&mei_data.mutex);
return 0;
}
@@ -473,6 +521,7 @@ mei_repeater_check_flow_prepare_ack(struct device *dev,
if (!dev || !rep_topology || !rep_send_ack || !data)
return -EINVAL;
+ mutex_lock(&mei_data.mutex);
cldev = to_mei_cl_device(dev);
verify_repeater_in.header.api_version = HDCP_API_VERSION;
@@ -498,6 +547,7 @@ mei_repeater_check_flow_prepare_ack(struct device *dev,
sizeof(verify_repeater_in));
if (byte < 0) {
dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte);
+ mutex_unlock(&mei_data.mutex);
return byte;
}
@@ -505,6 +555,7 @@ mei_repeater_check_flow_prepare_ack(struct device *dev,
sizeof(verify_repeater_out));
if (byte < 0) {
dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte);
+ mutex_unlock(&mei_data.mutex);
return byte;
}
@@ -512,12 +563,14 @@ mei_repeater_check_flow_prepare_ack(struct device *dev,
dev_dbg(dev, "ME cmd 0x%08X failed. status: 0x%X\n",
WIRED_VERIFY_REPEATER,
verify_repeater_out.header.status);
+ mutex_unlock(&mei_data.mutex);
return -EIO;
}
memcpy(rep_send_ack->v, verify_repeater_out.v,
HDCP_2_2_V_PRIME_HALF_LEN);
rep_send_ack->msg_id = HDCP_2_2_REP_SEND_ACK;
+ mutex_unlock(&mei_data.mutex);
return 0;
}
@@ -543,6 +596,7 @@ static int mei_verify_mprime(struct device *dev, struct hdcp_port_data *data,
if (!dev || !stream_ready || !data)
return -EINVAL;
+ mutex_lock(&mei_data.mutex);
cldev = to_mei_cl_device(dev);
verify_mprime_in.header.api_version = HDCP_API_VERSION;
@@ -566,6 +620,7 @@ static int mei_verify_mprime(struct device *dev, struct hdcp_port_data *data,
sizeof(verify_mprime_in));
if (byte < 0) {
dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte);
+ mutex_unlock(&mei_data.mutex);
return byte;
}
@@ -573,6 +628,7 @@ static int mei_verify_mprime(struct device *dev, struct hdcp_port_data *data,
sizeof(verify_mprime_out));
if (byte < 0) {
dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte);
+ mutex_unlock(&mei_data.mutex);
return byte;
}
@@ -580,8 +636,10 @@ static int mei_verify_mprime(struct device *dev, struct hdcp_port_data *data,
dev_dbg(dev, "ME cmd 0x%08X failed. status: 0x%X\n",
WIRED_REPEATER_AUTH_STREAM_REQ,
verify_mprime_out.header.status);
+ mutex_unlock(&mei_data.mutex);
return -EIO;
}
+ mutex_unlock(&mei_data.mutex);
return 0;
}
@@ -604,6 +662,7 @@ mei_enable_hdcp_authentication(struct device *dev, struct hdcp_port_data *data)
if (!dev || !data)
return -EINVAL;
+ mutex_lock(&mei_data.mutex);
cldev = to_mei_cl_device(dev);
enable_auth_in.header.api_version = HDCP_API_VERSION;
@@ -619,6 +678,7 @@ mei_enable_hdcp_authentication(struct device *dev, struct hdcp_port_data *data)
sizeof(enable_auth_in));
if (byte < 0) {
dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte);
+ mutex_unlock(&mei_data.mutex);
return byte;
}
@@ -626,14 +686,17 @@ mei_enable_hdcp_authentication(struct device *dev, struct hdcp_port_data *data)
sizeof(enable_auth_out));
if (byte < 0) {
dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte);
+ mutex_unlock(&mei_data.mutex);
return byte;
}
if (enable_auth_out.header.status != ME_HDCP_STATUS_SUCCESS) {
dev_dbg(dev, "ME cmd 0x%08X failed. status: 0x%X\n",
WIRED_ENABLE_AUTH, enable_auth_out.header.status);
+ mutex_unlock(&mei_data.mutex);
return -EIO;
}
+ mutex_unlock(&mei_data.mutex);
return 0;
}
@@ -657,6 +720,7 @@ mei_close_hdcp_session(struct device *dev, struct hdcp_port_data *data)
if (!dev || !data)
return -EINVAL;
+ mutex_lock(&mei_data.mutex);
cldev = to_mei_cl_device(dev);
session_close_in.header.api_version = HDCP_API_VERSION;
@@ -672,6 +736,7 @@ mei_close_hdcp_session(struct device *dev, struct hdcp_port_data *data)
sizeof(session_close_in));
if (byte < 0) {
dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte);
+ mutex_unlock(&mei_data.mutex);
return byte;
}
@@ -679,20 +744,22 @@ mei_close_hdcp_session(struct device *dev, struct hdcp_port_data *data)
sizeof(session_close_out));
if (byte < 0) {
dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte);
+ mutex_unlock(&mei_data.mutex);
return byte;
}
if (session_close_out.header.status != ME_HDCP_STATUS_SUCCESS) {
dev_dbg(dev, "Session Close Failed. status: 0x%X\n",
session_close_out.header.status);
+ mutex_unlock(&mei_data.mutex);
return -EIO;
}
+ mutex_unlock(&mei_data.mutex);
return 0;
}
-static __attribute__((unused))
-struct i915_hdcp_component_ops mei_hdcp_ops = {
+static struct i915_hdcp_component_ops mei_hdcp_ops = {
.owner = THIS_MODULE,
.initiate_hdcp2_session = mei_initiate_hdcp2_session,
.verify_receiver_cert_prepare_km = mei_verify_receiver_cert_prepare_km,
@@ -707,20 +774,97 @@ struct i915_hdcp_component_ops mei_hdcp_ops = {
.close_hdcp_session = mei_close_hdcp_session,
};
+static int mei_hdcp_component_bind(struct device *mei_kdev,
+ struct device *i915_kdev, void *data)
+{
+ struct i915_component_master *master_comp = data;
+
+ dev_info(mei_kdev, "MEI HDCP comp bind\n");
+ WARN_ON(master_comp->hdcp_ops);
+ master_comp->hdcp_ops = &mei_hdcp_ops;
+ master_comp->mei_dev = mei_kdev;
+
+ mei_data.master_comp = master_comp;
+
+ return 0;
+}
+
+static void mei_hdcp_component_unbind(struct device *mei_kdev,
+ struct device *i915_kdev, void *data)
+{
+ struct i915_component_master *master_comp = data;
+
+ dev_info(mei_kdev, "MEI HDCP comp unbind\n");
+ master_comp->hdcp_ops = NULL;
+ master_comp->mei_dev = NULL;
+ mei_data.master_comp = NULL;
+}
+
+static const struct component_ops mei_hdcp_component_bind_ops = {
+ .bind = mei_hdcp_component_bind,
+ .unbind = mei_hdcp_component_unbind,
+};
+
+static void mei_hdcp_component_init(struct device *dev)
+{
+ int ret;
+
+ mutex_lock(&mei_data.mutex);
+ if (mei_data.comp_registered && mei_data.master_comp) {
+
+ /*
+ * Component binding is not broken at driver->remove.
+ * So at next driver probe, we need to update the dev ptr.
+ */
+ mei_data.master_comp->mei_dev = dev;
+ mutex_unlock(&mei_data.mutex);
+ return;
+ }
+
+ dev_info(dev, "MEI HDCP comp init\n");
+ ret = component_add(dev, &mei_hdcp_component_bind_ops);
+ if (ret < 0) {
+ dev_err(dev, "Failed to add MEI HDCP comp (%d)\n", ret);
+ mutex_unlock(&mei_data.mutex);
+ return;
+ }
+
+ mei_data.comp_registered = true;
+ mei_data.orig_dev = dev;
+ mutex_unlock(&mei_data.mutex);
+}
+
+static void mei_hdcp_component_cleanup(struct device *dev)
+{
+ WARN_ON(!mutex_is_locked(&mei_data.mutex));
+
+ dev_info(dev, "MEI HDCP comp cleanup\n");
+ component_del(dev, &mei_hdcp_component_bind_ops);
+ mei_data.comp_registered = false;
+}
+
static int mei_hdcp_probe(struct mei_cl_device *cldev,
const struct mei_cl_device_id *id)
{
int ret;
ret = mei_cldev_enable(cldev);
- if (ret < 0)
+ if (ret < 0) {
dev_err(&cldev->dev, "mei_cldev_enable Failed. %d\n", ret);
+ return ret;
+ }
+ mei_hdcp_component_init(&cldev->dev);
- return ret;
+ return 0;
}
static int mei_hdcp_remove(struct mei_cl_device *cldev)
{
+ mutex_lock(&mei_data.mutex);
+ if (mei_data.master_comp)
+ mei_data.master_comp->mei_dev = NULL;
+ mutex_unlock(&mei_data.mutex);
+
return mei_cldev_disable(cldev);
}
@@ -741,7 +885,25 @@ static struct mei_cl_driver mei_hdcp_driver = {
.remove = mei_hdcp_remove,
};
-module_mei_cl_driver(mei_hdcp_driver);
+static int __init mei_hdcp_init(void)
+{
+ mutex_init(&mei_data.mutex);
+ return mei_cldev_driver_register(&mei_hdcp_driver);
+}
+
+static void __exit mei_hdcp_exit(void)
+{
+ mutex_lock(&mei_data.mutex);
+ if (mei_data.comp_registered)
+ mei_hdcp_component_cleanup(mei_data.orig_dev);
+ mutex_unlock(&mei_data.mutex);
+
+ mei_cldev_driver_unregister(&mei_hdcp_driver);
+ mutex_destroy(&mei_data.mutex);
+}
+
+module_init(mei_hdcp_init);
+module_exit(mei_hdcp_exit);
MODULE_AUTHOR("Intel Corporation");
MODULE_LICENSE("Dual BSD/GPL");
--
2.7.4
More information about the Intel-gfx-trybot
mailing list