Commit c215e48e authored by Douglas Gilbert's avatar Douglas Gilbert Committed by Greg Kroah-Hartman

USB-PD tcpm: bad warning+size, PPS adapters

Augmented Power Delivery Objects (A)PDO_s are used by USB-C
PD power adapters to advertize the voltages and currents
they support. There can be up to 7 PDO_s but before PPS
(programmable power supply) there were seldom more than 4
or 5. Recently Samsung released an optional PPS 45 Watt power
adapter (EP-TA485) that has 7 PDO_s. It is for the Galaxy 10+
tablet and charges it quicker than the adapter supplied at
purchase. The EP-TA485 causes an overzealous WARN_ON to soil
the log plus it miscalculates the number of bytes to read.

So this bug has been there for some time but goes
undetected for the majority of USB-C PD power adapters on
the market today that have 6 or less PDO_s. That may soon
change as more USB-C PD adapters with PPS come to market.

Tested on a EP-TA485 and an older Lenovo PN: SA10M13950
USB-C 65 Watt adapter (without PPS and has 4 PDO_s) plus
several other PD power adapters.
Signed-off-by: default avatarDouglas Gilbert <dgilbert@interlog.com>
Reviewed-by: default avatarGuenter Roeck <linux@roeck-us.net>
Cc: stable <stable@vger.kernel.org>
Link: https://lore.kernel.org/r/20191230033544.1809-1-dgilbert@interlog.comSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent efb3ecdc
...@@ -432,20 +432,30 @@ irqreturn_t tcpci_irq(struct tcpci *tcpci) ...@@ -432,20 +432,30 @@ irqreturn_t tcpci_irq(struct tcpci *tcpci)
if (status & TCPC_ALERT_RX_STATUS) { if (status & TCPC_ALERT_RX_STATUS) {
struct pd_message msg; struct pd_message msg;
unsigned int cnt; unsigned int cnt, payload_cnt;
u16 header; u16 header;
regmap_read(tcpci->regmap, TCPC_RX_BYTE_CNT, &cnt); regmap_read(tcpci->regmap, TCPC_RX_BYTE_CNT, &cnt);
/*
* 'cnt' corresponds to READABLE_BYTE_COUNT in section 4.4.14
* of the TCPCI spec [Rev 2.0 Ver 1.0 October 2017] and is
* defined in table 4-36 as one greater than the number of
* bytes received. And that number includes the header. So:
*/
if (cnt > 3)
payload_cnt = cnt - (1 + sizeof(msg.header));
else
payload_cnt = 0;
tcpci_read16(tcpci, TCPC_RX_HDR, &header); tcpci_read16(tcpci, TCPC_RX_HDR, &header);
msg.header = cpu_to_le16(header); msg.header = cpu_to_le16(header);
if (WARN_ON(cnt > sizeof(msg.payload))) if (WARN_ON(payload_cnt > sizeof(msg.payload)))
cnt = sizeof(msg.payload); payload_cnt = sizeof(msg.payload);
if (cnt > 0) if (payload_cnt > 0)
regmap_raw_read(tcpci->regmap, TCPC_RX_DATA, regmap_raw_read(tcpci->regmap, TCPC_RX_DATA,
&msg.payload, cnt); &msg.payload, payload_cnt);
/* Read complete, clear RX status alert bit */ /* Read complete, clear RX status alert bit */
tcpci_write16(tcpci, TCPC_ALERT, TCPC_ALERT_RX_STATUS); tcpci_write16(tcpci, TCPC_ALERT, TCPC_ALERT_RX_STATUS);
......
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