9695ef876f
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>
117 lines
3.0 KiB
C
117 lines
3.0 KiB
C
/* 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 */
|
|
|
|
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
|
|
|
|
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 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 */
|