summaryrefslogtreecommitdiff
path: root/include/net/bluetooth/coredump.h
blob: 1f071ab554163d71a92d4279157210d831a94b6a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (C) 2022 Google Corporation
 */

#ifndef __COREDUMP_H
#define __COREDUMP_H

#define DEVCOREDUMP_TIMEOUT	msecs_to_jiffies(10000)	/* 10 sec */

/*
 * Max header size, shared by both the devcoredump core and
 * the dmp_hdr() registered by driver via hci_devcd_register()
 */
#define HCI_DEVCD_HDR_SIZE_MAX	512
#define HCI_DEVCD_HDR_END_MARKER	"--- Start dump ---\n"

typedef void (*coredump_t)(struct hci_dev *hdev);
typedef void (*dmp_hdr_t)(struct hci_dev *hdev, struct sk_buff *skb);
typedef void (*notify_change_t)(struct hci_dev *hdev, int state);

/* struct hci_devcoredump - Devcoredump state
 *
 * @supported: Indicates if FW dump collection is supported by driver
 * @state: Current state of dump collection
 * @timeout: Indicates a timeout for collecting the devcoredump
 *
 * @alloc_size: Total size of the dump
 * @head: Start of the dump
 * @tail: Pointer to current end of dump
 * @end: head + alloc_size for easy comparisons
 *
 * @dump_q: Dump queue for state machine to process
 * @dump_rx: Devcoredump state machine work
 * @dump_timeout: Devcoredump timeout work
 *
 * @coredump: Called from the driver's .coredump() function.
 * @dmp_hdr: Create a dump header to identify controller/fw/driver info
 * @notify_change: Notify driver when devcoredump state has changed
 */
struct hci_devcoredump {
	bool		supported;

	enum devcoredump_state {
		HCI_DEVCOREDUMP_IDLE,
		HCI_DEVCOREDUMP_ACTIVE,
		HCI_DEVCOREDUMP_DONE,
		HCI_DEVCOREDUMP_ABORT,
		HCI_DEVCOREDUMP_TIMEOUT,
	} state;

	unsigned long	timeout;

	size_t		alloc_size;
	char		*head;
	char		*tail;
	char		*end;

	struct sk_buff_head	dump_q;
	struct work_struct	dump_rx;
	struct delayed_work	dump_timeout;

	coredump_t		coredump;
	dmp_hdr_t		dmp_hdr;
	notify_change_t		notify_change;
};

#ifdef CONFIG_DEV_COREDUMP

const char *hci_devcd_state_name(enum devcoredump_state state);

void hci_devcd_reset(struct hci_dev *hdev);
void hci_devcd_rx(struct work_struct *work);
void hci_devcd_timeout(struct work_struct *work);

int hci_devcd_register(struct hci_dev *hdev, coredump_t coredump,
		       dmp_hdr_t dmp_hdr, notify_change_t notify_change);
int hci_devcd_init(struct hci_dev *hdev, u32 dump_size);
int hci_devcd_append(struct hci_dev *hdev, struct sk_buff *skb);
int hci_devcd_append_pattern(struct hci_dev *hdev, u8 pattern, u32 len);
int hci_devcd_complete(struct hci_dev *hdev);
int hci_devcd_abort(struct hci_dev *hdev);

#else

static inline const char *hci_devcd_state_name(enum devcoredump_state state)
{
	return "";
}

static inline void hci_devcd_reset(struct hci_dev *hdev) {}
static inline void hci_devcd_rx(struct work_struct *work) {}
static inline void hci_devcd_timeout(struct work_struct *work) {}

static inline int hci_devcd_register(struct hci_dev *hdev, coredump_t coredump,
				     dmp_hdr_t dmp_hdr,
				     notify_change_t notify_change)
{
	return -EOPNOTSUPP;
}

static inline int hci_devcd_init(struct hci_dev *hdev, u32 dump_size)
{
	return -EOPNOTSUPP;
}

static inline int hci_devcd_append(struct hci_dev *hdev, struct sk_buff *skb)
{
	return -EOPNOTSUPP;
}

static inline int hci_devcd_append_pattern(struct hci_dev *hdev,
					   u8 pattern, u32 len)
{
	return -EOPNOTSUPP;
}

static inline int hci_devcd_complete(struct hci_dev *hdev)
{
	return -EOPNOTSUPP;
}

static inline int hci_devcd_abort(struct hci_dev *hdev)
{
	return -EOPNOTSUPP;
}

#endif /* CONFIG_DEV_COREDUMP */

#endif /* __COREDUMP_H */