forked from mirrors/linux
		
	Bluetooth: Add vhci devcoredump support
Add devcoredump support for vhci that creates forcce_devcoredump debugfs entry. This is used for mgmt-tester tests. Signed-off-by: Manish Mandlik <mmandlik@google.com> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
		
							parent
							
								
									9695ef876f
								
							
						
					
					
						commit
						ab4e4380d4
					
				
					 2 changed files with 98 additions and 0 deletions
				
			
		|  | @ -363,6 +363,7 @@ config BT_HCIBLUECARD | ||||||
| 
 | 
 | ||||||
| config BT_HCIVHCI | config BT_HCIVHCI | ||||||
| 	tristate "HCI VHCI (Virtual HCI device) driver" | 	tristate "HCI VHCI (Virtual HCI device) driver" | ||||||
|  | 	select WANT_DEV_COREDUMP | ||||||
| 	help | 	help | ||||||
| 	  Bluetooth Virtual HCI device driver. | 	  Bluetooth Virtual HCI device driver. | ||||||
| 	  This driver is required if you want to use HCI Emulation software. | 	  This driver is required if you want to use HCI Emulation software. | ||||||
|  |  | ||||||
|  | @ -278,6 +278,100 @@ static int vhci_setup(struct hci_dev *hdev) | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void vhci_coredump(struct hci_dev *hdev) | ||||||
|  | { | ||||||
|  | 	/* No need to do anything */ | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void vhci_coredump_hdr(struct hci_dev *hdev, struct sk_buff *skb) | ||||||
|  | { | ||||||
|  | 	char buf[80]; | ||||||
|  | 
 | ||||||
|  | 	snprintf(buf, sizeof(buf), "Controller Name: vhci_ctrl\n"); | ||||||
|  | 	skb_put_data(skb, buf, strlen(buf)); | ||||||
|  | 
 | ||||||
|  | 	snprintf(buf, sizeof(buf), "Firmware Version: vhci_fw\n"); | ||||||
|  | 	skb_put_data(skb, buf, strlen(buf)); | ||||||
|  | 
 | ||||||
|  | 	snprintf(buf, sizeof(buf), "Driver: vhci_drv\n"); | ||||||
|  | 	skb_put_data(skb, buf, strlen(buf)); | ||||||
|  | 
 | ||||||
|  | 	snprintf(buf, sizeof(buf), "Vendor: vhci\n"); | ||||||
|  | 	skb_put_data(skb, buf, strlen(buf)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #define MAX_COREDUMP_LINE_LEN	40 | ||||||
|  | 
 | ||||||
|  | struct devcoredump_test_data { | ||||||
|  | 	enum devcoredump_state state; | ||||||
|  | 	unsigned int timeout; | ||||||
|  | 	char data[MAX_COREDUMP_LINE_LEN]; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static inline void force_devcd_timeout(struct hci_dev *hdev, | ||||||
|  | 				       unsigned int timeout) | ||||||
|  | { | ||||||
|  | #ifdef CONFIG_DEV_COREDUMP | ||||||
|  | 	hdev->dump.timeout = msecs_to_jiffies(timeout * 1000); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static ssize_t force_devcd_write(struct file *file, const char __user *user_buf, | ||||||
|  | 				 size_t count, loff_t *ppos) | ||||||
|  | { | ||||||
|  | 	struct vhci_data *data = file->private_data; | ||||||
|  | 	struct hci_dev *hdev = data->hdev; | ||||||
|  | 	struct sk_buff *skb = NULL; | ||||||
|  | 	struct devcoredump_test_data dump_data; | ||||||
|  | 	int ret; | ||||||
|  | 
 | ||||||
|  | 	ret = simple_write_to_buffer(&dump_data, sizeof(dump_data), ppos, | ||||||
|  | 				     user_buf, count); | ||||||
|  | 	if (ret < count) | ||||||
|  | 		return ret; | ||||||
|  | 
 | ||||||
|  | 	skb = alloc_skb(sizeof(dump_data.data), GFP_ATOMIC); | ||||||
|  | 	if (!skb) | ||||||
|  | 		return -ENOMEM; | ||||||
|  | 	skb_put_data(skb, &dump_data.data, sizeof(dump_data.data)); | ||||||
|  | 
 | ||||||
|  | 	hci_devcd_register(hdev, vhci_coredump, vhci_coredump_hdr, NULL); | ||||||
|  | 
 | ||||||
|  | 	/* Force the devcoredump timeout */ | ||||||
|  | 	if (dump_data.timeout) | ||||||
|  | 		force_devcd_timeout(hdev, dump_data.timeout); | ||||||
|  | 
 | ||||||
|  | 	ret = hci_devcd_init(hdev, skb->len); | ||||||
|  | 	if (ret) { | ||||||
|  | 		BT_ERR("Failed to generate devcoredump"); | ||||||
|  | 		kfree_skb(skb); | ||||||
|  | 		return ret; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	hci_devcd_append(hdev, skb); | ||||||
|  | 
 | ||||||
|  | 	switch (dump_data.state) { | ||||||
|  | 	case HCI_DEVCOREDUMP_DONE: | ||||||
|  | 		hci_devcd_complete(hdev); | ||||||
|  | 		break; | ||||||
|  | 	case HCI_DEVCOREDUMP_ABORT: | ||||||
|  | 		hci_devcd_abort(hdev); | ||||||
|  | 		break; | ||||||
|  | 	case HCI_DEVCOREDUMP_TIMEOUT: | ||||||
|  | 		/* Do nothing */ | ||||||
|  | 		break; | ||||||
|  | 	default: | ||||||
|  | 		return -EINVAL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return count; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static const struct file_operations force_devcoredump_fops = { | ||||||
|  | 	.open		= simple_open, | ||||||
|  | 	.write		= force_devcd_write, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| static int __vhci_create_device(struct vhci_data *data, __u8 opcode) | static int __vhci_create_device(struct vhci_data *data, __u8 opcode) | ||||||
| { | { | ||||||
| 	struct hci_dev *hdev; | 	struct hci_dev *hdev; | ||||||
|  | @ -355,6 +449,9 @@ static int __vhci_create_device(struct vhci_data *data, __u8 opcode) | ||||||
| 		debugfs_create_file("aosp_capable", 0644, hdev->debugfs, data, | 		debugfs_create_file("aosp_capable", 0644, hdev->debugfs, data, | ||||||
| 				    &aosp_capable_fops); | 				    &aosp_capable_fops); | ||||||
| 
 | 
 | ||||||
|  | 	debugfs_create_file("force_devcoredump", 0644, hdev->debugfs, data, | ||||||
|  | 			    &force_devcoredump_fops); | ||||||
|  | 
 | ||||||
| 	hci_skb_pkt_type(skb) = HCI_VENDOR_PKT; | 	hci_skb_pkt_type(skb) = HCI_VENDOR_PKT; | ||||||
| 
 | 
 | ||||||
| 	skb_put_u8(skb, 0xff); | 	skb_put_u8(skb, 0xff); | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Manish Mandlik
						Manish Mandlik