Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Bluetooth: Add support for hci devcoredump

Add devcoredump APIs to hci core so that drivers only have to provide
the dump skbs instead of managing the synchronization and timeouts.

The devcoredump APIs should be used in the following manner:
- hci_devcoredump_init is called to allocate the dump.
- hci_devcoredump_append is called to append any skbs with dump data
OR hci_devcoredump_append_pattern is called to insert a pattern.
- hci_devcoredump_complete is called when all dump packets have been
sent OR hci_devcoredump_abort is called to indicate an error and
cancel an ongoing dump collection.

The high level APIs just prepare some skbs with the appropriate data and
queue it for the dump to process. Packets part of the crashdump can be
intercepted in the driver in interrupt context and forwarded directly to
the devcoredump APIs.

Internally, there are 5 states for the dump: idle, active, complete,
abort and timeout. A devcoredump will only be in active state after it
has been initialized. Once active, it accepts data to be appended,
patterns to be inserted (i.e. memset) and a completion event or an abort
event to generate a devcoredump. The timeout is initialized at the same
time the dump is initialized (defaulting to 10s) and will be cleared
either when the timeout occurs or the dump is complete or aborted.

Signed-off-by: Abhishek Pandit-Subedi <abhishekpandit@chromium.org>
Signed-off-by: Manish Mandlik <mmandlik@google.com>
Reviewed-by: Abhishek Pandit-Subedi <abhishekpandit@chromium.org>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

authored by

Abhishek Pandit-Subedi and committed by
Luiz Augusto von Dentz
9695ef87 77f542b1

