Received: by 2002:ad5:474a:0:0:0:0:0 with SMTP id i10csp3472006imu; Sun, 11 Nov 2018 15:53:32 -0800 (PST) X-Google-Smtp-Source: AJdET5dQs5oYvbbXynJorUwLbdsmT6uohBAROcs3KHzFFsY6lWJvchu4CptfMJW918DnFSnh0Vg4 X-Received: by 2002:aa7:8603:: with SMTP id p3-v6mr18025141pfn.247.1541980412063; Sun, 11 Nov 2018 15:53:32 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1541980412; cv=none; d=google.com; s=arc-20160816; b=BOfrAKm5IVpNw/vEqfz2xExSrEX1dG3TjowQuv5Uv33WGy4xGR+OT44zWvY1Q5TTxZ ZuxaQOPW70eGFghEEs1YzKbOKJbf7R7s1/LHUxSW8EpbZTxZN86Vfot8tn1homUUOkMN phH/UHIQehIS90d5+KFpxNABuvyoBuhrUuBSfl584/brrE4Ih2IBiGmkszspLulzWmMb 90jXsSrQ82HUG8/qaOwGFzHVSF0rc985ofBR4TlbJQbnGuHLBKHGzgxC7S2xnp+u93po Da3G4hj3etkfKvBxBqpBzwrgMUEkossl3ekGDBUBnVxPId22oPAJSJcCAJcu5qOcynZ+ xVTw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=8BU2qo2MmWo2LcSr5rsi1BWwdr1AmZaveupf9C0fHX4=; b=zdAjZ75aF8bydi55UJdHhXd8AA3s7Ip5IJ0vpchIagF2/as/HCYNNbm1GltipFf2gh wSdcPVM6LLEKoTa3ARev1MKSADpmj48gtHTp5hYVjg+AFDFWz6SRafx4u9qi3HNzxrJ8 S7E+LIWEbW3X9aGS9yJtFJZ5F31Y1ucdZgfyIJOpZporLvT7u9h5mCq3RYv7XAeldXo+ 5ZlXtXyK/glwUsXM/1wKqi4QbdPdwwQtzJfLmZHTW30cIou7R+f6tPlmf7LKPpBaDgit Vf49uVhAl/vvMvpazST9m7qqY6XDcoiw1keigrPf2DAYPTW21xc+SENCqs8XdImeFVcj WK8g== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=HXjfRPE6; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id k68-v6si14266007pgk.294.2018.11.11.15.53.17; Sun, 11 Nov 2018 15:53:32 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=HXjfRPE6; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1733168AbeKLJmF (ORCPT + 99 others); Mon, 12 Nov 2018 04:42:05 -0500 Received: from mail.kernel.org ([198.145.29.99]:38130 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1732859AbeKLISb (ORCPT ); Mon, 12 Nov 2018 03:18:31 -0500 Received: from localhost (unknown [206.108.79.134]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 460DB223C6; Sun, 11 Nov 2018 22:28:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1541975315; bh=C9ROMiZa35ZLJyqsw6oSguLintctMmYvSJg+nWYBUFk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=HXjfRPE65kSchAzWWP52mvfPHGJxyrwzKy2bzkRMp9ine14+tfq7YcieW4EZRR97d tAJuB+QmVOJ2tJieBDCYkZCZw/NYsKdAdNFYWRWSdJ20v9PUbqVpn5UzCTwxMhVpOb i6D4c44d1Bs0lr4EAjBo5mUFyvorJ0zQhMUpssvk= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Hans Verkuil , Mauro Carvalho Chehab Subject: [PATCH 4.19 302/361] media: cec: add new tx/rx status bits to detect aborts/timeouts Date: Sun, 11 Nov 2018 14:20:49 -0800 Message-Id: <20181111221657.579589198@linuxfoundation.org> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20181111221619.915519183@linuxfoundation.org> References: <20181111221619.915519183@linuxfoundation.org> User-Agent: quilt/0.65 X-stable: review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 4.19-stable review patch. If anyone has any objections, please let me know. ------------------ From: Hans Verkuil commit 7ec2b3b941a666a942859684281b5f6460a0c234 upstream. If the HDMI cable is disconnected or the CEC adapter is manually unconfigured, then all pending transmits and wait-for-replies are aborted. Signal this with new status bits (CEC_RX/TX_STATUS_ABORTED). If due to (usually) a driver bug a transmit never ends (i.e. the transmit_done was never called by the driver), then when this times out the message is marked with CEC_TX_STATUS_TIMEOUT. This should not happen and is an indication of a driver bug. Without a separate status bit for this it was impossible to detect this from userspace. The 'transmit timed out' kernel message is now a warning, so this should be more prominent in the kernel log as well. Signed-off-by: Hans Verkuil Cc: # for v4.18 and up Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- Documentation/media/uapi/cec/cec-ioc-receive.rst | 25 +++++++- drivers/media/cec/cec-adap.c | 68 ++++++----------------- include/uapi/linux/cec.h | 3 + 3 files changed, 45 insertions(+), 51 deletions(-) --- a/Documentation/media/uapi/cec/cec-ioc-receive.rst +++ b/Documentation/media/uapi/cec/cec-ioc-receive.rst @@ -16,10 +16,10 @@ CEC_RECEIVE, CEC_TRANSMIT - Receive or t Synopsis ======== -.. c:function:: int ioctl( int fd, CEC_RECEIVE, struct cec_msg *argp ) +.. c:function:: int ioctl( int fd, CEC_RECEIVE, struct cec_msg \*argp ) :name: CEC_RECEIVE -.. c:function:: int ioctl( int fd, CEC_TRANSMIT, struct cec_msg *argp ) +.. c:function:: int ioctl( int fd, CEC_TRANSMIT, struct cec_msg \*argp ) :name: CEC_TRANSMIT Arguments @@ -272,6 +272,19 @@ View On' messages from initiator 0xf ('U - The transmit failed after one or more retries. This status bit is mutually exclusive with :ref:`CEC_TX_STATUS_OK `. Other bits can still be set to explain which failures were seen. + * .. _`CEC-TX-STATUS-ABORTED`: + + - ``CEC_TX_STATUS_ABORTED`` + - 0x40 + - The transmit was aborted due to an HDMI disconnect, or the adapter + was unconfigured, or a transmit was interrupted, or the driver + returned an error when attempting to start a transmit. + * .. _`CEC-TX-STATUS-TIMEOUT`: + + - ``CEC_TX_STATUS_TIMEOUT`` + - 0x80 + - The transmit timed out. This should not normally happen and this + indicates a driver problem. .. tabularcolumns:: |p{5.6cm}|p{0.9cm}|p{11.0cm}| @@ -300,6 +313,14 @@ View On' messages from initiator 0xf ('U - The message was received successfully but the reply was ``CEC_MSG_FEATURE_ABORT``. This status is only set if this message was the reply to an earlier transmitted message. + * .. _`CEC-RX-STATUS-ABORTED`: + + - ``CEC_RX_STATUS_ABORTED`` + - 0x08 + - The wait for a reply to an earlier transmitted message was aborted + because the HDMI cable was disconnected, the adapter was unconfigured + or the :ref:`CEC_TRANSMIT ` that waited for a + reply was interrupted. --- a/drivers/media/cec/cec-adap.c +++ b/drivers/media/cec/cec-adap.c @@ -341,7 +341,7 @@ static void cec_data_completed(struct ce * * This function is called with adap->lock held. */ -static void cec_data_cancel(struct cec_data *data) +static void cec_data_cancel(struct cec_data *data, u8 tx_status) { /* * It's either the current transmit, or it is a pending @@ -356,13 +356,11 @@ static void cec_data_cancel(struct cec_d } if (data->msg.tx_status & CEC_TX_STATUS_OK) { - /* Mark the canceled RX as a timeout */ data->msg.rx_ts = ktime_get_ns(); - data->msg.rx_status = CEC_RX_STATUS_TIMEOUT; + data->msg.rx_status = CEC_RX_STATUS_ABORTED; } else { - /* Mark the canceled TX as an error */ data->msg.tx_ts = ktime_get_ns(); - data->msg.tx_status |= CEC_TX_STATUS_ERROR | + data->msg.tx_status |= tx_status | CEC_TX_STATUS_MAX_RETRIES; data->msg.tx_error_cnt++; data->attempts = 0; @@ -390,15 +388,15 @@ static void cec_flush(struct cec_adapter while (!list_empty(&adap->transmit_queue)) { data = list_first_entry(&adap->transmit_queue, struct cec_data, list); - cec_data_cancel(data); + cec_data_cancel(data, CEC_TX_STATUS_ABORTED); } if (adap->transmitting) - cec_data_cancel(adap->transmitting); + cec_data_cancel(adap->transmitting, CEC_TX_STATUS_ABORTED); /* Cancel the pending timeout work. */ list_for_each_entry_safe(data, n, &adap->wait_queue, list) { if (cancel_delayed_work(&data->work)) - cec_data_cancel(data); + cec_data_cancel(data, CEC_TX_STATUS_OK); /* * If cancel_delayed_work returned false, then * the cec_wait_timeout function is running, @@ -474,12 +472,13 @@ int cec_thread_func(void *_adap) * so much traffic on the bus that the adapter was * unable to transmit for CEC_XFER_TIMEOUT_MS (2.1s). */ - dprintk(1, "%s: message %*ph timed out\n", __func__, + pr_warn("cec-%s: message %*ph timed out\n", adap->name, adap->transmitting->msg.len, adap->transmitting->msg.msg); adap->tx_timeouts++; /* Just give up on this. */ - cec_data_cancel(adap->transmitting); + cec_data_cancel(adap->transmitting, + CEC_TX_STATUS_TIMEOUT); goto unlock; } @@ -530,7 +529,7 @@ int cec_thread_func(void *_adap) /* Tell the adapter to transmit, cancel on error */ if (adap->ops->adap_transmit(adap, data->attempts, signal_free_time, &data->msg)) - cec_data_cancel(data); + cec_data_cancel(data, CEC_TX_STATUS_ABORTED); unlock: mutex_unlock(&adap->lock); @@ -702,8 +701,6 @@ int cec_transmit_msg_fh(struct cec_adapt { struct cec_data *data; u8 last_initiator = 0xff; - unsigned int timeout; - int res = 0; msg->rx_ts = 0; msg->tx_ts = 0; @@ -846,47 +843,20 @@ int cec_transmit_msg_fh(struct cec_adapt return 0; /* - * If we don't get a completion before this time something is really - * wrong and we time out. - */ - timeout = CEC_XFER_TIMEOUT_MS; - /* Add the requested timeout if we have to wait for a reply as well */ - if (msg->timeout) - timeout += msg->timeout; - - /* * Release the lock and wait, retake the lock afterwards. */ mutex_unlock(&adap->lock); - res = wait_for_completion_killable_timeout(&data->c, - msecs_to_jiffies(timeout)); + wait_for_completion_killable(&data->c); mutex_lock(&adap->lock); - if (data->completed) { - /* The transmit completed (possibly with an error) */ - *msg = data->msg; - kfree(data); - return 0; - } - /* - * The wait for completion timed out or was interrupted, so mark this - * as non-blocking and disconnect from the filehandle since it is - * still 'in flight'. When it finally completes it will just drop the - * result silently. - */ - data->blocking = false; - if (data->fh) - list_del(&data->xfer_list); - data->fh = NULL; - - if (res == 0) { /* timed out */ - /* Check if the reply or the transmit failed */ - if (msg->timeout && (msg->tx_status & CEC_TX_STATUS_OK)) - msg->rx_status = CEC_RX_STATUS_TIMEOUT; - else - msg->tx_status = CEC_TX_STATUS_MAX_RETRIES; - } - return res > 0 ? 0 : res; + /* Cancel the transmit if it was interrupted */ + if (!data->completed) + cec_data_cancel(data, CEC_TX_STATUS_ABORTED); + + /* The transmit completed (possibly with an error) */ + *msg = data->msg; + kfree(data); + return 0; } /* Helper function to be used by drivers and this framework. */ --- a/include/uapi/linux/cec.h +++ b/include/uapi/linux/cec.h @@ -152,10 +152,13 @@ static inline void cec_msg_set_reply_to( #define CEC_TX_STATUS_LOW_DRIVE (1 << 3) #define CEC_TX_STATUS_ERROR (1 << 4) #define CEC_TX_STATUS_MAX_RETRIES (1 << 5) +#define CEC_TX_STATUS_ABORTED (1 << 6) +#define CEC_TX_STATUS_TIMEOUT (1 << 7) #define CEC_RX_STATUS_OK (1 << 0) #define CEC_RX_STATUS_TIMEOUT (1 << 1) #define CEC_RX_STATUS_FEATURE_ABORT (1 << 2) +#define CEC_RX_STATUS_ABORTED (1 << 3) static inline int cec_msg_status_is_ok(const struct cec_msg *msg) {