brintos

brintos / linux-shallow public Read only

0
0
Text · 18.8 KiB · f239530 Raw
724 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3	Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>4	<http://rt2x00.serialmonkey.com>5 6 */7 8/*9	Module: rt2x00lib10	Abstract: rt2x00 debugfs specific routines.11 */12 13#include <linux/debugfs.h>14#include <linux/kernel.h>15#include <linux/module.h>16#include <linux/poll.h>17#include <linux/sched.h>18#include <linux/slab.h>19#include <linux/uaccess.h>20 21#include "rt2x00.h"22#include "rt2x00lib.h"23#include "rt2x00dump.h"24 25#define MAX_LINE_LENGTH 6426 27struct rt2x00debug_crypto {28	unsigned long success;29	unsigned long icv_error;30	unsigned long mic_error;31	unsigned long key_error;32};33 34struct rt2x00debug_intf {35	/*36	 * Pointer to driver structure where37	 * this debugfs entry belongs to.38	 */39	struct rt2x00_dev *rt2x00dev;40 41	/*42	 * Reference to the rt2x00debug structure43	 * which can be used to communicate with44	 * the registers.45	 */46	const struct rt2x00debug *debug;47 48	/*49	 * Debugfs entries for:50	 * - driver folder51	 *   - driver file52	 *   - chipset file53	 *   - device state flags file54	 *   - device capability flags file55	 *   - hardware restart file56	 *   - register folder57	 *     - csr offset/value files58	 *     - eeprom offset/value files59	 *     - bbp offset/value files60	 *     - rf offset/value files61	 *     - rfcsr offset/value files62	 *   - queue folder63	 *     - frame dump file64	 *     - queue stats file65	 *     - crypto stats file66	 */67	struct dentry *driver_folder;68 69	/*70	 * The frame dump file only allows a single reader,71	 * so we need to store the current state here.72	 */73	unsigned long frame_dump_flags;74#define FRAME_DUMP_FILE_OPEN	175 76	/*77	 * We queue each frame before dumping it to the user,78	 * per read command we will pass a single skb structure79	 * so we should be prepared to queue multiple sk buffers80	 * before sending it to userspace.81	 */82	struct sk_buff_head frame_dump_skbqueue;83	wait_queue_head_t frame_dump_waitqueue;84 85	/*86	 * HW crypto statistics.87	 * All statistics are stored separately per cipher type.88	 */89	struct rt2x00debug_crypto crypto_stats[CIPHER_MAX];90 91	/*92	 * Driver and chipset files will use a data buffer93	 * that has been created in advance. This will simplify94	 * the code since we can use the debugfs functions.95	 */96	struct debugfs_blob_wrapper driver_blob;97	struct debugfs_blob_wrapper chipset_blob;98 99	/*100	 * Requested offset for each register type.101	 */102	unsigned int offset_csr;103	unsigned int offset_eeprom;104	unsigned int offset_bbp;105	unsigned int offset_rf;106	unsigned int offset_rfcsr;107};108 109void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev,110			       struct rxdone_entry_desc *rxdesc)111{112	struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf;113	enum cipher cipher = rxdesc->cipher;114	enum rx_crypto status = rxdesc->cipher_status;115 116	if (cipher == CIPHER_TKIP_NO_MIC)117		cipher = CIPHER_TKIP;118	if (cipher == CIPHER_NONE || cipher >= CIPHER_MAX)119		return;120 121	/* Remove CIPHER_NONE index */122	cipher--;123 124	intf->crypto_stats[cipher].success += (status == RX_CRYPTO_SUCCESS);125	intf->crypto_stats[cipher].icv_error += (status == RX_CRYPTO_FAIL_ICV);126	intf->crypto_stats[cipher].mic_error += (status == RX_CRYPTO_FAIL_MIC);127	intf->crypto_stats[cipher].key_error += (status == RX_CRYPTO_FAIL_KEY);128}129 130void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,131			    enum rt2x00_dump_type type, struct queue_entry *entry)132{133	struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf;134	struct sk_buff *skb = entry->skb;135	struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);136	struct sk_buff *skbcopy;137	struct rt2x00dump_hdr *dump_hdr;138	struct timespec64 timestamp;139	u32 data_len;140 141	if (likely(!test_bit(FRAME_DUMP_FILE_OPEN, &intf->frame_dump_flags)))142		return;143 144	ktime_get_ts64(&timestamp);145 146	if (skb_queue_len(&intf->frame_dump_skbqueue) > 20) {147		rt2x00_dbg(rt2x00dev, "txrx dump queue length exceeded\n");148		return;149	}150 151	data_len = skb->len;152	if (skbdesc->flags & SKBDESC_DESC_IN_SKB)153		data_len -= skbdesc->desc_len;154 155	skbcopy = alloc_skb(sizeof(*dump_hdr) + skbdesc->desc_len + data_len,156			    GFP_ATOMIC);157	if (!skbcopy) {158		rt2x00_dbg(rt2x00dev, "Failed to copy skb for dump\n");159		return;160	}161 162	dump_hdr = skb_put(skbcopy, sizeof(*dump_hdr));163	dump_hdr->version = cpu_to_le32(DUMP_HEADER_VERSION);164	dump_hdr->header_length = cpu_to_le32(sizeof(*dump_hdr));165	dump_hdr->desc_length = cpu_to_le32(skbdesc->desc_len);166	dump_hdr->data_length = cpu_to_le32(data_len);167	dump_hdr->chip_rt = cpu_to_le16(rt2x00dev->chip.rt);168	dump_hdr->chip_rf = cpu_to_le16(rt2x00dev->chip.rf);169	dump_hdr->chip_rev = cpu_to_le16(rt2x00dev->chip.rev);170	dump_hdr->type = cpu_to_le16(type);171	dump_hdr->queue_index = entry->queue->qid;172	dump_hdr->entry_index = entry->entry_idx;173	dump_hdr->timestamp_sec = cpu_to_le32(timestamp.tv_sec);174	dump_hdr->timestamp_usec = cpu_to_le32(timestamp.tv_nsec /175					       NSEC_PER_USEC);176 177	if (!(skbdesc->flags & SKBDESC_DESC_IN_SKB))178		skb_put_data(skbcopy, skbdesc->desc, skbdesc->desc_len);179	skb_put_data(skbcopy, skb->data, skb->len);180 181	skb_queue_tail(&intf->frame_dump_skbqueue, skbcopy);182	wake_up_interruptible(&intf->frame_dump_waitqueue);183 184	/*185	 * Verify that the file has not been closed while we were working.186	 */187	if (!test_bit(FRAME_DUMP_FILE_OPEN, &intf->frame_dump_flags))188		skb_queue_purge(&intf->frame_dump_skbqueue);189}190EXPORT_SYMBOL_GPL(rt2x00debug_dump_frame);191 192static int rt2x00debug_file_open(struct inode *inode, struct file *file)193{194	struct rt2x00debug_intf *intf = inode->i_private;195 196	file->private_data = inode->i_private;197 198	if (!try_module_get(intf->debug->owner))199		return -EBUSY;200 201	return 0;202}203 204static int rt2x00debug_file_release(struct inode *inode, struct file *file)205{206	struct rt2x00debug_intf *intf = file->private_data;207 208	module_put(intf->debug->owner);209 210	return 0;211}212 213static int rt2x00debug_open_queue_dump(struct inode *inode, struct file *file)214{215	struct rt2x00debug_intf *intf = inode->i_private;216	int retval;217 218	retval = rt2x00debug_file_open(inode, file);219	if (retval)220		return retval;221 222	if (test_and_set_bit(FRAME_DUMP_FILE_OPEN, &intf->frame_dump_flags)) {223		rt2x00debug_file_release(inode, file);224		return -EBUSY;225	}226 227	return 0;228}229 230static int rt2x00debug_release_queue_dump(struct inode *inode, struct file *file)231{232	struct rt2x00debug_intf *intf = inode->i_private;233 234	skb_queue_purge(&intf->frame_dump_skbqueue);235 236	clear_bit(FRAME_DUMP_FILE_OPEN, &intf->frame_dump_flags);237 238	return rt2x00debug_file_release(inode, file);239}240 241static ssize_t rt2x00debug_read_queue_dump(struct file *file,242					   char __user *buf,243					   size_t length,244					   loff_t *offset)245{246	struct rt2x00debug_intf *intf = file->private_data;247	struct sk_buff *skb;248	size_t status;249	int retval;250 251	if (file->f_flags & O_NONBLOCK)252		return -EAGAIN;253 254	retval =255	    wait_event_interruptible(intf->frame_dump_waitqueue,256				     (skb =257				     skb_dequeue(&intf->frame_dump_skbqueue)));258	if (retval)259		return retval;260 261	status = min_t(size_t, skb->len, length);262	if (copy_to_user(buf, skb->data, status)) {263		status = -EFAULT;264		goto exit;265	}266 267	*offset += status;268 269exit:270	kfree_skb(skb);271 272	return status;273}274 275static __poll_t rt2x00debug_poll_queue_dump(struct file *file,276						poll_table *wait)277{278	struct rt2x00debug_intf *intf = file->private_data;279 280	poll_wait(file, &intf->frame_dump_waitqueue, wait);281 282	if (!skb_queue_empty(&intf->frame_dump_skbqueue))283		return EPOLLOUT | EPOLLWRNORM;284 285	return 0;286}287 288static const struct file_operations rt2x00debug_fop_queue_dump = {289	.owner		= THIS_MODULE,290	.read		= rt2x00debug_read_queue_dump,291	.poll		= rt2x00debug_poll_queue_dump,292	.open		= rt2x00debug_open_queue_dump,293	.release	= rt2x00debug_release_queue_dump,294	.llseek		= default_llseek,295};296 297static ssize_t rt2x00debug_read_queue_stats(struct file *file,298					    char __user *buf,299					    size_t length,300					    loff_t *offset)301{302	struct rt2x00debug_intf *intf = file->private_data;303	struct data_queue *queue;304	unsigned long irqflags;305	unsigned int lines = 1 + intf->rt2x00dev->data_queues;306	size_t size;307	char *data;308	char *temp;309 310	if (*offset)311		return 0;312 313	data = kcalloc(lines, MAX_LINE_LENGTH, GFP_KERNEL);314	if (!data)315		return -ENOMEM;316 317	temp = data +318	    sprintf(data, "qid\tflags\t\tcount\tlimit\tlength\tindex\tdma done\tdone\n");319 320	queue_for_each(intf->rt2x00dev, queue) {321		spin_lock_irqsave(&queue->index_lock, irqflags);322 323		temp += sprintf(temp, "%d\t0x%.8x\t%d\t%d\t%d\t%d\t%d\t\t%d\n",324				queue->qid, (unsigned int)queue->flags,325				queue->count, queue->limit, queue->length,326				queue->index[Q_INDEX],327				queue->index[Q_INDEX_DMA_DONE],328				queue->index[Q_INDEX_DONE]);329 330		spin_unlock_irqrestore(&queue->index_lock, irqflags);331	}332 333	size = strlen(data);334	size = min(size, length);335 336	if (copy_to_user(buf, data, size)) {337		kfree(data);338		return -EFAULT;339	}340 341	kfree(data);342 343	*offset += size;344	return size;345}346 347static const struct file_operations rt2x00debug_fop_queue_stats = {348	.owner		= THIS_MODULE,349	.read		= rt2x00debug_read_queue_stats,350	.open		= rt2x00debug_file_open,351	.release	= rt2x00debug_file_release,352	.llseek		= default_llseek,353};354 355#ifdef CONFIG_RT2X00_LIB_CRYPTO356static ssize_t rt2x00debug_read_crypto_stats(struct file *file,357					     char __user *buf,358					     size_t length,359					     loff_t *offset)360{361	struct rt2x00debug_intf *intf = file->private_data;362	static const char * const name[] = { "WEP64", "WEP128", "TKIP", "AES" };363	char *data;364	char *temp;365	size_t size;366	unsigned int i;367 368	if (*offset)369		return 0;370 371	data = kcalloc(1 + CIPHER_MAX, MAX_LINE_LENGTH, GFP_KERNEL);372	if (!data)373		return -ENOMEM;374 375	temp = data;376	temp += sprintf(data, "cipher\tsuccess\ticv err\tmic err\tkey err\n");377 378	for (i = 0; i < CIPHER_MAX; i++) {379		temp += sprintf(temp, "%s\t%lu\t%lu\t%lu\t%lu\n", name[i],380				intf->crypto_stats[i].success,381				intf->crypto_stats[i].icv_error,382				intf->crypto_stats[i].mic_error,383				intf->crypto_stats[i].key_error);384	}385 386	size = strlen(data);387	size = min(size, length);388 389	if (copy_to_user(buf, data, size)) {390		kfree(data);391		return -EFAULT;392	}393 394	kfree(data);395 396	*offset += size;397	return size;398}399 400static const struct file_operations rt2x00debug_fop_crypto_stats = {401	.owner		= THIS_MODULE,402	.read		= rt2x00debug_read_crypto_stats,403	.open		= rt2x00debug_file_open,404	.release	= rt2x00debug_file_release,405	.llseek		= default_llseek,406};407#endif408 409#define RT2X00DEBUGFS_OPS_READ(__name, __format, __type)	\410static ssize_t rt2x00debug_read_##__name(struct file *file,	\411					 char __user *buf,	\412					 size_t length,		\413					 loff_t *offset)	\414{								\415	struct rt2x00debug_intf *intf = file->private_data;	\416	const struct rt2x00debug *debug = intf->debug;		\417	char line[16];						\418	size_t size;						\419	unsigned int index = intf->offset_##__name;		\420	__type value;						\421								\422	if (*offset)						\423		return 0;					\424								\425	if (index >= debug->__name.word_count)			\426		return -EINVAL;					\427								\428	index += (debug->__name.word_base /			\429		  debug->__name.word_size);			\430								\431	if (debug->__name.flags & RT2X00DEBUGFS_OFFSET)		\432		index *= debug->__name.word_size;		\433								\434	value = debug->__name.read(intf->rt2x00dev, index);	\435								\436	size = sprintf(line, __format, value);			\437								\438	return simple_read_from_buffer(buf, length, offset, line, size); \439}440 441#define RT2X00DEBUGFS_OPS_WRITE(__name, __type)			\442static ssize_t rt2x00debug_write_##__name(struct file *file,	\443					  const char __user *buf,\444					  size_t length,	\445					  loff_t *offset)	\446{								\447	struct rt2x00debug_intf *intf = file->private_data;	\448	const struct rt2x00debug *debug = intf->debug;		\449	char line[17];						\450	size_t size;						\451	unsigned int index = intf->offset_##__name;		\452	__type value;						\453								\454	if (*offset)						\455		return 0;					\456								\457	if (index >= debug->__name.word_count)			\458		return -EINVAL;					\459								\460	if (length > sizeof(line))				\461		return -EINVAL;					\462								\463	if (copy_from_user(line, buf, length))			\464		return -EFAULT;					\465	line[16] = 0;						\466						\467	size = strlen(line);					\468	value = simple_strtoul(line, NULL, 0);			\469								\470	index += (debug->__name.word_base /			\471		  debug->__name.word_size);			\472								\473	if (debug->__name.flags & RT2X00DEBUGFS_OFFSET)		\474		index *= debug->__name.word_size;		\475								\476	debug->__name.write(intf->rt2x00dev, index, value);	\477								\478	*offset += size;					\479	return size;						\480}481 482#define RT2X00DEBUGFS_OPS(__name, __format, __type)		\483RT2X00DEBUGFS_OPS_READ(__name, __format, __type);		\484RT2X00DEBUGFS_OPS_WRITE(__name, __type);			\485								\486static const struct file_operations rt2x00debug_fop_##__name = {\487	.owner		= THIS_MODULE,				\488	.read		= rt2x00debug_read_##__name,		\489	.write		= rt2x00debug_write_##__name,		\490	.open		= rt2x00debug_file_open,		\491	.release	= rt2x00debug_file_release,		\492	.llseek		= generic_file_llseek,			\493};494 495RT2X00DEBUGFS_OPS(csr, "0x%.8x\n", u32);496RT2X00DEBUGFS_OPS(eeprom, "0x%.4x\n", u16);497RT2X00DEBUGFS_OPS(bbp, "0x%.2x\n", u8);498RT2X00DEBUGFS_OPS(rf, "0x%.8x\n", u32);499RT2X00DEBUGFS_OPS(rfcsr, "0x%.2x\n", u8);500 501static ssize_t rt2x00debug_read_dev_flags(struct file *file,502					  char __user *buf,503					  size_t length,504					  loff_t *offset)505{506	struct rt2x00debug_intf *intf =	file->private_data;507	char line[16];508	size_t size;509 510	if (*offset)511		return 0;512 513	size = sprintf(line, "0x%.8x\n", (unsigned int)intf->rt2x00dev->flags);514 515	return simple_read_from_buffer(buf, length, offset, line, size);516}517 518static const struct file_operations rt2x00debug_fop_dev_flags = {519	.owner		= THIS_MODULE,520	.read		= rt2x00debug_read_dev_flags,521	.open		= rt2x00debug_file_open,522	.release	= rt2x00debug_file_release,523	.llseek		= default_llseek,524};525 526static ssize_t rt2x00debug_read_cap_flags(struct file *file,527					  char __user *buf,528					  size_t length,529					  loff_t *offset)530{531	struct rt2x00debug_intf *intf =	file->private_data;532	char line[16];533	size_t size;534 535	if (*offset)536		return 0;537 538	size = sprintf(line, "0x%.8x\n", (unsigned int)intf->rt2x00dev->cap_flags);539 540	return simple_read_from_buffer(buf, length, offset, line, size);541}542 543static const struct file_operations rt2x00debug_fop_cap_flags = {544	.owner		= THIS_MODULE,545	.read		= rt2x00debug_read_cap_flags,546	.open		= rt2x00debug_file_open,547	.release	= rt2x00debug_file_release,548	.llseek		= default_llseek,549};550 551static ssize_t rt2x00debug_write_restart_hw(struct file *file,552					    const char __user *buf,553					    size_t length,554					    loff_t *offset)555{556	struct rt2x00debug_intf *intf =	file->private_data;557	struct rt2x00_dev *rt2x00dev = intf->rt2x00dev;558	static unsigned long last_reset = INITIAL_JIFFIES;559 560	if (!rt2x00_has_cap_restart_hw(rt2x00dev))561		return -EOPNOTSUPP;562 563	if (time_before(jiffies, last_reset + msecs_to_jiffies(2000)))564		return -EBUSY;565 566	last_reset = jiffies;567 568	ieee80211_restart_hw(rt2x00dev->hw);569	return length;570}571 572static const struct file_operations rt2x00debug_restart_hw = {573	.owner = THIS_MODULE,574	.write = rt2x00debug_write_restart_hw,575	.open = simple_open,576	.llseek = generic_file_llseek,577};578 579static void rt2x00debug_create_file_driver(const char *name,580					   struct rt2x00debug_intf *intf,581					   struct debugfs_blob_wrapper *blob)582{583	char *data;584 585	data = kzalloc(3 * MAX_LINE_LENGTH, GFP_KERNEL);586	if (!data)587		return;588 589	blob->data = data;590	data += sprintf(data, "driver:\t%s\n", intf->rt2x00dev->ops->name);591	data += sprintf(data, "version:\t%s\n", DRV_VERSION);592	blob->size = strlen(blob->data);593 594	debugfs_create_blob(name, 0400, intf->driver_folder, blob);595}596 597static void rt2x00debug_create_file_chipset(const char *name,598					    struct rt2x00debug_intf *intf,599					    struct debugfs_blob_wrapper *blob)600{601	const struct rt2x00debug *debug = intf->debug;602	char *data;603 604	data = kzalloc(9 * MAX_LINE_LENGTH, GFP_KERNEL);605	if (!data)606		return;607 608	blob->data = data;609	data += sprintf(data, "rt chip:\t%04x\n", intf->rt2x00dev->chip.rt);610	data += sprintf(data, "rf chip:\t%04x\n", intf->rt2x00dev->chip.rf);611	data += sprintf(data, "revision:\t%04x\n", intf->rt2x00dev->chip.rev);612	data += sprintf(data, "\n");613	data += sprintf(data, "register\tbase\twords\twordsize\n");614#define RT2X00DEBUGFS_SPRINTF_REGISTER(__name)			\615{								\616	if (debug->__name.read)					\617		data += sprintf(data, __stringify(__name)	\618				"\t%d\t%d\t%d\n",		\619				debug->__name.word_base,	\620				debug->__name.word_count,	\621				debug->__name.word_size);	\622}623	RT2X00DEBUGFS_SPRINTF_REGISTER(csr);624	RT2X00DEBUGFS_SPRINTF_REGISTER(eeprom);625	RT2X00DEBUGFS_SPRINTF_REGISTER(bbp);626	RT2X00DEBUGFS_SPRINTF_REGISTER(rf);627	RT2X00DEBUGFS_SPRINTF_REGISTER(rfcsr);628#undef RT2X00DEBUGFS_SPRINTF_REGISTER629 630	blob->size = strlen(blob->data);631 632	debugfs_create_blob(name, 0400, intf->driver_folder, blob);633}634 635void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)636{637	const struct rt2x00debug *debug = rt2x00dev->ops->debugfs;638	struct rt2x00debug_intf *intf;639	struct dentry *queue_folder;640	struct dentry *register_folder;641 642	intf = kzalloc(sizeof(struct rt2x00debug_intf), GFP_KERNEL);643	if (!intf) {644		rt2x00_err(rt2x00dev, "Failed to allocate debug handler\n");645		return;646	}647 648	intf->debug = debug;649	intf->rt2x00dev = rt2x00dev;650	rt2x00dev->debugfs_intf = intf;651 652	intf->driver_folder =653	    debugfs_create_dir(intf->rt2x00dev->ops->name,654			       rt2x00dev->hw->wiphy->debugfsdir);655 656	rt2x00debug_create_file_driver("driver", intf, &intf->driver_blob);657	rt2x00debug_create_file_chipset("chipset", intf, &intf->chipset_blob);658	debugfs_create_file("dev_flags", 0400, intf->driver_folder, intf,659			    &rt2x00debug_fop_dev_flags);660	debugfs_create_file("cap_flags", 0400, intf->driver_folder, intf,661			    &rt2x00debug_fop_cap_flags);662	debugfs_create_file("restart_hw", 0200, intf->driver_folder, intf,663			    &rt2x00debug_restart_hw);664 665	register_folder = debugfs_create_dir("register", intf->driver_folder);666 667#define RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(__intf, __name)		\668({									\669	if (debug->__name.read) {					\670		debugfs_create_u32(__stringify(__name) "_offset", 0600,	\671				   register_folder,			\672				   &(__intf)->offset_##__name);		\673									\674		debugfs_create_file(__stringify(__name) "_value", 0600,	\675				    register_folder, (__intf),		\676				    &rt2x00debug_fop_##__name);		\677	}								\678})679 680	RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(intf, csr);681	RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(intf, eeprom);682	RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(intf, bbp);683	RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(intf, rf);684	RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(intf, rfcsr);685 686#undef RT2X00DEBUGFS_CREATE_REGISTER_ENTRY687 688	queue_folder = debugfs_create_dir("queue", intf->driver_folder);689 690	debugfs_create_file("dump", 0400, queue_folder, intf,691			    &rt2x00debug_fop_queue_dump);692 693	skb_queue_head_init(&intf->frame_dump_skbqueue);694	init_waitqueue_head(&intf->frame_dump_waitqueue);695 696	debugfs_create_file("queue", 0400, queue_folder, intf,697			    &rt2x00debug_fop_queue_stats);698 699#ifdef CONFIG_RT2X00_LIB_CRYPTO700	if (rt2x00_has_cap_hw_crypto(rt2x00dev))701		debugfs_create_file("crypto", 0444, queue_folder, intf,702				    &rt2x00debug_fop_crypto_stats);703#endif704 705	return;706}707 708void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev)709{710	struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf;711 712	if (unlikely(!intf))713		return;714 715	skb_queue_purge(&intf->frame_dump_skbqueue);716 717	debugfs_remove_recursive(intf->driver_folder);718	kfree(intf->chipset_blob.data);719	kfree(intf->driver_blob.data);720	kfree(intf);721 722	rt2x00dev->debugfs_intf = NULL;723}724