From d70dba550ebd10398e5939f785a3612dfbe5c6fb Mon Sep 17 00:00:00 2001 From: cvh Date: Mon, 30 Jan 2017 18:43:04 +0100 Subject: [PATCH] media_build: fix TT-S2-3600 - fixes kernel oops see patch notes --- .../media_build-02-add-to-backports.patch | 3 +- ...inux-240-pctv452e_kernel_oops_in_4.9.patch | 311 ++++++++++++++++++ 2 files changed, 313 insertions(+), 1 deletion(-) create mode 100644 packages/linux-drivers/media_build/sources/backports/linux-240-pctv452e_kernel_oops_in_4.9.patch diff --git a/packages/linux-drivers/media_build/patches/media_build-02-add-to-backports.patch b/packages/linux-drivers/media_build/patches/media_build-02-add-to-backports.patch index a60b36b7ae..1f3f1999e4 100644 --- a/packages/linux-drivers/media_build/patches/media_build-02-add-to-backports.patch +++ b/packages/linux-drivers/media_build/patches/media_build-02-add-to-backports.patch @@ -1,6 +1,6 @@ --- a/backports/backports.txt +++ b/backports/backports.txt -@@ -25,6 +25,13 @@ +@@ -25,6 +25,14 @@ add pr_fmt.patch add debug.patch add drx39xxj.patch @@ -11,6 +11,7 @@ +add linux-054-nuvoton_revert_d7b290a1056c5564eec8a1b169c6e84ff3.6.114c13.patch +add linux-057-Removed-MCE-customer-code-restriction-in-rc6-decode.patch +add linux-062-imon_pad_ignore_diagonal.patch ++add linux-240-pctv452e_kernel_oops_in_4.9.patch [4.8.255] add v4.8_user_pages_flag.patch diff --git a/packages/linux-drivers/media_build/sources/backports/linux-240-pctv452e_kernel_oops_in_4.9.patch b/packages/linux-drivers/media_build/sources/backports/linux-240-pctv452e_kernel_oops_in_4.9.patch new file mode 100644 index 0000000000..72559d16ff --- /dev/null +++ b/packages/linux-drivers/media_build/sources/backports/linux-240-pctv452e_kernel_oops_in_4.9.patch @@ -0,0 +1,311 @@ +fixes: +dvb-usb: found a 'Technotrend TT Connect S2-3600' in warm state. +pctv452e: pctv452e_power_ctrl: 1 + +Unable to handle kernel NULL pointer dereference at virtual address 00000000 +pgd = adb60000 +[00000000] *pgd=00000000 +Internal error: Oops: 805 [#1] SMP ARM + +fixed in kernel 4.10 + +--- +From 48775cb73c2e26b7ca9d679875a6e570c8b8e124 Mon Sep 17 00:00:00 2001 +From: Max Kellermann +Date: Thu, 15 Dec 2016 19:51:07 -0200 +Subject: [PATCH] [media] pctv452e: move buffer to heap, no mutex + +commit 73d5c5c864f4 ("[media] pctv452e: don't do DMA on stack") caused +a NULL pointer dereference which occurs when dvb_usb_init() +calls dvb_usb_device_power_ctrl() for the first time, before the +frontend has been attached. It also caused a recursive deadlock because +tt3650_ci_msg_locked() has already locked the mutex. + +So, partially revert it, but move the buffer to the heap +(DMA capable), not to the stack (may not be DMA capable). +Instead of sharing one buffer which needs mutex protection, +do a new heap allocation for each call. + +Fixes: commit 73d5c5c864f4 ("[media] pctv452e: don't do DMA on stack") + +--- + drivers/media/usb/dvb-usb/pctv452e.c | 133 +++++++++++++++++++---------------- + 1 file changed, 72 insertions(+), 61 deletions(-) + +diff --git a/drivers/media/usb/dvb-usb/pctv452e.c b/drivers/media/usb/dvb-usb/pctv452e.c +index 07fa08b..d54ebe7 100644 +--- a/drivers/media/usb/dvb-usb/pctv452e.c ++++ b/drivers/media/usb/dvb-usb/pctv452e.c +@@ -97,14 +97,13 @@ struct pctv452e_state { + u8 c; /* transaction counter, wraps around... */ + u8 initialized; /* set to 1 if 0x15 has been sent */ + u16 last_rc_key; +- +- unsigned char data[80]; + }; + + static int tt3650_ci_msg(struct dvb_usb_device *d, u8 cmd, u8 *data, + unsigned int write_len, unsigned int read_len) + { + struct pctv452e_state *state = (struct pctv452e_state *)d->priv; ++ u8 *buf; + u8 id; + unsigned int rlen; + int ret; +@@ -114,36 +113,39 @@ static int tt3650_ci_msg(struct dvb_usb_device *d, u8 cmd, u8 *data, + return -EIO; + } + +- mutex_lock(&state->ca_mutex); ++ buf = kmalloc(64, GFP_KERNEL); ++ if (!buf) ++ return -ENOMEM; ++ + id = state->c++; + +- state->data[0] = SYNC_BYTE_OUT; +- state->data[1] = id; +- state->data[2] = cmd; +- state->data[3] = write_len; ++ buf[0] = SYNC_BYTE_OUT; ++ buf[1] = id; ++ buf[2] = cmd; ++ buf[3] = write_len; + +- memcpy(state->data + 4, data, write_len); ++ memcpy(buf + 4, data, write_len); + + rlen = (read_len > 0) ? 64 : 0; +- ret = dvb_usb_generic_rw(d, state->data, 4 + write_len, +- state->data, rlen, /* delay_ms */ 0); ++ ret = dvb_usb_generic_rw(d, buf, 4 + write_len, ++ buf, rlen, /* delay_ms */ 0); + if (0 != ret) + goto failed; + + ret = -EIO; +- if (SYNC_BYTE_IN != state->data[0] || id != state->data[1]) ++ if (SYNC_BYTE_IN != buf[0] || id != buf[1]) + goto failed; + +- memcpy(data, state->data + 4, read_len); ++ memcpy(data, buf + 4, read_len); + +- mutex_unlock(&state->ca_mutex); ++ kfree(buf); + return 0; + + failed: + err("CI error %d; %02X %02X %02X -> %*ph.", +- ret, SYNC_BYTE_OUT, id, cmd, 3, state->data); ++ ret, SYNC_BYTE_OUT, id, cmd, 3, buf); + +- mutex_unlock(&state->ca_mutex); ++ kfree(buf); + return ret; + } + +@@ -410,53 +412,57 @@ static int pctv452e_i2c_msg(struct dvb_usb_device *d, u8 addr, + u8 *rcv_buf, u8 rcv_len) + { + struct pctv452e_state *state = (struct pctv452e_state *)d->priv; ++ u8 *buf; + u8 id; + int ret; + +- mutex_lock(&state->ca_mutex); ++ buf = kmalloc(64, GFP_KERNEL); ++ if (!buf) ++ return -ENOMEM; ++ + id = state->c++; + + ret = -EINVAL; + if (snd_len > 64 - 7 || rcv_len > 64 - 7) + goto failed; + +- state->data[0] = SYNC_BYTE_OUT; +- state->data[1] = id; +- state->data[2] = PCTV_CMD_I2C; +- state->data[3] = snd_len + 3; +- state->data[4] = addr << 1; +- state->data[5] = snd_len; +- state->data[6] = rcv_len; ++ buf[0] = SYNC_BYTE_OUT; ++ buf[1] = id; ++ buf[2] = PCTV_CMD_I2C; ++ buf[3] = snd_len + 3; ++ buf[4] = addr << 1; ++ buf[5] = snd_len; ++ buf[6] = rcv_len; + +- memcpy(state->data + 7, snd_buf, snd_len); ++ memcpy(buf + 7, snd_buf, snd_len); + +- ret = dvb_usb_generic_rw(d, state->data, 7 + snd_len, +- state->data, /* rcv_len */ 64, ++ ret = dvb_usb_generic_rw(d, buf, 7 + snd_len, ++ buf, /* rcv_len */ 64, + /* delay_ms */ 0); + if (ret < 0) + goto failed; + + /* TT USB protocol error. */ + ret = -EIO; +- if (SYNC_BYTE_IN != state->data[0] || id != state->data[1]) ++ if (SYNC_BYTE_IN != buf[0] || id != buf[1]) + goto failed; + + /* I2C device didn't respond as expected. */ + ret = -EREMOTEIO; +- if (state->data[5] < snd_len || state->data[6] < rcv_len) ++ if (buf[5] < snd_len || buf[6] < rcv_len) + goto failed; + +- memcpy(rcv_buf, state->data + 7, rcv_len); +- mutex_unlock(&state->ca_mutex); ++ memcpy(rcv_buf, buf + 7, rcv_len); + ++ kfree(buf); + return rcv_len; + + failed: + err("I2C error %d; %02X %02X %02X %02X %02X -> %*ph", + ret, SYNC_BYTE_OUT, id, addr << 1, snd_len, rcv_len, +- 7, state->data); ++ 7, buf); + +- mutex_unlock(&state->ca_mutex); ++ kfree(buf); + return ret; + } + +@@ -505,7 +511,7 @@ static u32 pctv452e_i2c_func(struct i2c_adapter *adapter) + static int pctv452e_power_ctrl(struct dvb_usb_device *d, int i) + { + struct pctv452e_state *state = (struct pctv452e_state *)d->priv; +- u8 *rx; ++ u8 *b0, *rx; + int ret; + + info("%s: %d\n", __func__, i); +@@ -516,11 +522,12 @@ static int pctv452e_power_ctrl(struct dvb_usb_device *d, int i) + if (state->initialized) + return 0; + +- rx = kmalloc(PCTV_ANSWER_LEN, GFP_KERNEL); +- if (!rx) ++ b0 = kmalloc(5 + PCTV_ANSWER_LEN, GFP_KERNEL); ++ if (!b0) + return -ENOMEM; + +- mutex_lock(&state->ca_mutex); ++ rx = b0 + 5; ++ + /* hmm where shoud this should go? */ + ret = usb_set_interface(d->udev, 0, ISOC_INTERFACE_ALTERNATIVE); + if (ret != 0) +@@ -528,66 +535,70 @@ static int pctv452e_power_ctrl(struct dvb_usb_device *d, int i) + __func__, ret); + + /* this is a one-time initialization, dont know where to put */ +- state->data[0] = 0xaa; +- state->data[1] = state->c++; +- state->data[2] = PCTV_CMD_RESET; +- state->data[3] = 1; +- state->data[4] = 0; ++ b0[0] = 0xaa; ++ b0[1] = state->c++; ++ b0[2] = PCTV_CMD_RESET; ++ b0[3] = 1; ++ b0[4] = 0; + /* reset board */ +- ret = dvb_usb_generic_rw(d, state->data, 5, rx, PCTV_ANSWER_LEN, 0); ++ ret = dvb_usb_generic_rw(d, b0, 5, rx, PCTV_ANSWER_LEN, 0); + if (ret) + goto ret; + +- state->data[1] = state->c++; +- state->data[4] = 1; ++ b0[1] = state->c++; ++ b0[4] = 1; + /* reset board (again?) */ +- ret = dvb_usb_generic_rw(d, state->data, 5, rx, PCTV_ANSWER_LEN, 0); ++ ret = dvb_usb_generic_rw(d, b0, 5, rx, PCTV_ANSWER_LEN, 0); + if (ret) + goto ret; + + state->initialized = 1; + + ret: +- mutex_unlock(&state->ca_mutex); +- kfree(rx); ++ kfree(b0); + return ret; + } + + static int pctv452e_rc_query(struct dvb_usb_device *d) + { + struct pctv452e_state *state = (struct pctv452e_state *)d->priv; ++ u8 *b, *rx; + int ret, i; + u8 id; + +- mutex_lock(&state->ca_mutex); ++ b = kmalloc(CMD_BUFFER_SIZE + PCTV_ANSWER_LEN, GFP_KERNEL); ++ if (!b) ++ return -ENOMEM; ++ ++ rx = b + CMD_BUFFER_SIZE; ++ + id = state->c++; + + /* prepare command header */ +- state->data[0] = SYNC_BYTE_OUT; +- state->data[1] = id; +- state->data[2] = PCTV_CMD_IR; +- state->data[3] = 0; ++ b[0] = SYNC_BYTE_OUT; ++ b[1] = id; ++ b[2] = PCTV_CMD_IR; ++ b[3] = 0; + + /* send ir request */ +- ret = dvb_usb_generic_rw(d, state->data, 4, +- state->data, PCTV_ANSWER_LEN, 0); ++ ret = dvb_usb_generic_rw(d, b, 4, rx, PCTV_ANSWER_LEN, 0); + if (ret != 0) + goto ret; + + if (debug > 3) { +- info("%s: read: %2d: %*ph: ", __func__, ret, 3, state->data); +- for (i = 0; (i < state->data[3]) && ((i + 3) < PCTV_ANSWER_LEN); i++) +- info(" %02x", state->data[i + 3]); ++ info("%s: read: %2d: %*ph: ", __func__, ret, 3, rx); ++ for (i = 0; (i < rx[3]) && ((i+3) < PCTV_ANSWER_LEN); i++) ++ info(" %02x", rx[i+3]); + + info("\n"); + } + +- if ((state->data[3] == 9) && (state->data[12] & 0x01)) { ++ if ((rx[3] == 9) && (rx[12] & 0x01)) { + /* got a "press" event */ +- state->last_rc_key = RC_SCANCODE_RC5(state->data[7], state->data[6]); ++ state->last_rc_key = RC_SCANCODE_RC5(rx[7], rx[6]); + if (debug > 2) + info("%s: cmd=0x%02x sys=0x%02x\n", +- __func__, state->data[6], state->data[7]); ++ __func__, rx[6], rx[7]); + + rc_keydown(d->rc_dev, RC_TYPE_RC5, state->last_rc_key, 0); + } else if (state->last_rc_key) { +@@ -595,7 +606,7 @@ static int pctv452e_rc_query(struct dvb_usb_device *d) + state->last_rc_key = 0; + } + ret: +- mutex_unlock(&state->ca_mutex); ++ kfree(b); + return ret; + } +