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 /*
12 * Max header size, shared by both the devcoredump core and
13 * the dmp_hdr() registered by driver via hci_devcd_register()
14 */
15 #define HCI_DEVCD_HDR_SIZE_MAX 512
16 #define HCI_DEVCD_HDR_END_MARKER "--- Start dump ---\n"
17
18 typedef void (*coredump_t)(struct hci_dev *hdev);
19 typedef void (*dmp_hdr_t)(struct hci_dev *hdev, struct sk_buff *skb);
20 typedef void (*notify_change_t)(struct hci_dev *hdev, int state);
21
22 /* struct hci_devcoredump - Devcoredump state
23 *
24 * @supported: Indicates if FW dump collection is supported by driver
25 * @state: Current state of dump collection
26 * @timeout: Indicates a timeout for collecting the devcoredump
27 *
28 * @alloc_size: Total size of the dump
29 * @head: Start of the dump
30 * @tail: Pointer to current end of dump
31 * @end: head + alloc_size for easy comparisons
32 *
33 * @dump_q: Dump queue for state machine to process
34 * @dump_rx: Devcoredump state machine work
35 * @dump_timeout: Devcoredump timeout work
36 *
37 * @coredump: Called from the driver's .coredump() function.
38 * @dmp_hdr: Create a dump header to identify controller/fw/driver info
39 * @notify_change: Notify driver when devcoredump state has changed
40 */
41 struct hci_devcoredump {
42 bool supported;
43
44 enum devcoredump_state {
45 HCI_DEVCOREDUMP_IDLE,
46 HCI_DEVCOREDUMP_ACTIVE,
47 HCI_DEVCOREDUMP_DONE,
48 HCI_DEVCOREDUMP_ABORT,
49 HCI_DEVCOREDUMP_TIMEOUT,
50 } state;
51
52 unsigned long timeout;
53
54 size_t alloc_size;
55 char *head;
56 char *tail;
57 char *end;
58
59 struct sk_buff_head dump_q;
60 struct work_struct dump_rx;
61 struct delayed_work dump_timeout;
62
63 coredump_t coredump;
64 dmp_hdr_t dmp_hdr;
65 notify_change_t notify_change;
66 };
67
68 #ifdef CONFIG_DEV_COREDUMP
69
70 const char *hci_devcd_state_name(enum devcoredump_state state);
71
72 void hci_devcd_reset(struct hci_dev *hdev);
73 void hci_devcd_shutdown(struct hci_dev *hdev);
74 void hci_devcd_rx(struct work_struct *work);
75 void hci_devcd_timeout(struct work_struct *work);
76
77 int hci_devcd_register(struct hci_dev *hdev, coredump_t coredump,
78 dmp_hdr_t dmp_hdr, notify_change_t notify_change);
79 int hci_devcd_init(struct hci_dev *hdev, u32 dump_size);
80 int hci_devcd_append(struct hci_dev *hdev, struct sk_buff *skb);
81 int hci_devcd_append_pattern(struct hci_dev *hdev, u8 pattern, u32 len);
82 int hci_devcd_complete(struct hci_dev *hdev);
83 int hci_devcd_abort(struct hci_dev *hdev);
84
85 #else
86
hci_devcd_state_name(enum devcoredump_state state)87 static inline const char *hci_devcd_state_name(enum devcoredump_state state)
88 {
89 return "";
90 }
91
hci_devcd_reset(struct hci_dev * hdev)92 static inline void hci_devcd_reset(struct hci_dev *hdev) {}
hci_devcd_shutdown(struct hci_dev * hdev)93 static inline void hci_devcd_shutdown(struct hci_dev *hdev) {}
hci_devcd_rx(struct work_struct * work)94 static inline void hci_devcd_rx(struct work_struct *work) {}
hci_devcd_timeout(struct work_struct * work)95 static inline void hci_devcd_timeout(struct work_struct *work) {}
96
hci_devcd_register(struct hci_dev * hdev,coredump_t coredump,dmp_hdr_t dmp_hdr,notify_change_t notify_change)97 static inline int hci_devcd_register(struct hci_dev *hdev, coredump_t coredump,
98 dmp_hdr_t dmp_hdr,
99 notify_change_t notify_change)
100 {
101 return -EOPNOTSUPP;
102 }
103
hci_devcd_init(struct hci_dev * hdev,u32 dump_size)104 static inline int hci_devcd_init(struct hci_dev *hdev, u32 dump_size)
105 {
106 return -EOPNOTSUPP;
107 }
108
hci_devcd_append(struct hci_dev * hdev,struct sk_buff * skb)109 static inline int hci_devcd_append(struct hci_dev *hdev, struct sk_buff *skb)
110 {
111 return -EOPNOTSUPP;
112 }
113
hci_devcd_append_pattern(struct hci_dev * hdev,u8 pattern,u32 len)114 static inline int hci_devcd_append_pattern(struct hci_dev *hdev,
115 u8 pattern, u32 len)
116 {
117 return -EOPNOTSUPP;
118 }
119
hci_devcd_complete(struct hci_dev * hdev)120 static inline int hci_devcd_complete(struct hci_dev *hdev)
121 {
122 return -EOPNOTSUPP;
123 }
124
hci_devcd_abort(struct hci_dev * hdev)125 static inline int hci_devcd_abort(struct hci_dev *hdev)
126 {
127 return -EOPNOTSUPP;
128 }
129
130 #endif /* CONFIG_DEV_COREDUMP */
131
132 #endif /* __COREDUMP_H */
133