| Jing Huang | ab2a9ba | 2010-07-08 20:02:55 -0700 | [diff] [blame] | 1 | /* | 
 | 2 |  * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. | 
 | 3 |  * All rights reserved | 
 | 4 |  * www.brocade.com | 
 | 5 |  * | 
 | 6 |  * Linux driver for Brocade Fibre Channel Host Bus Adapter. | 
 | 7 |  * | 
 | 8 |  * This program is free software; you can redistribute it and/or modify it | 
 | 9 |  * under the terms of the GNU General Public License (GPL) Version 2 as | 
 | 10 |  * published by the Free Software Foundation | 
 | 11 |  * | 
 | 12 |  * This program is distributed in the hope that it will be useful, but | 
 | 13 |  * WITHOUT ANY WARRANTY; without even the implied warranty of | 
 | 14 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
 | 15 |  * General Public License for more details. | 
 | 16 |  */ | 
 | 17 |  | 
 | 18 | #include <linux/debugfs.h> | 
 | 19 |  | 
| Krishna Gudipati | a36c61f | 2010-09-15 11:50:55 -0700 | [diff] [blame] | 20 | #include "bfad_drv.h" | 
 | 21 | #include "bfad_im.h" | 
| Jing Huang | ab2a9ba | 2010-07-08 20:02:55 -0700 | [diff] [blame] | 22 |  | 
 | 23 | /* | 
 | 24 |  * BFA debufs interface | 
 | 25 |  * | 
 | 26 |  * To access the interface, debugfs file system should be mounted | 
 | 27 |  * if not already mounted using: | 
 | 28 |  * mount -t debugfs none /sys/kernel/debug | 
 | 29 |  * | 
 | 30 |  * BFA Hierarchy: | 
| Krishna Gudipati | 7c38c05 | 2011-04-14 16:50:35 -0700 | [diff] [blame] | 31 |  *	- bfa/pci_dev:<pci_name> | 
 | 32 |  * where the pci_name corresponds to the one under /sys/bus/pci/drivers/bfa | 
| Jing Huang | ab2a9ba | 2010-07-08 20:02:55 -0700 | [diff] [blame] | 33 |  * | 
| Krishna Gudipati | 7c38c05 | 2011-04-14 16:50:35 -0700 | [diff] [blame] | 34 |  * Debugging service available per pci_dev: | 
| Jing Huang | ab2a9ba | 2010-07-08 20:02:55 -0700 | [diff] [blame] | 35 |  * fwtrc:  To collect current firmware trace. | 
 | 36 |  * drvtrc: To collect current driver trace | 
 | 37 |  * fwsave: To collect last saved fw trace as a result of firmware crash. | 
 | 38 |  * regwr:  To write one word to chip register | 
 | 39 |  * regrd:  To read one or more words from chip register. | 
 | 40 |  */ | 
 | 41 |  | 
 | 42 | struct bfad_debug_info { | 
 | 43 | 	char *debug_buffer; | 
 | 44 | 	void *i_private; | 
 | 45 | 	int buffer_len; | 
 | 46 | }; | 
 | 47 |  | 
 | 48 | static int | 
 | 49 | bfad_debugfs_open_drvtrc(struct inode *inode, struct file *file) | 
 | 50 | { | 
 | 51 | 	struct bfad_port_s *port = inode->i_private; | 
 | 52 | 	struct bfad_s *bfad = port->bfad; | 
 | 53 | 	struct bfad_debug_info *debug; | 
 | 54 |  | 
 | 55 | 	debug = kzalloc(sizeof(struct bfad_debug_info), GFP_KERNEL); | 
 | 56 | 	if (!debug) | 
 | 57 | 		return -ENOMEM; | 
 | 58 |  | 
 | 59 | 	debug->debug_buffer = (void *) bfad->trcmod; | 
 | 60 | 	debug->buffer_len = sizeof(struct bfa_trc_mod_s); | 
 | 61 |  | 
 | 62 | 	file->private_data = debug; | 
 | 63 |  | 
 | 64 | 	return 0; | 
 | 65 | } | 
 | 66 |  | 
 | 67 | static int | 
 | 68 | bfad_debugfs_open_fwtrc(struct inode *inode, struct file *file) | 
 | 69 | { | 
 | 70 | 	struct bfad_port_s *port = inode->i_private; | 
 | 71 | 	struct bfad_s *bfad = port->bfad; | 
 | 72 | 	struct bfad_debug_info *fw_debug; | 
 | 73 | 	unsigned long flags; | 
 | 74 | 	int rc; | 
 | 75 |  | 
 | 76 | 	fw_debug = kzalloc(sizeof(struct bfad_debug_info), GFP_KERNEL); | 
 | 77 | 	if (!fw_debug) | 
 | 78 | 		return -ENOMEM; | 
 | 79 |  | 
 | 80 | 	fw_debug->buffer_len = sizeof(struct bfa_trc_mod_s); | 
 | 81 |  | 
 | 82 | 	fw_debug->debug_buffer = vmalloc(fw_debug->buffer_len); | 
 | 83 | 	if (!fw_debug->debug_buffer) { | 
 | 84 | 		kfree(fw_debug); | 
 | 85 | 		printk(KERN_INFO "bfad[%d]: Failed to allocate fwtrc buffer\n", | 
 | 86 | 				bfad->inst_no); | 
 | 87 | 		return -ENOMEM; | 
 | 88 | 	} | 
 | 89 |  | 
 | 90 | 	memset(fw_debug->debug_buffer, 0, fw_debug->buffer_len); | 
 | 91 |  | 
 | 92 | 	spin_lock_irqsave(&bfad->bfad_lock, flags); | 
| Maggie Zhang | f7f7381 | 2010-12-09 19:08:43 -0800 | [diff] [blame] | 93 | 	rc = bfa_ioc_debug_fwtrc(&bfad->bfa.ioc, | 
| Jing Huang | ab2a9ba | 2010-07-08 20:02:55 -0700 | [diff] [blame] | 94 | 			fw_debug->debug_buffer, | 
 | 95 | 			&fw_debug->buffer_len); | 
 | 96 | 	spin_unlock_irqrestore(&bfad->bfad_lock, flags); | 
 | 97 | 	if (rc != BFA_STATUS_OK) { | 
 | 98 | 		vfree(fw_debug->debug_buffer); | 
 | 99 | 		fw_debug->debug_buffer = NULL; | 
 | 100 | 		kfree(fw_debug); | 
 | 101 | 		printk(KERN_INFO "bfad[%d]: Failed to collect fwtrc\n", | 
 | 102 | 				bfad->inst_no); | 
 | 103 | 		return -ENOMEM; | 
 | 104 | 	} | 
 | 105 |  | 
 | 106 | 	file->private_data = fw_debug; | 
 | 107 |  | 
 | 108 | 	return 0; | 
 | 109 | } | 
 | 110 |  | 
 | 111 | static int | 
 | 112 | bfad_debugfs_open_fwsave(struct inode *inode, struct file *file) | 
 | 113 | { | 
 | 114 | 	struct bfad_port_s *port = inode->i_private; | 
 | 115 | 	struct bfad_s *bfad = port->bfad; | 
 | 116 | 	struct bfad_debug_info *fw_debug; | 
 | 117 | 	unsigned long flags; | 
 | 118 | 	int rc; | 
 | 119 |  | 
 | 120 | 	fw_debug = kzalloc(sizeof(struct bfad_debug_info), GFP_KERNEL); | 
 | 121 | 	if (!fw_debug) | 
 | 122 | 		return -ENOMEM; | 
 | 123 |  | 
 | 124 | 	fw_debug->buffer_len = sizeof(struct bfa_trc_mod_s); | 
 | 125 |  | 
 | 126 | 	fw_debug->debug_buffer = vmalloc(fw_debug->buffer_len); | 
 | 127 | 	if (!fw_debug->debug_buffer) { | 
 | 128 | 		kfree(fw_debug); | 
 | 129 | 		printk(KERN_INFO "bfad[%d]: Failed to allocate fwsave buffer\n", | 
 | 130 | 				bfad->inst_no); | 
 | 131 | 		return -ENOMEM; | 
 | 132 | 	} | 
 | 133 |  | 
 | 134 | 	memset(fw_debug->debug_buffer, 0, fw_debug->buffer_len); | 
 | 135 |  | 
 | 136 | 	spin_lock_irqsave(&bfad->bfad_lock, flags); | 
| Maggie Zhang | f7f7381 | 2010-12-09 19:08:43 -0800 | [diff] [blame] | 137 | 	rc = bfa_ioc_debug_fwsave(&bfad->bfa.ioc, | 
| Jing Huang | ab2a9ba | 2010-07-08 20:02:55 -0700 | [diff] [blame] | 138 | 			fw_debug->debug_buffer, | 
 | 139 | 			&fw_debug->buffer_len); | 
 | 140 | 	spin_unlock_irqrestore(&bfad->bfad_lock, flags); | 
 | 141 | 	if (rc != BFA_STATUS_OK) { | 
 | 142 | 		vfree(fw_debug->debug_buffer); | 
 | 143 | 		fw_debug->debug_buffer = NULL; | 
 | 144 | 		kfree(fw_debug); | 
 | 145 | 		printk(KERN_INFO "bfad[%d]: Failed to collect fwsave\n", | 
 | 146 | 				bfad->inst_no); | 
 | 147 | 		return -ENOMEM; | 
 | 148 | 	} | 
 | 149 |  | 
 | 150 | 	file->private_data = fw_debug; | 
 | 151 |  | 
 | 152 | 	return 0; | 
 | 153 | } | 
 | 154 |  | 
 | 155 | static int | 
 | 156 | bfad_debugfs_open_reg(struct inode *inode, struct file *file) | 
 | 157 | { | 
 | 158 | 	struct bfad_debug_info *reg_debug; | 
 | 159 |  | 
 | 160 | 	reg_debug = kzalloc(sizeof(struct bfad_debug_info), GFP_KERNEL); | 
 | 161 | 	if (!reg_debug) | 
 | 162 | 		return -ENOMEM; | 
 | 163 |  | 
 | 164 | 	reg_debug->i_private = inode->i_private; | 
 | 165 |  | 
 | 166 | 	file->private_data = reg_debug; | 
 | 167 |  | 
 | 168 | 	return 0; | 
 | 169 | } | 
 | 170 |  | 
 | 171 | /* Changes the current file position */ | 
 | 172 | static loff_t | 
 | 173 | bfad_debugfs_lseek(struct file *file, loff_t offset, int orig) | 
 | 174 | { | 
 | 175 | 	struct bfad_debug_info *debug; | 
 | 176 | 	loff_t pos = file->f_pos; | 
 | 177 |  | 
 | 178 | 	debug = file->private_data; | 
 | 179 |  | 
 | 180 | 	switch (orig) { | 
 | 181 | 	case 0: | 
 | 182 | 		file->f_pos = offset; | 
 | 183 | 		break; | 
 | 184 | 	case 1: | 
 | 185 | 		file->f_pos += offset; | 
 | 186 | 		break; | 
 | 187 | 	case 2: | 
 | 188 | 		file->f_pos = debug->buffer_len - offset; | 
 | 189 | 		break; | 
 | 190 | 	default: | 
 | 191 | 		return -EINVAL; | 
 | 192 | 	} | 
 | 193 |  | 
 | 194 | 	if (file->f_pos < 0 || file->f_pos > debug->buffer_len) { | 
 | 195 | 		file->f_pos = pos; | 
 | 196 | 		return -EINVAL; | 
 | 197 | 	} | 
 | 198 |  | 
 | 199 | 	return file->f_pos; | 
 | 200 | } | 
 | 201 |  | 
 | 202 | static ssize_t | 
 | 203 | bfad_debugfs_read(struct file *file, char __user *buf, | 
 | 204 | 			size_t nbytes, loff_t *pos) | 
 | 205 | { | 
 | 206 | 	struct bfad_debug_info *debug = file->private_data; | 
 | 207 |  | 
 | 208 | 	if (!debug || !debug->debug_buffer) | 
 | 209 | 		return 0; | 
 | 210 |  | 
| Maggie | 52f94b6 | 2010-11-29 18:21:32 -0800 | [diff] [blame] | 211 | 	return simple_read_from_buffer(buf, nbytes, pos, | 
| Jing Huang | ab2a9ba | 2010-07-08 20:02:55 -0700 | [diff] [blame] | 212 | 				debug->debug_buffer, debug->buffer_len); | 
 | 213 | } | 
 | 214 |  | 
 | 215 | #define BFA_REG_CT_ADDRSZ	(0x40000) | 
 | 216 | #define BFA_REG_CB_ADDRSZ	(0x20000) | 
 | 217 | #define BFA_REG_ADDRSZ(__bfa)	\ | 
 | 218 | 	((bfa_ioc_devid(&(__bfa)->ioc) == BFA_PCI_DEVICE_ID_CT) ?	\ | 
 | 219 | 		BFA_REG_CT_ADDRSZ : BFA_REG_CB_ADDRSZ) | 
