Commit e5aeebdd authored by Zijun Hu's avatar Zijun Hu Committed by Marcel Holtmann

Bluetooth: hci_qca: Fix QCA6390 memdump failure

QCA6390 memdump VSE sometimes come to bluetooth driver
with wrong sequence number as illustrated as follows:
frame # in dec: frame data in hex
1396: ff fd 01 08 74 05 00 37 8f 14
1397: ff fd 01 08 75 05 00 ff bf 38
1414: ff fd 01 08 86 05 00 fb 5e 4b
1399: ff fd 01 08 77 05 00 f3 44 0a
1400: ff fd 01 08 78 05 00 ca f7 41
it is mistook for controller missing packets, so results
in page fault after overwriting memdump buffer allocated.

Fixed by ignoring QCA6390 sequence number check and
checking buffer space before writing.
Signed-off-by: default avatarZijun Hu <zijuhu@codeaurora.org>
Tested-by: default avatarZijun Hu <zijuhu@codeaurora.org>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent d3a0fe6b
...@@ -114,6 +114,7 @@ struct qca_memdump_data { ...@@ -114,6 +114,7 @@ struct qca_memdump_data {
char *memdump_buf_tail; char *memdump_buf_tail;
u32 current_seq_no; u32 current_seq_no;
u32 received_dump; u32 received_dump;
u32 ram_dump_size;
}; };
struct qca_memdump_event_hdr { struct qca_memdump_event_hdr {
...@@ -976,6 +977,8 @@ static void qca_controller_memdump(struct work_struct *work) ...@@ -976,6 +977,8 @@ static void qca_controller_memdump(struct work_struct *work)
char nullBuff[QCA_DUMP_PACKET_SIZE] = { 0 }; char nullBuff[QCA_DUMP_PACKET_SIZE] = { 0 };
u16 seq_no; u16 seq_no;
u32 dump_size; u32 dump_size;
u32 rx_size;
enum qca_btsoc_type soc_type = qca_soc_type(hu);
while ((skb = skb_dequeue(&qca->rx_memdump_q))) { while ((skb = skb_dequeue(&qca->rx_memdump_q))) {
...@@ -1025,10 +1028,12 @@ static void qca_controller_memdump(struct work_struct *work) ...@@ -1025,10 +1028,12 @@ static void qca_controller_memdump(struct work_struct *work)
dump_size); dump_size);
queue_delayed_work(qca->workqueue, queue_delayed_work(qca->workqueue,
&qca->ctrl_memdump_timeout, &qca->ctrl_memdump_timeout,
msecs_to_jiffies(MEMDUMP_TIMEOUT_MS)); msecs_to_jiffies(MEMDUMP_TIMEOUT_MS)
);
skb_pull(skb, sizeof(dump_size)); skb_pull(skb, sizeof(dump_size));
memdump_buf = vmalloc(dump_size); memdump_buf = vmalloc(dump_size);
qca_memdump->ram_dump_size = dump_size;
qca_memdump->memdump_buf_head = memdump_buf; qca_memdump->memdump_buf_head = memdump_buf;
qca_memdump->memdump_buf_tail = memdump_buf; qca_memdump->memdump_buf_tail = memdump_buf;
} }
...@@ -1051,26 +1056,57 @@ static void qca_controller_memdump(struct work_struct *work) ...@@ -1051,26 +1056,57 @@ static void qca_controller_memdump(struct work_struct *work)
* the controller. In such cases let us store the dummy * the controller. In such cases let us store the dummy
* packets in the buffer. * packets in the buffer.
*/ */
/* For QCA6390, controller does not lost packets but
* sequence number field of packat sometimes has error
* bits, so skip this checking for missing packet.
*/
while ((seq_no > qca_memdump->current_seq_no + 1) && while ((seq_no > qca_memdump->current_seq_no + 1) &&
(soc_type != QCA_QCA6390) &&
seq_no != QCA_LAST_SEQUENCE_NUM) { seq_no != QCA_LAST_SEQUENCE_NUM) {
bt_dev_err(hu->hdev, "QCA controller missed packet:%d", bt_dev_err(hu->hdev, "QCA controller missed packet:%d",
qca_memdump->current_seq_no); qca_memdump->current_seq_no);
rx_size = qca_memdump->received_dump;
rx_size += QCA_DUMP_PACKET_SIZE;
if (rx_size > qca_memdump->ram_dump_size) {
bt_dev_err(hu->hdev,
"QCA memdump received %d, no space for missed packet",
qca_memdump->received_dump);
break;
}
memcpy(memdump_buf, nullBuff, QCA_DUMP_PACKET_SIZE); memcpy(memdump_buf, nullBuff, QCA_DUMP_PACKET_SIZE);
memdump_buf = memdump_buf + QCA_DUMP_PACKET_SIZE; memdump_buf = memdump_buf + QCA_DUMP_PACKET_SIZE;
qca_memdump->received_dump += QCA_DUMP_PACKET_SIZE; qca_memdump->received_dump += QCA_DUMP_PACKET_SIZE;
qca_memdump->current_seq_no++; qca_memdump->current_seq_no++;
} }
memcpy(memdump_buf, (unsigned char *) skb->data, skb->len); rx_size = qca_memdump->received_dump + skb->len;
if (rx_size <= qca_memdump->ram_dump_size) {
if ((seq_no != QCA_LAST_SEQUENCE_NUM) &&
(seq_no != qca_memdump->current_seq_no))
bt_dev_err(hu->hdev,
"QCA memdump unexpected packet %d",
seq_no);
bt_dev_dbg(hu->hdev,
"QCA memdump packet %d with length %d",
seq_no, skb->len);
memcpy(memdump_buf, (unsigned char *)skb->data,
skb->len);
memdump_buf = memdump_buf + skb->len; memdump_buf = memdump_buf + skb->len;
qca_memdump->memdump_buf_tail = memdump_buf; qca_memdump->memdump_buf_tail = memdump_buf;
qca_memdump->current_seq_no = seq_no + 1; qca_memdump->current_seq_no = seq_no + 1;
qca_memdump->received_dump += skb->len; qca_memdump->received_dump += skb->len;
} else {
bt_dev_err(hu->hdev,
"QCA memdump received %d, no space for packet %d",
qca_memdump->received_dump, seq_no);
}
qca->qca_memdump = qca_memdump; qca->qca_memdump = qca_memdump;
kfree_skb(skb); kfree_skb(skb);
if (seq_no == QCA_LAST_SEQUENCE_NUM) { if (seq_no == QCA_LAST_SEQUENCE_NUM) {
bt_dev_info(hu->hdev, "QCA writing crash dump of size %d bytes", bt_dev_info(hu->hdev,
qca_memdump->received_dump); "QCA memdump Done, received %d, total %d",
qca_memdump->received_dump,
qca_memdump->ram_dump_size);
memdump_buf = qca_memdump->memdump_buf_head; memdump_buf = qca_memdump->memdump_buf_head;
dev_coredumpv(&hu->serdev->dev, memdump_buf, dev_coredumpv(&hu->serdev->dev, memdump_buf,
qca_memdump->received_dump, GFP_KERNEL); qca_memdump->received_dump, GFP_KERNEL);
......
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