|
@@ -1324,6 +1324,14 @@ static const struct file_operations iwl_dbgfs_##name##_ops = { \
|
|
|
.llseek = generic_file_llseek, \
|
|
|
};
|
|
|
|
|
|
+#define DEBUGFS_WRITE_FILE_OPS(name) \
|
|
|
+ DEBUGFS_WRITE_FUNC(name); \
|
|
|
+static const struct file_operations iwl_dbgfs_##name##_ops = { \
|
|
|
+ .write = iwl_dbgfs_##name##_write, \
|
|
|
+ .open = iwl_dbgfs_open_file_generic, \
|
|
|
+ .llseek = generic_file_llseek, \
|
|
|
+};
|
|
|
+
|
|
|
#define DEBUGFS_READ_WRITE_FILE_OPS(name) \
|
|
|
DEBUGFS_READ_FUNC(name); \
|
|
|
DEBUGFS_WRITE_FUNC(name); \
|
|
@@ -1635,11 +1643,183 @@ static ssize_t iwl_dbgfs_interrupt_write(struct file *file,
|
|
|
return count;
|
|
|
}
|
|
|
|
|
|
+static const char *get_csr_string(int cmd)
|
|
|
+{
|
|
|
+ switch (cmd) {
|
|
|
+ IWL_CMD(CSR_HW_IF_CONFIG_REG);
|
|
|
+ IWL_CMD(CSR_INT_COALESCING);
|
|
|
+ IWL_CMD(CSR_INT);
|
|
|
+ IWL_CMD(CSR_INT_MASK);
|
|
|
+ IWL_CMD(CSR_FH_INT_STATUS);
|
|
|
+ IWL_CMD(CSR_GPIO_IN);
|
|
|
+ IWL_CMD(CSR_RESET);
|
|
|
+ IWL_CMD(CSR_GP_CNTRL);
|
|
|
+ IWL_CMD(CSR_HW_REV);
|
|
|
+ IWL_CMD(CSR_EEPROM_REG);
|
|
|
+ IWL_CMD(CSR_EEPROM_GP);
|
|
|
+ IWL_CMD(CSR_OTP_GP_REG);
|
|
|
+ IWL_CMD(CSR_GIO_REG);
|
|
|
+ IWL_CMD(CSR_GP_UCODE_REG);
|
|
|
+ IWL_CMD(CSR_GP_DRIVER_REG);
|
|
|
+ IWL_CMD(CSR_UCODE_DRV_GP1);
|
|
|
+ IWL_CMD(CSR_UCODE_DRV_GP2);
|
|
|
+ IWL_CMD(CSR_LED_REG);
|
|
|
+ IWL_CMD(CSR_DRAM_INT_TBL_REG);
|
|
|
+ IWL_CMD(CSR_GIO_CHICKEN_BITS);
|
|
|
+ IWL_CMD(CSR_ANA_PLL_CFG);
|
|
|
+ IWL_CMD(CSR_HW_REV_WA_REG);
|
|
|
+ IWL_CMD(CSR_DBG_HPET_MEM_REG);
|
|
|
+ default:
|
|
|
+ return "UNKNOWN";
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void iwl_dump_csr(struct iwl_trans *trans)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ static const u32 csr_tbl[] = {
|
|
|
+ CSR_HW_IF_CONFIG_REG,
|
|
|
+ CSR_INT_COALESCING,
|
|
|
+ CSR_INT,
|
|
|
+ CSR_INT_MASK,
|
|
|
+ CSR_FH_INT_STATUS,
|
|
|
+ CSR_GPIO_IN,
|
|
|
+ CSR_RESET,
|
|
|
+ CSR_GP_CNTRL,
|
|
|
+ CSR_HW_REV,
|
|
|
+ CSR_EEPROM_REG,
|
|
|
+ CSR_EEPROM_GP,
|
|
|
+ CSR_OTP_GP_REG,
|
|
|
+ CSR_GIO_REG,
|
|
|
+ CSR_GP_UCODE_REG,
|
|
|
+ CSR_GP_DRIVER_REG,
|
|
|
+ CSR_UCODE_DRV_GP1,
|
|
|
+ CSR_UCODE_DRV_GP2,
|
|
|
+ CSR_LED_REG,
|
|
|
+ CSR_DRAM_INT_TBL_REG,
|
|
|
+ CSR_GIO_CHICKEN_BITS,
|
|
|
+ CSR_ANA_PLL_CFG,
|
|
|
+ CSR_HW_REV_WA_REG,
|
|
|
+ CSR_DBG_HPET_MEM_REG
|
|
|
+ };
|
|
|
+ IWL_ERR(trans, "CSR values:\n");
|
|
|
+ IWL_ERR(trans, "(2nd byte of CSR_INT_COALESCING is "
|
|
|
+ "CSR_INT_PERIODIC_REG)\n");
|
|
|
+ for (i = 0; i < ARRAY_SIZE(csr_tbl); i++) {
|
|
|
+ IWL_ERR(trans, " %25s: 0X%08x\n",
|
|
|
+ get_csr_string(csr_tbl[i]),
|
|
|
+ iwl_read32(priv(trans), csr_tbl[i]));
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t iwl_dbgfs_csr_write(struct file *file,
|
|
|
+ const char __user *user_buf,
|
|
|
+ size_t count, loff_t *ppos)
|
|
|
+{
|
|
|
+ struct iwl_trans *trans = file->private_data;
|
|
|
+ char buf[8];
|
|
|
+ int buf_size;
|
|
|
+ int csr;
|
|
|
+
|
|
|
+ memset(buf, 0, sizeof(buf));
|
|
|
+ buf_size = min(count, sizeof(buf) - 1);
|
|
|
+ if (copy_from_user(buf, user_buf, buf_size))
|
|
|
+ return -EFAULT;
|
|
|
+ if (sscanf(buf, "%d", &csr) != 1)
|
|
|
+ return -EFAULT;
|
|
|
+
|
|
|
+ iwl_dump_csr(trans);
|
|
|
+
|
|
|
+ return count;
|
|
|
+}
|
|
|
+
|
|
|
+static const char *get_fh_string(int cmd)
|
|
|
+{
|
|
|
+ switch (cmd) {
|
|
|
+ IWL_CMD(FH_RSCSR_CHNL0_STTS_WPTR_REG);
|
|
|
+ IWL_CMD(FH_RSCSR_CHNL0_RBDCB_BASE_REG);
|
|
|
+ IWL_CMD(FH_RSCSR_CHNL0_WPTR);
|
|
|
+ IWL_CMD(FH_MEM_RCSR_CHNL0_CONFIG_REG);
|
|
|
+ IWL_CMD(FH_MEM_RSSR_SHARED_CTRL_REG);
|
|
|
+ IWL_CMD(FH_MEM_RSSR_RX_STATUS_REG);
|
|
|
+ IWL_CMD(FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV);
|
|
|
+ IWL_CMD(FH_TSSR_TX_STATUS_REG);
|
|
|
+ IWL_CMD(FH_TSSR_TX_ERROR_REG);
|
|
|
+ default:
|
|
|
+ return "UNKNOWN";
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+int iwl_dump_fh(struct iwl_trans *trans, char **buf, bool display)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+#ifdef CONFIG_IWLWIFI_DEBUG
|
|
|
+ int pos = 0;
|
|
|
+ size_t bufsz = 0;
|
|
|
+#endif
|
|
|
+ static const u32 fh_tbl[] = {
|
|
|
+ FH_RSCSR_CHNL0_STTS_WPTR_REG,
|
|
|
+ FH_RSCSR_CHNL0_RBDCB_BASE_REG,
|
|
|
+ FH_RSCSR_CHNL0_WPTR,
|
|
|
+ FH_MEM_RCSR_CHNL0_CONFIG_REG,
|
|
|
+ FH_MEM_RSSR_SHARED_CTRL_REG,
|
|
|
+ FH_MEM_RSSR_RX_STATUS_REG,
|
|
|
+ FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV,
|
|
|
+ FH_TSSR_TX_STATUS_REG,
|
|
|
+ FH_TSSR_TX_ERROR_REG
|
|
|
+ };
|
|
|
+#ifdef CONFIG_IWLWIFI_DEBUG
|
|
|
+ if (display) {
|
|
|
+ bufsz = ARRAY_SIZE(fh_tbl) * 48 + 40;
|
|
|
+ *buf = kmalloc(bufsz, GFP_KERNEL);
|
|
|
+ if (!*buf)
|
|
|
+ return -ENOMEM;
|
|
|
+ pos += scnprintf(*buf + pos, bufsz - pos,
|
|
|
+ "FH register values:\n");
|
|
|
+ for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) {
|
|
|
+ pos += scnprintf(*buf + pos, bufsz - pos,
|
|
|
+ " %34s: 0X%08x\n",
|
|
|
+ get_fh_string(fh_tbl[i]),
|
|
|
+ iwl_read_direct32(priv(trans), fh_tbl[i]));
|
|
|
+ }
|
|
|
+ return pos;
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ IWL_ERR(trans, "FH register values:\n");
|
|
|
+ for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) {
|
|
|
+ IWL_ERR(trans, " %34s: 0X%08x\n",
|
|
|
+ get_fh_string(fh_tbl[i]),
|
|
|
+ iwl_read_direct32(priv(trans), fh_tbl[i]));
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t iwl_dbgfs_fh_reg_read(struct file *file,
|
|
|
+ char __user *user_buf,
|
|
|
+ size_t count, loff_t *ppos)
|
|
|
+{
|
|
|
+ struct iwl_trans *trans = file->private_data;
|
|
|
+ char *buf;
|
|
|
+ int pos = 0;
|
|
|
+ ssize_t ret = -EFAULT;
|
|
|
+
|
|
|
+ ret = pos = iwl_dump_fh(trans, &buf, true);
|
|
|
+ if (buf) {
|
|
|
+ ret = simple_read_from_buffer(user_buf,
|
|
|
+ count, ppos, buf, pos);
|
|
|
+ kfree(buf);
|
|
|
+ }
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
DEBUGFS_READ_WRITE_FILE_OPS(traffic_log);
|
|
|
DEBUGFS_READ_WRITE_FILE_OPS(log_event);
|
|
|
DEBUGFS_READ_WRITE_FILE_OPS(interrupt);
|
|
|
+DEBUGFS_READ_FILE_OPS(fh_reg);
|
|
|
DEBUGFS_READ_FILE_OPS(rx_queue);
|
|
|
DEBUGFS_READ_FILE_OPS(tx_queue);
|
|
|
+DEBUGFS_WRITE_FILE_OPS(csr);
|
|
|
|
|
|
/*
|
|
|
* Create the debugfs files and directories
|
|
@@ -1653,6 +1833,8 @@ static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
|
|
|
DEBUGFS_ADD_FILE(tx_queue, dir, S_IRUSR);
|
|
|
DEBUGFS_ADD_FILE(log_event, dir, S_IWUSR | S_IRUSR);
|
|
|
DEBUGFS_ADD_FILE(interrupt, dir, S_IWUSR | S_IRUSR);
|
|
|
+ DEBUGFS_ADD_FILE(csr, dir, S_IWUSR);
|
|
|
+ DEBUGFS_ADD_FILE(fh_reg, dir, S_IRUSR);
|
|
|
return 0;
|
|
|
}
|
|
|
#else
|