[PATCH 1/4] ath10k: provide firmware crash info via debugfs.

Kalle Valo kvalo at qca.qualcomm.com
Fri Jun 6 02:33:44 PDT 2014


greearb at candelatech.com writes:

> From: Ben Greear <greearb at candelatech.com>
>
> Store the firmware crash registers and last 128 or so
> firmware debug-log ids and present them to user-space
> via debugfs.
>
> Should help with figuring out why the firmware crashed.
>
> Signed-off-by: Ben Greear <greearb at candelatech.com>

Review part 2.

> @@ -875,6 +877,80 @@ static void ath10k_pci_hif_dump_area(struct ath10k *ar)
>  			   reg_dump_values[i + 2],
>  			   reg_dump_values[i + 3]);
>  
> +	/* Dump the debug logs on the target */
> +	host_addr = host_interest_item_address(HI_ITEM(hi_dbglog_hdr));
> +	if (ath10k_pci_diag_read_mem(ar, host_addr,
> +				     &reg_dump_area, sizeof(u32)) != 0) {
> +		ath10k_warn("failed to read hi_dbglog_hdr\n");

Please print the error code.

> +		goto save_regs_and_restart;
> +	}
> +
> +	ath10k_err("target register Debug Log Location: 0x%08X\n",
> +		   reg_dump_area);

Is this needed? I think this more like debug log material than something
we should report to the user.

> +	ret = ath10k_pci_diag_read_mem(ar, reg_dump_area,
> +				       &dbg_hdr, sizeof(dbg_hdr));
> +	if (ret != 0) {
> +		ath10k_err("failed to dump Debug Log Area\n");

ath10k_warn("failed to dump debug log area: %d\n", ret);

> +		goto save_regs_and_restart;
> +	}
> +
> +	ath10k_err("Debug Log Header, dbuf: 0x%x  dropped: %i\n",
> +		   dbg_hdr.dbuf, dbg_hdr.dropped);

ath10k_dbg()?

> +	dbufp = dbg_hdr.dbuf;
> +	i = 0;
> +	while (dbufp) {

for (i = 0; dbufp > 0; i++)?

> +		struct ath10k_fw_dbglog_buf dbuf;

Please move to the beginning of the function.

> +		ret = ath10k_pci_diag_read_mem(ar, dbufp,
> +					       &dbuf, sizeof(dbuf));
> +		if (ret != 0) {
> +			ath10k_err("failed to read Debug Log Area: 0x%x\n",
> +				   dbufp);

ath10k_warn("failed to read debug log area: %d\n");

> +			goto save_regs_and_restart;
> +		}
> +
> +		/* We have a buffer of data */
> +		ath10k_err("[%i] next: 0x%x buf: 0x%x sz: %i len: %i count: %i free: %i\n",
> +			   i, dbuf.next, dbuf.buffer, dbuf.bufsize, dbuf.length,
> +			   dbuf.count, dbuf.free);

ath10k_dbg()?

> +		if (dbuf.buffer && dbuf.length) {

I would prefer inverse here to keep the indentation clean, something
like:

if (dbuf.buffer == 0 || dbug.length == 0)
        goto next;

> +			u8 *buffer = kmalloc(dbuf.length, GFP_ATOMIC);

Should we have a maximum for the length so that we don't allocate insane
amounts of memory by accident?

> +			if (buffer) {

Again I would prefer the inverse:

if (!buf)
   break;

I assume there's no sense continuing here if kmalloc fails and better
just bail out.

> +				ret = ath10k_pci_diag_read_mem(ar, dbuf.buffer,
> +							       buffer,
> +							       dbuf.length);
> +				if (ret != 0) {
> +					ath10k_err("failed to read Debug Log buffer: 0x%x\n",
> +						   dbuf.buffer);

ath10k_warn("failed to read debug log buffer: %d\n", ret);

> +					kfree(buffer);
> +					goto save_regs_and_restart;
> +				}
> +
> +				ath10k_dbg_save_fw_dbg_buffer(ar, buffer,
> +							      dbuf.length);
> +				kfree(buffer);

Instead of doing atomic allocations multiple times in a loop, would it
be better to allocate just one buffer before the loop and free it
afterwards?

> +			}
> +		}
> +		dbufp = dbuf.next;
> +		if (dbufp == dbg_hdr.dbuf) {
> +			/* It is a circular buffer it seems, bail if next
> +			 * is head
> +			 */
> +			break;
> +		}
> +		i++;
> +	} /* While we have a debug buffer to read */
> +
> +save_regs_and_restart:

exit_save_regs:

> +	if (!ar->crashed_since_read) {
> +		ar->crashed_since_read = true;
> +		memcpy(ar->reg_dump_values, reg_dump_values,
> +		       sizeof(ar->reg_dump_values));
> +	}

How is the locking handled in this function?

> +do_restart:

exit:

>  	queue_work(ar->workqueue, &ar->restart_work);
>  }

-- 
Kalle Valo



More information about the ath10k mailing list