| Krishna Gudipati | a36c61f | 2010-09-15 11:50:55 -0700 | [diff] [blame] | 220 | #define BFA_REG_ADDRMSK(__bfa)  ((u32)(BFA_REG_ADDRSZ(__bfa) - 1)) | 
| Jing Huang | ab2a9ba | 2010-07-08 20:02:55 -0700 | [diff] [blame] | 221 |  | 
 | 222 | static bfa_status_t | 
 | 223 | bfad_reg_offset_check(struct bfa_s *bfa, u32 offset, u32 len) | 
 | 224 | { | 
 | 225 | 	u8	area; | 
 | 226 |  | 
 | 227 | 	/* check [16:15] */ | 
 | 228 | 	area = (offset >> 15) & 0x7; | 
 | 229 | 	if (area == 0) { | 
 | 230 | 		/* PCIe core register */ | 
 | 231 | 		if ((offset + (len<<2)) > 0x8000)    /* 8k dwords or 32KB */ | 
 | 232 | 			return BFA_STATUS_EINVAL; | 
 | 233 | 	} else if (area == 0x1) { | 
 | 234 | 		/* CB 32 KB memory page */ | 
 | 235 | 		if ((offset + (len<<2)) > 0x10000)    /* 8k dwords or 32KB */ | 
 | 236 | 			return BFA_STATUS_EINVAL; | 
 | 237 | 	} else { | 
 | 238 | 		/* CB register space 64KB */ | 
 | 239 | 		if ((offset + (len<<2)) > BFA_REG_ADDRMSK(bfa)) | 
 | 240 | 			return BFA_STATUS_EINVAL; | 
 | 241 | 	} | 
 | 242 | 	return BFA_STATUS_OK; | 
 | 243 | } | 
 | 244 |  | 
 | 245 | static ssize_t | 
 | 246 | bfad_debugfs_read_regrd(struct file *file, char __user *buf, | 
 | 247 | 		size_t nbytes, loff_t *pos) | 
 | 248 | { | 
 | 249 | 	struct bfad_debug_info *regrd_debug = file->private_data; | 
 | 250 | 	struct bfad_port_s *port = (struct bfad_port_s *)regrd_debug->i_private; | 
 | 251 | 	struct bfad_s *bfad = port->bfad; | 
 | 252 | 	ssize_t rc; | 
 | 253 |  | 
 | 254 | 	if (!bfad->regdata) | 
 | 255 | 		return 0; | 
 | 256 |  | 
| Maggie | 52f94b6 | 2010-11-29 18:21:32 -0800 | [diff] [blame] | 257 | 	rc = simple_read_from_buffer(buf, nbytes, pos, | 
| Jing Huang | ab2a9ba | 2010-07-08 20:02:55 -0700 | [diff] [blame] | 258 | 			bfad->regdata, bfad->reglen); | 
 | 259 |  | 
 | 260 | 	if ((*pos + nbytes) >= bfad->reglen) { | 
 | 261 | 		kfree(bfad->regdata); | 
 | 262 | 		bfad->regdata = NULL; | 
 | 263 | 		bfad->reglen = 0; | 
 | 264 | 	} | 
 | 265 |  | 
 | 266 | 	return rc; | 
 | 267 | } | 
 | 268 |  | 
 | 269 | static ssize_t | 
 | 270 | bfad_debugfs_write_regrd(struct file *file, const char __user *buf, | 
 | 271 | 		size_t nbytes, loff_t *ppos) | 
 | 272 | { | 
 | 273 | 	struct bfad_debug_info *regrd_debug = file->private_data; | 
 | 274 | 	struct bfad_port_s *port = (struct bfad_port_s *)regrd_debug->i_private; | 
 | 275 | 	struct bfad_s *bfad = port->bfad; | 
 | 276 | 	struct bfa_s *bfa = &bfad->bfa; | 
 | 277 | 	struct bfa_ioc_s *ioc = &bfa->ioc; | 
 | 278 | 	int addr, len, rc, i; | 
 | 279 | 	u32 *regbuf; | 
 | 280 | 	void __iomem *rb, *reg_addr; | 
 | 281 | 	unsigned long flags; | 
| Maggie | 52f94b6 | 2010-11-29 18:21:32 -0800 | [diff] [blame] | 282 | 	void *kern_buf; | 
| Jing Huang | ab2a9ba | 2010-07-08 20:02:55 -0700 | [diff] [blame] | 283 |  | 
| Maggie | 52f94b6 | 2010-11-29 18:21:32 -0800 | [diff] [blame] | 284 | 	kern_buf = kzalloc(nbytes, GFP_KERNEL); | 
 | 285 |  | 
 | 286 | 	if (!kern_buf) { | 
 | 287 | 		printk(KERN_INFO "bfad[%d]: Failed to allocate buffer\n", | 
 | 288 | 				bfad->inst_no); | 
 | 289 | 		return -ENOMEM; | 
 | 290 | 	} | 
 | 291 |  | 
 | 292 | 	if (copy_from_user(kern_buf, (void  __user *)buf, nbytes)) { | 
 | 293 | 		kfree(kern_buf); | 
 | 294 | 		return -ENOMEM; | 
 | 295 | 	} | 
 | 296 |  | 
 | 297 | 	rc = sscanf(kern_buf, "%x:%x", &addr, &len); | 
| Jing Huang | ab2a9ba | 2010-07-08 20:02:55 -0700 | [diff] [blame] | 298 | 	if (rc < 2) { | 
 | 299 | 		printk(KERN_INFO | 
 | 300 | 			"bfad[%d]: %s failed to read user buf\n", | 
 | 301 | 			bfad->inst_no, __func__); | 
| Maggie | 52f94b6 | 2010-11-29 18:21:32 -0800 | [diff] [blame] | 302 | 		kfree(kern_buf); | 
| Jing Huang | ab2a9ba | 2010-07-08 20:02:55 -0700 | [diff] [blame] | 303 | 		return -EINVAL; | 
 | 304 | 	} | 
 | 305 |  | 
| Maggie | 52f94b6 | 2010-11-29 18:21:32 -0800 | [diff] [blame] | 306 | 	kfree(kern_buf); | 
| Jing Huang | ab2a9ba | 2010-07-08 20:02:55 -0700 | [diff] [blame] | 307 | 	kfree(bfad->regdata); | 
 | 308 | 	bfad->regdata = NULL; | 
 | 309 | 	bfad->reglen = 0; | 
 | 310 |  | 
 | 311 | 	bfad->regdata = kzalloc(len << 2, GFP_KERNEL); | 
 | 312 | 	if (!bfad->regdata) { | 
 | 313 | 		printk(KERN_INFO "bfad[%d]: Failed to allocate regrd buffer\n", | 
 | 314 | 				bfad->inst_no); | 
 | 315 | 		return -ENOMEM; | 
 | 316 | 	} | 
 | 317 |  | 
 | 318 | 	bfad->reglen = len << 2; | 
 | 319 | 	rb = bfa_ioc_bar0(ioc); | 
 | 320 | 	addr &= BFA_REG_ADDRMSK(bfa); | 
 | 321 |  | 
 | 322 | 	/* offset and len sanity check */ | 
 | 323 | 	rc = bfad_reg_offset_check(bfa, addr, len); | 
 | 324 | 	if (rc) { | 
 | 325 | 		printk(KERN_INFO "bfad[%d]: Failed reg offset check\n", | 
 | 326 | 				bfad->inst_no); | 
 | 327 | 		kfree(bfad->regdata); | 
 | 328 | 		bfad->regdata = NULL; | 
 | 329 | 		bfad->reglen = 0; | 
 | 330 | 		return -EINVAL; | 
 | 331 | 	} | 
 | 332 |  | 
 | 333 | 	reg_addr = rb + addr; | 
 | 334 | 	regbuf =  (u32 *)bfad->regdata; | 
 | 335 | 	spin_lock_irqsave(&bfad->bfad_lock, flags); | 
 | 336 | 	for (i = 0; i < len; i++) { | 
| Jing Huang | 5344026 | 2010-10-18 17:12:29 -0700 | [diff] [blame] | 337 | 		*regbuf = readl(reg_addr); | 
| Jing Huang | ab2a9ba | 2010-07-08 20:02:55 -0700 | [diff] [blame] | 338 | 		regbuf++; | 
 | 339 | 		reg_addr += sizeof(u32); | 
 | 340 | 	} | 
 | 341 | 	spin_unlock_irqrestore(&bfad->bfad_lock, flags); | 
 | 342 |  | 
 | 343 | 	return nbytes; | 
 | 344 | } | 
 | 345 |  | 
 | 346 | static ssize_t | 
 | 347 | bfad_debugfs_write_regwr(struct file *file, const char __user *buf, | 
 | 348 | 		size_t nbytes, loff_t *ppos) | 
 | 349 | { | 
 | 350 | 	struct bfad_debug_info *debug = file->private_data; | 
 | 351 | 	struct bfad_port_s *port = (struct bfad_port_s *)debug->i_private; | 
 | 352 | 	struct bfad_s *bfad = port->bfad; | 
 | 353 | 	struct bfa_s *bfa = &bfad->bfa; | 
 | 354 | 	struct bfa_ioc_s *ioc = &bfa->ioc; | 
 | 355 | 	int addr, val, rc; | 
 | 356 | 	void __iomem *reg_addr; | 
 | 357 | 	unsigned long flags; | 
| Maggie | 52f94b6 | 2010-11-29 18:21:32 -0800 | [diff] [blame] | 358 | 	void *kern_buf; | 
| Jing Huang | ab2a9ba | 2010-07-08 20:02:55 -0700 | [diff] [blame] | 359 |  | 
| Maggie | 52f94b6 | 2010-11-29 18:21:32 -0800 | [diff] [blame] | 360 | 	kern_buf = kzalloc(nbytes, GFP_KERNEL); | 
 | 361 |  | 
 | 362 | 	if (!kern_buf) { | 
 | 363 | 		printk(KERN_INFO "bfad[%d]: Failed to allocate buffer\n", | 
 | 364 | 				bfad->inst_no); | 
 | 365 | 		return -ENOMEM; | 
 | 366 | 	} | 
 | 367 |  | 
 | 368 | 	if (copy_from_user(kern_buf, (void  __user *)buf, nbytes)) { | 
 | 369 | 		kfree(kern_buf); | 
 | 370 | 		return -ENOMEM; | 
 | 371 | 	} | 
 | 372 |  | 
 | 373 | 	rc = sscanf(kern_buf, "%x:%x", &addr, &val); | 
| Jing Huang | ab2a9ba | 2010-07-08 20:02:55 -0700 | [diff] [blame] | 374 | 	if (rc < 2) { | 
 | 375 | 		printk(KERN_INFO | 
 | 376 | 			"bfad[%d]: %s failed to read user buf\n", | 
 | 377 | 			bfad->inst_no, __func__); | 
| Maggie | 52f94b6 | 2010-11-29 18:21:32 -0800 | [diff] [blame] | 378 | 		kfree(kern_buf); | 
| Jing Huang | ab2a9ba | 2010-07-08 20:02:55 -0700 | [diff] [blame] | 379 | 		return -EINVAL; | 
 | 380 | 	} | 
| Maggie | 52f94b6 | 2010-11-29 18:21:32 -0800 | [diff] [blame] | 381 | 	kfree(kern_buf); | 
| Jing Huang | ab2a9ba | 2010-07-08 20:02:55 -0700 | [diff] [blame] | 382 |  | 
 | 383 | 	addr &= BFA_REG_ADDRMSK(bfa); /* offset only 17 bit and word align */ | 
 | 384 |  | 
 | 385 | 	/* offset and len sanity check */ | 
 | 386 | 	rc = bfad_reg_offset_check(bfa, addr, 1); | 
 | 387 | 	if (rc) { | 
 | 388 | 		printk(KERN_INFO | 
 | 389 | 			"bfad[%d]: Failed reg offset check\n", | 
 | 390 | 			bfad->inst_no); | 
 | 391 | 		return -EINVAL; | 
 | 392 | 	} | 
 | 393 |  | 
| Maggie | 52f94b6 | 2010-11-29 18:21:32 -0800 | [diff] [blame] | 394 | 	reg_addr = (bfa_ioc_bar0(ioc)) + addr; | 
| Jing Huang | ab2a9ba | 2010-07-08 20:02:55 -0700 | [diff] [blame] | 395 | 	spin_lock_irqsave(&bfad->bfad_lock, flags); | 
| Jing Huang | 5344026 | 2010-10-18 17:12:29 -0700 | [diff] [blame] | 396 | 	writel(val, reg_addr); | 
| Jing Huang | ab2a9ba | 2010-07-08 20:02:55 -0700 | [diff] [blame] | 397 | 	spin_unlock_irqrestore(&bfad->bfad_lock, flags); | 
 | 398 |  | 
 | 399 | 	return nbytes; | 
 | 400 | } | 
 | 401 |  | 
 | 402 | static int | 
 | 403 | bfad_debugfs_release(struct inode *inode, struct file *file) | 
 | 404 | { | 
 | 405 | 	struct bfad_debug_info *debug = file->private_data; | 
 | 406 |  | 
 | 407 | 	if (!debug) | 
 | 408 | 		return 0; | 
 | 409 |  | 
 | 410 | 	file->private_data = NULL; | 
 | 411 | 	kfree(debug); | 
 | 412 | 	return 0; | 
 | 413 | } | 
 | 414 |  | 
 | 415 | static int | 
 | 416 | bfad_debugfs_release_fwtrc(struct inode *inode, struct file *file) | 
 | 417 | { | 
 | 418 | 	struct bfad_debug_info *fw_debug = file->private_data; | 
 | 419 |  | 
 | 420 | 	if (!fw_debug) | 
 | 421 | 		return 0; | 
 | 422 |  | 
 | 423 | 	if (fw_debug->debug_buffer) | 
 | 424 | 		vfree(fw_debug->debug_buffer); | 
 | 425 |  | 
 | 426 | 	file->private_data = NULL; | 
 | 427 | 	kfree(fw_debug); | 
 | 428 | 	return 0; | 
 | 429 | } | 
 | 430 |  | 
 | 431 | static const struct file_operations bfad_debugfs_op_drvtrc = { | 
 | 432 | 	.owner		=	THIS_MODULE, | 
 | 433 | 	.open		=	bfad_debugfs_open_drvtrc, | 
 | 434 | 	.llseek		=	bfad_debugfs_lseek, | 
 | 435 | 	.read		=	bfad_debugfs_read, | 
 | 436 | 	.release	=	bfad_debugfs_release, | 
 | 437 | }; | 
 | 438 |  | 
 | 439 | static const struct file_operations bfad_debugfs_op_fwtrc = { | 
 | 440 | 	.owner		=	THIS_MODULE, | 
 | 441 | 	.open		=	bfad_debugfs_open_fwtrc, | 
 | 442 | 	.llseek		=	bfad_debugfs_lseek, | 
 | 443 | 	.read		=	bfad_debugfs_read, | 
 | 444 | 	.release	=	bfad_debugfs_release_fwtrc, | 
 | 445 | }; | 
 | 446 |  | 
 | 447 | static const struct file_operations bfad_debugfs_op_fwsave = { | 
 | 448 | 	.owner		=	THIS_MODULE, | 
 | 449 | 	.open		=	bfad_debugfs_open_fwsave, | 
 | 450 | 	.llseek		=	bfad_debugfs_lseek, | 
 | 451 | 	.read		=	bfad_debugfs_read, | 
 | 452 | 	.release	=	bfad_debugfs_release_fwtrc, | 
 | 453 | }; | 
 | 454 |  | 
 | 455 | static const struct file_operations bfad_debugfs_op_regrd = { | 
 | 456 | 	.owner		=	THIS_MODULE, | 
 | 457 | 	.open		=	bfad_debugfs_open_reg, | 
 | 458 | 	.llseek		=	bfad_debugfs_lseek, | 
 | 459 | 	.read		=	bfad_debugfs_read_regrd, | 
 | 460 | 	.write		=	bfad_debugfs_write_regrd, | 
 | 461 | 	.release	=	bfad_debugfs_release, | 
 | 462 | }; | 
 | 463 |  | 
 | 464 | static const struct file_operations bfad_debugfs_op_regwr = { | 
 | 465 | 	.owner		=	THIS_MODULE, | 
 | 466 | 	.open		=	bfad_debugfs_open_reg, | 
 | 467 | 	.llseek		=	bfad_debugfs_lseek, | 
 | 468 | 	.write		=	bfad_debugfs_write_regwr, | 
 | 469 | 	.release	=	bfad_debugfs_release, | 
 | 470 | }; | 
 | 471 |  | 
 | 472 | struct bfad_debugfs_entry { | 
 | 473 | 	const char *name; | 
 | 474 | 	mode_t	mode; | 
 | 475 | 	const struct file_operations *fops; | 
 | 476 | }; | 
 | 477 |  | 
 | 478 | static const struct bfad_debugfs_entry bfad_debugfs_files[] = { | 
 | 479 | 	{ "drvtrc", S_IFREG|S_IRUGO, &bfad_debugfs_op_drvtrc, }, | 
 | 480 | 	{ "fwtrc",  S_IFREG|S_IRUGO, &bfad_debugfs_op_fwtrc,  }, | 
 | 481 | 	{ "fwsave", S_IFREG|S_IRUGO, &bfad_debugfs_op_fwsave, }, | 
 | 482 | 	{ "regrd",  S_IFREG|S_IRUGO|S_IWUSR, &bfad_debugfs_op_regrd,  }, | 
 | 483 | 	{ "regwr",  S_IFREG|S_IWUSR, &bfad_debugfs_op_regwr,  }, | 
 | 484 | }; | 
 | 485 |  | 
 | 486 | static struct dentry *bfa_debugfs_root; | 
 | 487 | static atomic_t bfa_debugfs_port_count; | 
 | 488 |  | 
 | 489 | inline void | 
 | 490 | bfad_debugfs_init(struct bfad_port_s *port) | 
 | 491 | { | 
| Krishna Gudipati | 7c38c05 | 2011-04-14 16:50:35 -0700 | [diff] [blame] | 492 | 	struct bfad_s *bfad = port->bfad; | 
| Jing Huang | ab2a9ba | 2010-07-08 20:02:55 -0700 | [diff] [blame] | 493 | 	const struct bfad_debugfs_entry *file; | 
| Krishna Gudipati | 7c38c05 | 2011-04-14 16:50:35 -0700 | [diff] [blame] | 494 | 	char name[64]; | 
| Jing Huang | ab2a9ba | 2010-07-08 20:02:55 -0700 | [diff] [blame] | 495 | 	int i; | 
 | 496 |  | 
 | 497 | 	if (!bfa_debugfs_enable) | 
 | 498 | 		return; | 
 | 499 |  | 
 | 500 | 	/* Setup the BFA debugfs root directory*/ | 
 | 501 | 	if (!bfa_debugfs_root) { | 
 | 502 | 		bfa_debugfs_root = debugfs_create_dir("bfa", NULL); | 
 | 503 | 		atomic_set(&bfa_debugfs_port_count, 0); | 
 | 504 | 		if (!bfa_debugfs_root) { | 
 | 505 | 			printk(KERN_WARNING | 
 | 506 | 				"BFA debugfs root dir creation failed\n"); | 
 | 507 | 			goto err; | 
 | 508 | 		} | 
 | 509 | 	} | 
 | 510 |  | 
| Krishna Gudipati | 7c38c05 | 2011-04-14 16:50:35 -0700 | [diff] [blame] | 511 | 	/* Setup the pci_dev debugfs directory for the port */ | 
 | 512 | 	snprintf(name, sizeof(name), "pci_dev:%s", bfad->pci_name); | 
| Jing Huang | ab2a9ba | 2010-07-08 20:02:55 -0700 | [diff] [blame] | 513 | 	if (!port->port_debugfs_root) { | 
 | 514 | 		port->port_debugfs_root = | 
 | 515 | 			debugfs_create_dir(name, bfa_debugfs_root); | 
 | 516 | 		if (!port->port_debugfs_root) { | 
 | 517 | 			printk(KERN_WARNING | 
| Krishna Gudipati | 7c38c05 | 2011-04-14 16:50:35 -0700 | [diff] [blame] | 518 | 				"bfa %s: debugfs root creation failed\n", | 
 | 519 | 				bfad->pci_name); | 
| Jing Huang | ab2a9ba | 2010-07-08 20:02:55 -0700 | [diff] [blame] | 520 | 			goto err; | 
 | 521 | 		} | 
 | 522 |  | 
 | 523 | 		atomic_inc(&bfa_debugfs_port_count); | 
 | 524 |  | 
 | 525 | 		for (i = 0; i < ARRAY_SIZE(bfad_debugfs_files); i++) { | 
 | 526 | 			file = &bfad_debugfs_files[i]; | 
 | 527 | 			bfad->bfad_dentry_files[i] = | 
 | 528 | 					debugfs_create_file(file->name, | 
 | 529 | 							file->mode, | 
 | 530 | 							port->port_debugfs_root, | 
 | 531 | 							port, | 
 | 532 | 							file->fops); | 
 | 533 | 			if (!bfad->bfad_dentry_files[i]) { | 
 | 534 | 				printk(KERN_WARNING | 
| Krishna Gudipati | 7c38c05 | 2011-04-14 16:50:35 -0700 | [diff] [blame] | 535 | 					"bfa %s: debugfs %s creation failed\n", | 
 | 536 | 					bfad->pci_name, file->name); | 
| Jing Huang | ab2a9ba | 2010-07-08 20:02:55 -0700 | [diff] [blame] | 537 | 				goto err; | 
 | 538 | 			} | 
 | 539 | 		} | 
 | 540 | 	} | 
 | 541 |  | 
 | 542 | err: | 
 | 543 | 	return; | 
 | 544 | } | 
 | 545 |  | 
 | 546 | inline void | 
 | 547 | bfad_debugfs_exit(struct bfad_port_s *port) | 
 | 548 | { | 
| Krishna Gudipati | 7c38c05 | 2011-04-14 16:50:35 -0700 | [diff] [blame] | 549 | 	struct bfad_s *bfad = port->bfad; | 
| Jing Huang | ab2a9ba | 2010-07-08 20:02:55 -0700 | [diff] [blame] | 550 | 	int i; | 
 | 551 |  | 
 | 552 | 	for (i = 0; i < ARRAY_SIZE(bfad_debugfs_files); i++) { | 
 | 553 | 		if (bfad->bfad_dentry_files[i]) { | 
 | 554 | 			debugfs_remove(bfad->bfad_dentry_files[i]); | 
 | 555 | 			bfad->bfad_dentry_files[i] = NULL; | 
 | 556 | 		} | 
 | 557 | 	} | 
 | 558 |  | 
 | 559 | 	/* | 
| Krishna Gudipati | 7c38c05 | 2011-04-14 16:50:35 -0700 | [diff] [blame] | 560 | 	 * Remove the pci_dev debugfs directory for the port */ | 
| Jing Huang | ab2a9ba | 2010-07-08 20:02:55 -0700 | [diff] [blame] | 561 | 	if (port->port_debugfs_root) { | 
 | 562 | 		debugfs_remove(port->port_debugfs_root); | 
 | 563 | 		port->port_debugfs_root = NULL; | 
 | 564 | 		atomic_dec(&bfa_debugfs_port_count); | 
 | 565 | 	} | 
 | 566 |  | 
 | 567 | 	/* Remove the BFA debugfs root directory */ | 
 | 568 | 	if (atomic_read(&bfa_debugfs_port_count) == 0) { | 
 | 569 | 		debugfs_remove(bfa_debugfs_root); | 
 | 570 | 		bfa_debugfs_root = NULL; | 
 | 571 | 	} | 
 | 572 | } |