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: Zijun Hu <zijuhu@codeaurora.org> Tested-by: Zijun Hu <zijuhu@codeaurora.org> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
committed by
Marcel Holtmann
parent
d3a0fe6b09
commit
e5aeebddfc
@@ -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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
* 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) &&
|
||||||
seq_no != QCA_LAST_SEQUENCE_NUM) {
|
(soc_type != QCA_QCA6390) &&
|
||||||
|
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;
|
||||||
memdump_buf = memdump_buf + skb->len;
|
if (rx_size <= qca_memdump->ram_dump_size) {
|
||||||
qca_memdump->memdump_buf_tail = memdump_buf;
|
if ((seq_no != QCA_LAST_SEQUENCE_NUM) &&
|
||||||
qca_memdump->current_seq_no = seq_no + 1;
|
(seq_no != qca_memdump->current_seq_no))
|
||||||
qca_memdump->received_dump += skb->len;
|
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;
|
||||||
|
qca_memdump->memdump_buf_tail = memdump_buf;
|
||||||
|
qca_memdump->current_seq_no = seq_no + 1;
|
||||||
|
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);
|
||||||
|
|||||||
Reference in New Issue
Block a user