+670
+116
include/net/bluetooth/coredump.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * Copyright (C) 2022 Google Corporation 4 + */ 5 + 6 + #ifndef __COREDUMP_H 7 + #define __COREDUMP_H 8 + 9 + #define DEVCOREDUMP_TIMEOUT msecs_to_jiffies(10000) /* 10 sec */ 10 + 11 + typedef void (*coredump_t)(struct hci_dev *hdev); 12 + typedef void (*dmp_hdr_t)(struct hci_dev *hdev, struct sk_buff *skb); 13 + typedef void (*notify_change_t)(struct hci_dev *hdev, int state); 14 + 15 + /* struct hci_devcoredump - Devcoredump state 16 + * 17 + * @supported: Indicates if FW dump collection is supported by driver 18 + * @state: Current state of dump collection 19 + * @timeout: Indicates a timeout for collecting the devcoredump 20 + * 21 + * @alloc_size: Total size of the dump 22 + * @head: Start of the dump 23 + * @tail: Pointer to current end of dump 24 + * @end: head + alloc_size for easy comparisons 25 + * 26 + * @dump_q: Dump queue for state machine to process 27 + * @dump_rx: Devcoredump state machine work 28 + * @dump_timeout: Devcoredump timeout work 29 + * 30 + * @coredump: Called from the driver's .coredump() function. 31 + * @dmp_hdr: Create a dump header to identify controller/fw/driver info 32 + * @notify_change: Notify driver when devcoredump state has changed 33 + */ 34 + struct hci_devcoredump { 35 + bool supported; 36 + 37 + enum devcoredump_state { 38 + HCI_DEVCOREDUMP_IDLE, 39 + HCI_DEVCOREDUMP_ACTIVE, 40 + HCI_DEVCOREDUMP_DONE, 41 + HCI_DEVCOREDUMP_ABORT, 42 + HCI_DEVCOREDUMP_TIMEOUT, 43 + } state; 44 + 45 + unsigned long timeout; 46 + 47 + size_t alloc_size; 48 + char *head; 49 + char *tail; 50 + char *end; 51 + 52 + struct sk_buff_head dump_q; 53 + struct work_struct dump_rx; 54 + struct delayed_work dump_timeout; 55 + 56 + coredump_t coredump; 57 + dmp_hdr_t dmp_hdr; 58 + notify_change_t notify_change; 59 + }; 60 + 61 + #ifdef CONFIG_DEV_COREDUMP 62 + 63 + void hci_devcd_reset(struct hci_dev *hdev); 64 + void hci_devcd_rx(struct work_struct *work); 65 + void hci_devcd_timeout(struct work_struct *work); 66 + 67 + int hci_devcd_register(struct hci_dev *hdev, coredump_t coredump, 68 + dmp_hdr_t dmp_hdr, notify_change_t notify_change); 69 + int hci_devcd_init(struct hci_dev *hdev, u32 dump_size); 70 + int hci_devcd_append(struct hci_dev *hdev, struct sk_buff *skb); 71 + int hci_devcd_append_pattern(struct hci_dev *hdev, u8 pattern, u32 len); 72 + int hci_devcd_complete(struct hci_dev *hdev); 73 + int hci_devcd_abort(struct hci_dev *hdev); 74 + 75 + #else 76 + 77 + static inline void hci_devcd_reset(struct hci_dev *hdev) {} 78 + static inline void hci_devcd_rx(struct work_struct *work) {} 79 + static inline void hci_devcd_timeout(struct work_struct *work) {} 80 + 81 + static inline int hci_devcd_register(struct hci_dev *hdev, coredump_t coredump, 82 + dmp_hdr_t dmp_hdr, 83 + notify_change_t notify_change) 84 + { 85 + return -EOPNOTSUPP; 86 + } 87 + 88 + static inline int hci_devcd_init(struct hci_dev *hdev, u32 dump_size) 89 + { 90 + return -EOPNOTSUPP; 91 + } 92 + 93 + static inline int hci_devcd_append(struct hci_dev *hdev, struct sk_buff *skb) 94 + { 95 + return -EOPNOTSUPP; 96 + } 97 + 98 + static inline int hci_devcd_append_pattern(struct hci_dev *hdev, 99 + u8 pattern, u32 len) 100 + { 101 + return -EOPNOTSUPP; 102 + } 103 + 104 + static inline int hci_devcd_complete(struct hci_dev *hdev) 105 + { 106 + return -EOPNOTSUPP; 107 + } 108 + 109 + static inline int hci_devcd_abort(struct hci_dev *hdev) 110 + { 111 + return -EOPNOTSUPP; 112 + } 113 + 114 + #endif /* CONFIG_DEV_COREDUMP */ 115 + 116 + #endif /* __COREDUMP_H */
+14
include/net/bluetooth/hci_core.h
··· 32 32 #include <net/bluetooth/hci.h> 33 33 #include <net/bluetooth/hci_sync.h> 34 34 #include <net/bluetooth/hci_sock.h> 35 + #include <net/bluetooth/coredump.h> 35 36 36 37 /* HCI priority */ 37 38 #define HCI_PRIO_MAX 7 ··· 590 589 const char *hw_info; 591 590 const char *fw_info; 592 591 struct dentry *debugfs; 592 + 593 + #ifdef CONFIG_DEV_COREDUMP 594 + struct hci_devcoredump dump; 595 + #endif 593 596 594 597 struct device dev; 595 598 ··· 1499 1494 { 1500 1495 #if IS_ENABLED(CONFIG_BT_AOSPEXT) 1501 1496 hdev->aosp_capable = true; 1497 + #endif 1498 + } 1499 + 1500 + static inline void hci_devcd_setup(struct hci_dev *hdev) 1501 + { 1502 + #ifdef CONFIG_DEV_COREDUMP 1503 + INIT_WORK(&hdev->dump.dump_rx, hci_devcd_rx); 1504 + INIT_DELAYED_WORK(&hdev->dump.dump_timeout, hci_devcd_timeout); 1505 + skb_queue_head_init(&hdev->dump.dump_q); 1502 1506 #endif 1503 1507 } 1504 1508
+2
net/bluetooth/Makefile
··· 17 17 ecdh_helper.o hci_request.o mgmt_util.o mgmt_config.o hci_codec.o \ 18 18 eir.o hci_sync.o 19 19 20 + bluetooth-$(CONFIG_DEV_COREDUMP) += coredump.o 21 + 20 22 bluetooth-$(CONFIG_BT_BREDR) += sco.o 21 23 bluetooth-$(CONFIG_BT_LE) += iso.o 22 24 bluetooth-$(CONFIG_BT_HS) += a2mp.o amp.o
+535
net/bluetooth/coredump.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright (C) 2023 Google Corporation 4 + */ 5 + 6 + #include <linux/devcoredump.h> 7 + 8 + #include <net/bluetooth/bluetooth.h> 9 + #include <net/bluetooth/hci_core.h> 10 + 11 + enum hci_devcoredump_pkt_type { 12 + HCI_DEVCOREDUMP_PKT_INIT, 13 + HCI_DEVCOREDUMP_PKT_SKB, 14 + HCI_DEVCOREDUMP_PKT_PATTERN, 15 + HCI_DEVCOREDUMP_PKT_COMPLETE, 16 + HCI_DEVCOREDUMP_PKT_ABORT, 17 + }; 18 + 19 + struct hci_devcoredump_skb_cb { 20 + u16 pkt_type; 21 + }; 22 + 23 + struct hci_devcoredump_skb_pattern { 24 + u8 pattern; 25 + u32 len; 26 + } __packed; 27 + 28 + #define hci_dmp_cb(skb) ((struct hci_devcoredump_skb_cb *)((skb)->cb)) 29 + 30 + #define DBG_UNEXPECTED_STATE() \ 31 + bt_dev_dbg(hdev, \ 32 + "Unexpected packet (%d) for state (%d). ", \ 33 + hci_dmp_cb(skb)->pkt_type, hdev->dump.state) 34 + 35 + #define MAX_DEVCOREDUMP_HDR_SIZE 512 /* bytes */ 36 + 37 + static int hci_devcd_update_hdr_state(char *buf, size_t size, int state) 38 + { 39 + int len = 0; 40 + 41 + if (!buf) 42 + return 0; 43 + 44 + len = scnprintf(buf, size, "Bluetooth devcoredump\nState: %d\n", state); 45 + 46 + return len + 1; /* scnprintf adds \0 at the end upon state rewrite */ 47 + } 48 + 49 + /* Call with hci_dev_lock only. */ 50 + static int hci_devcd_update_state(struct hci_dev *hdev, int state) 51 + { 52 + bt_dev_dbg(hdev, "Updating devcoredump state from %d to %d.", 53 + hdev->dump.state, state); 54 + 55 + hdev->dump.state = state; 56 + 57 + return hci_devcd_update_hdr_state(hdev->dump.head, 58 + hdev->dump.alloc_size, state); 59 + } 60 + 61 + static int hci_devcd_mkheader(struct hci_dev *hdev, struct sk_buff *skb) 62 + { 63 + char dump_start[] = "--- Start dump ---\n"; 64 + char hdr[80]; 65 + int hdr_len; 66 + 67 + hdr_len = hci_devcd_update_hdr_state(hdr, sizeof(hdr), 68 + HCI_DEVCOREDUMP_IDLE); 69 + skb_put_data(skb, hdr, hdr_len); 70 + 71 + if (hdev->dump.dmp_hdr) 72 + hdev->dump.dmp_hdr(hdev, skb); 73 + 74 + skb_put_data(skb, dump_start, strlen(dump_start)); 75 + 76 + return skb->len; 77 + } 78 + 79 + /* Do not call with hci_dev_lock since this calls driver code. */ 80 + static void hci_devcd_notify(struct hci_dev *hdev, int state) 81 + { 82 + if (hdev->dump.notify_change) 83 + hdev->dump.notify_change(hdev, state); 84 + } 85 + 86 + /* Call with hci_dev_lock only. */ 87 + void hci_devcd_reset(struct hci_dev *hdev) 88 + { 89 + hdev->dump.head = NULL; 90 + hdev->dump.tail = NULL; 91 + hdev->dump.alloc_size = 0; 92 + 93 + hci_devcd_update_state(hdev, HCI_DEVCOREDUMP_IDLE); 94 + 95 + cancel_delayed_work(&hdev->dump.dump_timeout); 96 + skb_queue_purge(&hdev->dump.dump_q); 97 + } 98 + 99 + /* Call with hci_dev_lock only. */ 100 + static void hci_devcd_free(struct hci_dev *hdev) 101 + { 102 + if (hdev->dump.head) 103 + vfree(hdev->dump.head); 104 + 105 + hci_devcd_reset(hdev); 106 + } 107 + 108 + /* Call with hci_dev_lock only. */ 109 + static int hci_devcd_alloc(struct hci_dev *hdev, u32 size) 110 + { 111 + hdev->dump.head = vmalloc(size); 112 + if (!hdev->dump.head) 113 + return -ENOMEM; 114 + 115 + hdev->dump.alloc_size = size; 116 + hdev->dump.tail = hdev->dump.head; 117 + hdev->dump.end = hdev->dump.head + size; 118 + 119 + hci_devcd_update_state(hdev, HCI_DEVCOREDUMP_IDLE); 120 + 121 + return 0; 122 + } 123 + 124 + /* Call with hci_dev_lock only. */ 125 + static bool hci_devcd_copy(struct hci_dev *hdev, char *buf, u32 size) 126 + { 127 + if (hdev->dump.tail + size > hdev->dump.end) 128 + return false; 129 + 130 + memcpy(hdev->dump.tail, buf, size); 131 + hdev->dump.tail += size; 132 + 133 + return true; 134 + } 135 + 136 + /* Call with hci_dev_lock only. */ 137 + static bool hci_devcd_memset(struct hci_dev *hdev, u8 pattern, u32 len) 138 + { 139 + if (hdev->dump.tail + len > hdev->dump.end) 140 + return false; 141 + 142 + memset(hdev->dump.tail, pattern, len); 143 + hdev->dump.tail += len; 144 + 145 + return true; 146 + } 147 + 148 + /* Call with hci_dev_lock only. */ 149 + static int hci_devcd_prepare(struct hci_dev *hdev, u32 dump_size) 150 + { 151 + struct sk_buff *skb; 152 + int dump_hdr_size; 153 + int err = 0; 154 + 155 + skb = alloc_skb(MAX_DEVCOREDUMP_HDR_SIZE, GFP_ATOMIC); 156 + if (!skb) 157 + return -ENOMEM; 158 + 159 + dump_hdr_size = hci_devcd_mkheader(hdev, skb); 160 + 161 + if (hci_devcd_alloc(hdev, dump_hdr_size + dump_size)) { 162 + err = -ENOMEM; 163 + goto hdr_free; 164 + } 165 + 166 + /* Insert the device header */ 167 + if (!hci_devcd_copy(hdev, skb->data, skb->len)) { 168 + bt_dev_err(hdev, "Failed to insert header"); 169 + hci_devcd_free(hdev); 170 + 171 + err = -ENOMEM; 172 + goto hdr_free; 173 + } 174 + 175 + hdr_free: 176 + kfree_skb(skb); 177 + 178 + return err; 179 + } 180 + 181 + static void hci_devcd_handle_pkt_init(struct hci_dev *hdev, struct sk_buff *skb) 182 + { 183 + u32 *dump_size; 184 + 185 + if (hdev->dump.state != HCI_DEVCOREDUMP_IDLE) { 186 + DBG_UNEXPECTED_STATE(); 187 + return; 188 + } 189 + 190 + if (skb->len != sizeof(*dump_size)) { 191 + bt_dev_dbg(hdev, "Invalid dump init pkt"); 192 + return; 193 + } 194 + 195 + dump_size = skb_pull_data(skb, sizeof(*dump_size)); 196 + if (!*dump_size) { 197 + bt_dev_err(hdev, "Zero size dump init pkt"); 198 + return; 199 + } 200 + 201 + if (hci_devcd_prepare(hdev, *dump_size)) { 202 + bt_dev_err(hdev, "Failed to prepare for dump"); 203 + return; 204 + } 205 + 206 + hci_devcd_update_state(hdev, HCI_DEVCOREDUMP_ACTIVE); 207 + queue_delayed_work(hdev->workqueue, &hdev->dump.dump_timeout, 208 + hdev->dump.timeout); 209 + } 210 + 211 + static void hci_devcd_handle_pkt_skb(struct hci_dev *hdev, struct sk_buff *skb) 212 + { 213 + if (hdev->dump.state != HCI_DEVCOREDUMP_ACTIVE) { 214 + DBG_UNEXPECTED_STATE(); 215 + return; 216 + } 217 + 218 + if (!hci_devcd_copy(hdev, skb->data, skb->len)) 219 + bt_dev_dbg(hdev, "Failed to insert skb"); 220 + } 221 + 222 + static void hci_devcd_handle_pkt_pattern(struct hci_dev *hdev, 223 + struct sk_buff *skb) 224 + { 225 + struct hci_devcoredump_skb_pattern *pattern; 226 + 227 + if (hdev->dump.state != HCI_DEVCOREDUMP_ACTIVE) { 228 + DBG_UNEXPECTED_STATE(); 229 + return; 230 + } 231 + 232 + if (skb->len != sizeof(*pattern)) { 233 + bt_dev_dbg(hdev, "Invalid pattern skb"); 234 + return; 235 + } 236 + 237 + pattern = skb_pull_data(skb, sizeof(*pattern)); 238 + 239 + if (!hci_devcd_memset(hdev, pattern->pattern, pattern->len)) 240 + bt_dev_dbg(hdev, "Failed to set pattern"); 241 + } 242 + 243 + static void hci_devcd_handle_pkt_complete(struct hci_dev *hdev, 244 + struct sk_buff *skb) 245 + { 246 + u32 dump_size; 247 + 248 + if (hdev->dump.state != HCI_DEVCOREDUMP_ACTIVE) { 249 + DBG_UNEXPECTED_STATE(); 250 + return; 251 + } 252 + 253 + hci_devcd_update_state(hdev, HCI_DEVCOREDUMP_DONE); 254 + dump_size = hdev->dump.tail - hdev->dump.head; 255 + 256 + bt_dev_dbg(hdev, "complete with size %u (expect %zu)", dump_size, 257 + hdev->dump.alloc_size); 258 + 259 + dev_coredumpv(&hdev->dev, hdev->dump.head, dump_size, GFP_KERNEL); 260 + } 261 + 262 + static void hci_devcd_handle_pkt_abort(struct hci_dev *hdev, 263 + struct sk_buff *skb) 264 + { 265 + u32 dump_size; 266 + 267 + if (hdev->dump.state != HCI_DEVCOREDUMP_ACTIVE) { 268 + DBG_UNEXPECTED_STATE(); 269 + return; 270 + } 271 + 272 + hci_devcd_update_state(hdev, HCI_DEVCOREDUMP_ABORT); 273 + dump_size = hdev->dump.tail - hdev->dump.head; 274 + 275 + bt_dev_dbg(hdev, "aborted with size %u (expect %zu)", dump_size, 276 + hdev->dump.alloc_size); 277 + 278 + /* Emit a devcoredump with the available data */ 279 + dev_coredumpv(&hdev->dev, hdev->dump.head, dump_size, GFP_KERNEL); 280 + } 281 + 282 + /* Bluetooth devcoredump state machine. 283 + * 284 + * Devcoredump states: 285 + * 286 + * HCI_DEVCOREDUMP_IDLE: The default state. 287 + * 288 + * HCI_DEVCOREDUMP_ACTIVE: A devcoredump will be in this state once it has 289 + * been initialized using hci_devcd_init(). Once active, the driver 290 + * can append data using hci_devcd_append() or insert a pattern 291 + * using hci_devcd_append_pattern(). 292 + * 293 + * HCI_DEVCOREDUMP_DONE: Once the dump collection is complete, the drive 294 + * can signal the completion using hci_devcd_complete(). A 295 + * devcoredump is generated indicating the completion event and 296 + * then the state machine is reset to the default state. 297 + * 298 + * HCI_DEVCOREDUMP_ABORT: The driver can cancel ongoing dump collection in 299 + * case of any error using hci_devcd_abort(). A devcoredump is 300 + * still generated with the available data indicating the abort 301 + * event and then the state machine is reset to the default state. 302 + * 303 + * HCI_DEVCOREDUMP_TIMEOUT: A timeout timer for HCI_DEVCOREDUMP_TIMEOUT sec 304 + * is started during devcoredump initialization. Once the timeout 305 + * occurs, the driver is notified, a devcoredump is generated with 306 + * the available data indicating the timeout event and then the 307 + * state machine is reset to the default state. 308 + * 309 + * The driver must register using hci_devcd_register() before using the hci 310 + * devcoredump APIs. 311 + */ 312 + void hci_devcd_rx(struct work_struct *work) 313 + { 314 + struct hci_dev *hdev = container_of(work, struct hci_dev, dump.dump_rx); 315 + struct sk_buff *skb; 316 + int start_state; 317 + 318 + while ((skb = skb_dequeue(&hdev->dump.dump_q))) { 319 + /* Return if timeout occurs. The timeout handler function 320 + * hci_devcd_timeout() will report the available dump data. 321 + */ 322 + if (hdev->dump.state == HCI_DEVCOREDUMP_TIMEOUT) { 323 + kfree_skb(skb); 324 + return; 325 + } 326 + 327 + hci_dev_lock(hdev); 328 + start_state = hdev->dump.state; 329 + 330 + switch (hci_dmp_cb(skb)->pkt_type) { 331 + case HCI_DEVCOREDUMP_PKT_INIT: 332 + hci_devcd_handle_pkt_init(hdev, skb); 333 + break; 334 + 335 + case HCI_DEVCOREDUMP_PKT_SKB: 336 + hci_devcd_handle_pkt_skb(hdev, skb); 337 + break; 338 + 339 + case HCI_DEVCOREDUMP_PKT_PATTERN: 340 + hci_devcd_handle_pkt_pattern(hdev, skb); 341 + break; 342 + 343 + case HCI_DEVCOREDUMP_PKT_COMPLETE: 344 + hci_devcd_handle_pkt_complete(hdev, skb); 345 + break; 346 + 347 + case HCI_DEVCOREDUMP_PKT_ABORT: 348 + hci_devcd_handle_pkt_abort(hdev, skb); 349 + break; 350 + 351 + default: 352 + bt_dev_dbg(hdev, "Unknown packet (%d) for state (%d). ", 353 + hci_dmp_cb(skb)->pkt_type, hdev->dump.state); 354 + break; 355 + } 356 + 357 + hci_dev_unlock(hdev); 358 + kfree_skb(skb); 359 + 360 + /* Notify the driver about any state changes before resetting 361 + * the state machine 362 + */ 363 + if (start_state != hdev->dump.state) 364 + hci_devcd_notify(hdev, hdev->dump.state); 365 + 366 + /* Reset the state machine if the devcoredump is complete */ 367 + hci_dev_lock(hdev); 368 + if (hdev->dump.state == HCI_DEVCOREDUMP_DONE || 369 + hdev->dump.state == HCI_DEVCOREDUMP_ABORT) 370 + hci_devcd_reset(hdev); 371 + hci_dev_unlock(hdev); 372 + } 373 + } 374 + EXPORT_SYMBOL(hci_devcd_rx); 375 + 376 + void hci_devcd_timeout(struct work_struct *work) 377 + { 378 + struct hci_dev *hdev = container_of(work, struct hci_dev, 379 + dump.dump_timeout.work); 380 + u32 dump_size; 381 + 382 + hci_devcd_notify(hdev, HCI_DEVCOREDUMP_TIMEOUT); 383 + 384 + hci_dev_lock(hdev); 385 + 386 + cancel_work(&hdev->dump.dump_rx); 387 + 388 + hci_devcd_update_state(hdev, HCI_DEVCOREDUMP_TIMEOUT); 389 + 390 + dump_size = hdev->dump.tail - hdev->dump.head; 391 + bt_dev_dbg(hdev, "timeout with size %u (expect %zu)", dump_size, 392 + hdev->dump.alloc_size); 393 + 394 + /* Emit a devcoredump with the available data */ 395 + dev_coredumpv(&hdev->dev, hdev->dump.head, dump_size, GFP_KERNEL); 396 + 397 + hci_devcd_reset(hdev); 398 + 399 + hci_dev_unlock(hdev); 400 + } 401 + EXPORT_SYMBOL(hci_devcd_timeout); 402 + 403 + int hci_devcd_register(struct hci_dev *hdev, coredump_t coredump, 404 + dmp_hdr_t dmp_hdr, notify_change_t notify_change) 405 + { 406 + /* Driver must implement coredump() and dmp_hdr() functions for 407 + * bluetooth devcoredump. The coredump() should trigger a coredump 408 + * event on the controller when the device's coredump sysfs entry is 409 + * written to. The dmp_hdr() should create a dump header to identify 410 + * the controller/fw/driver info. 411 + */ 412 + if (!coredump || !dmp_hdr) 413 + return -EINVAL; 414 + 415 + hci_dev_lock(hdev); 416 + hdev->dump.coredump = coredump; 417 + hdev->dump.dmp_hdr = dmp_hdr; 418 + hdev->dump.notify_change = notify_change; 419 + hdev->dump.supported = true; 420 + hdev->dump.timeout = DEVCOREDUMP_TIMEOUT; 421 + hci_dev_unlock(hdev); 422 + 423 + return 0; 424 + } 425 + EXPORT_SYMBOL(hci_devcd_register); 426 + 427 + static inline bool hci_devcd_enabled(struct hci_dev *hdev) 428 + { 429 + return hdev->dump.supported; 430 + } 431 + 432 + int hci_devcd_init(struct hci_dev *hdev, u32 dump_size) 433 + { 434 + struct sk_buff *skb; 435 + 436 + if (!hci_devcd_enabled(hdev)) 437 + return -EOPNOTSUPP; 438 + 439 + skb = alloc_skb(sizeof(dump_size), GFP_ATOMIC); 440 + if (!skb) 441 + return -ENOMEM; 442 + 443 + hci_dmp_cb(skb)->pkt_type = HCI_DEVCOREDUMP_PKT_INIT; 444 + skb_put_data(skb, &dump_size, sizeof(dump_size)); 445 + 446 + skb_queue_tail(&hdev->dump.dump_q, skb); 447 + queue_work(hdev->workqueue, &hdev->dump.dump_rx); 448 + 449 + return 0; 450 + } 451 + EXPORT_SYMBOL(hci_devcd_init); 452 + 453 + int hci_devcd_append(struct hci_dev *hdev, struct sk_buff *skb) 454 + { 455 + if (!skb) 456 + return -ENOMEM; 457 + 458 + if (!hci_devcd_enabled(hdev)) { 459 + kfree_skb(skb); 460 + return -EOPNOTSUPP; 461 + } 462 + 463 + hci_dmp_cb(skb)->pkt_type = HCI_DEVCOREDUMP_PKT_SKB; 464 + 465 + skb_queue_tail(&hdev->dump.dump_q, skb); 466 + queue_work(hdev->workqueue, &hdev->dump.dump_rx); 467 + 468 + return 0; 469 + } 470 + EXPORT_SYMBOL(hci_devcd_append); 471 + 472 + int hci_devcd_append_pattern(struct hci_dev *hdev, u8 pattern, u32 len) 473 + { 474 + struct hci_devcoredump_skb_pattern p; 475 + struct sk_buff *skb; 476 + 477 + if (!hci_devcd_enabled(hdev)) 478 + return -EOPNOTSUPP; 479 + 480 + skb = alloc_skb(sizeof(p), GFP_ATOMIC); 481 + if (!skb) 482 + return -ENOMEM; 483 + 484 + p.pattern = pattern; 485 + p.len = len; 486 + 487 + hci_dmp_cb(skb)->pkt_type = HCI_DEVCOREDUMP_PKT_PATTERN; 488 + skb_put_data(skb, &p, sizeof(p)); 489 + 490 + skb_queue_tail(&hdev->dump.dump_q, skb); 491 + queue_work(hdev->workqueue, &hdev->dump.dump_rx); 492 + 493 + return 0; 494 + } 495 + EXPORT_SYMBOL(hci_devcd_append_pattern); 496 + 497 + int hci_devcd_complete(struct hci_dev *hdev) 498 + { 499 + struct sk_buff *skb; 500 + 501 + if (!hci_devcd_enabled(hdev)) 502 + return -EOPNOTSUPP; 503 + 504 + skb = alloc_skb(0, GFP_ATOMIC); 505 + if (!skb) 506 + return -ENOMEM; 507 + 508 + hci_dmp_cb(skb)->pkt_type = HCI_DEVCOREDUMP_PKT_COMPLETE; 509 + 510 + skb_queue_tail(&hdev->dump.dump_q, skb); 511 + queue_work(hdev->workqueue, &hdev->dump.dump_rx); 512 + 513 + return 0; 514 + } 515 + EXPORT_SYMBOL(hci_devcd_complete); 516 + 517 + int hci_devcd_abort(struct hci_dev *hdev) 518 + { 519 + struct sk_buff *skb; 520 + 521 + if (!hci_devcd_enabled(hdev)) 522 + return -EOPNOTSUPP; 523 + 524 + skb = alloc_skb(0, GFP_ATOMIC); 525 + if (!skb) 526 + return -ENOMEM; 527 + 528 + hci_dmp_cb(skb)->pkt_type = HCI_DEVCOREDUMP_PKT_ABORT; 529 + 530 + skb_queue_tail(&hdev->dump.dump_q, skb); 531 + queue_work(hdev->workqueue, &hdev->dump.dump_rx); 532 + 533 + return 0; 534 + } 535 + EXPORT_SYMBOL(hci_devcd_abort);
+1
net/bluetooth/hci_core.c
··· 2544 2544 INIT_DELAYED_WORK(&hdev->cmd_timer, hci_cmd_timeout); 2545 2545 INIT_DELAYED_WORK(&hdev->ncmd_timer, hci_ncmd_timeout); 2546 2546 2547 + hci_devcd_setup(hdev); 2547 2548 hci_request_setup(hdev); 2548 2549 2549 2550 hci_init_sysfs(hdev);
+2
net/bluetooth/hci_sync.c
··· 4727 4727 goto done; 4728 4728 } 4729 4729 4730 + hci_devcd_reset(hdev); 4731 + 4730 4732 set_bit(HCI_RUNNING, &hdev->flags); 4731 4733 hci_sock_dev_event(hdev, HCI_DEV_OPEN); 4732 4734