aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>2011-08-26 02:10:54 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-08-29 15:25:33 -0400
commit7ff94706a055f3e21710b08ffbe3979d7db615db (patch)
tree453cabac4b495e4ee8d7fe63a193435e90920883
parent0c325769a394559941acda83e888a1d9b1ef8b7f (diff)
iwlagn: move the NIC error flow to the transport layer
It is transport dependent, move to the PCIe transport layer. Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c358
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c38
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debugfs.c42
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans-int-pcie.h6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans-rx-pcie.c396
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans.c40
7 files changed, 442 insertions, 442 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index ca6bb7b1c96d..f6884a54b7f8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -1308,364 +1308,6 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
1308 release_firmware(ucode_raw); 1308 release_firmware(ucode_raw);
1309} 1309}
1310 1310
1311static const char * const desc_lookup_text[] = {
1312 "OK",
1313 "FAIL",
1314 "BAD_PARAM",
1315 "BAD_CHECKSUM",
1316 "NMI_INTERRUPT_WDG",
1317 "SYSASSERT",
1318 "FATAL_ERROR",
1319 "BAD_COMMAND",
1320 "HW_ERROR_TUNE_LOCK",
1321 "HW_ERROR_TEMPERATURE",
1322 "ILLEGAL_CHAN_FREQ",
1323 "VCC_NOT_STABLE",
1324 "FH_ERROR",
1325 "NMI_INTERRUPT_HOST",
1326 "NMI_INTERRUPT_ACTION_PT",
1327 "NMI_INTERRUPT_UNKNOWN",
1328 "UCODE_VERSION_MISMATCH",
1329 "HW_ERROR_ABS_LOCK",
1330 "HW_ERROR_CAL_LOCK_FAIL",
1331 "NMI_INTERRUPT_INST_ACTION_PT",
1332 "NMI_INTERRUPT_DATA_ACTION_PT",
1333 "NMI_TRM_HW_ER",
1334 "NMI_INTERRUPT_TRM",
1335 "NMI_INTERRUPT_BREAK_POINT",
1336 "DEBUG_0",
1337 "DEBUG_1",
1338 "DEBUG_2",
1339 "DEBUG_3",
1340};
1341
1342static struct { char *name; u8 num; } advanced_lookup[] = {
1343 { "NMI_INTERRUPT_WDG", 0x34 },
1344 { "SYSASSERT", 0x35 },
1345 { "UCODE_VERSION_MISMATCH", 0x37 },
1346 { "BAD_COMMAND", 0x38 },
1347 { "NMI_INTERRUPT_DATA_ACTION_PT", 0x3C },
1348 { "FATAL_ERROR", 0x3D },
1349 { "NMI_TRM_HW_ERR", 0x46 },
1350 { "NMI_INTERRUPT_TRM", 0x4C },
1351 { "NMI_INTERRUPT_BREAK_POINT", 0x54 },
1352 { "NMI_INTERRUPT_WDG_RXF_FULL", 0x5C },
1353 { "NMI_INTERRUPT_WDG_NO_RBD_RXF_FULL", 0x64 },
1354 { "NMI_INTERRUPT_HOST", 0x66 },
1355 { "NMI_INTERRUPT_ACTION_PT", 0x7C },
1356 { "NMI_INTERRUPT_UNKNOWN", 0x84 },
1357 { "NMI_INTERRUPT_INST_ACTION_PT", 0x86 },
1358 { "ADVANCED_SYSASSERT", 0 },
1359};
1360
1361static const char *desc_lookup(u32 num)
1362{
1363 int i;
1364 int max = ARRAY_SIZE(desc_lookup_text);
1365
1366 if (num < max)
1367 return desc_lookup_text[num];
1368
1369 max = ARRAY_SIZE(advanced_lookup) - 1;
1370 for (i = 0; i < max; i++) {
1371 if (advanced_lookup[i].num == num)
1372 break;
1373 }
1374 return advanced_lookup[i].name;
1375}
1376
1377#define ERROR_START_OFFSET (1 * sizeof(u32))
1378#define ERROR_ELEM_SIZE (7 * sizeof(u32))
1379
1380void iwl_dump_nic_error_log(struct iwl_priv *priv)
1381{
1382 u32 base;
1383 struct iwl_error_event_table table;
1384
1385 base = priv->device_pointers.error_event_table;
1386 if (priv->ucode_type == IWL_UCODE_INIT) {
1387 if (!base)
1388 base = priv->init_errlog_ptr;
1389 } else {
1390 if (!base)
1391 base = priv->inst_errlog_ptr;
1392 }
1393
1394 if (!iwlagn_hw_valid_rtc_data_addr(base)) {
1395 IWL_ERR(priv,
1396 "Not valid error log pointer 0x%08X for %s uCode\n",
1397 base,
1398 (priv->ucode_type == IWL_UCODE_INIT)
1399 ? "Init" : "RT");
1400 return;
1401 }
1402
1403 iwl_read_targ_mem_words(priv, base, &table, sizeof(table));
1404
1405 if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
1406 IWL_ERR(priv, "Start IWL Error Log Dump:\n");
1407 IWL_ERR(priv, "Status: 0x%08lX, count: %d\n",
1408 priv->shrd->status, table.valid);
1409 }
1410
1411 priv->isr_stats.err_code = table.error_id;
1412
1413 trace_iwlwifi_dev_ucode_error(priv, table.error_id, table.tsf_low,
1414 table.data1, table.data2, table.line,
1415 table.blink1, table.blink2, table.ilink1,
1416 table.ilink2, table.bcon_time, table.gp1,
1417 table.gp2, table.gp3, table.ucode_ver,
1418 table.hw_ver, table.brd_ver);
1419 IWL_ERR(priv, "0x%08X | %-28s\n", table.error_id,
1420 desc_lookup(table.error_id));
1421 IWL_ERR(priv, "0x%08X | uPc\n", table.pc);
1422 IWL_ERR(priv, "0x%08X | branchlink1\n", table.blink1);
1423 IWL_ERR(priv, "0x%08X | branchlink2\n", table.blink2);
1424 IWL_ERR(priv, "0x%08X | interruptlink1\n", table.ilink1);
1425 IWL_ERR(priv, "0x%08X | interruptlink2\n", table.ilink2);
1426 IWL_ERR(priv, "0x%08X | data1\n", table.data1);
1427 IWL_ERR(priv, "0x%08X | data2\n", table.data2);
1428 IWL_ERR(priv, "0x%08X | line\n", table.line);
1429 IWL_ERR(priv, "0x%08X | beacon time\n", table.bcon_time);
1430 IWL_ERR(priv, "0x%08X | tsf low\n", table.tsf_low);
1431 IWL_ERR(priv, "0x%08X | tsf hi\n", table.tsf_hi);
1432 IWL_ERR(priv, "0x%08X | time gp1\n", table.gp1);
1433 IWL_ERR(priv, "0x%08X | time gp2\n", table.gp2);
1434 IWL_ERR(priv, "0x%08X | time gp3\n", table.gp3);
1435 IWL_ERR(priv, "0x%08X | uCode version\n", table.ucode_ver);
1436 IWL_ERR(priv, "0x%08X | hw version\n", table.hw_ver);
1437 IWL_ERR(priv, "0x%08X | board version\n", table.brd_ver);
1438 IWL_ERR(priv, "0x%08X | hcmd\n", table.hcmd);
1439}
1440
1441#define EVENT_START_OFFSET (4 * sizeof(u32))
1442
1443/**
1444 * iwl_print_event_log - Dump error event log to syslog
1445 *
1446 */
1447static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
1448 u32 num_events, u32 mode,
1449 int pos, char **buf, size_t bufsz)
1450{
1451 u32 i;
1452 u32 base; /* SRAM byte address of event log header */
1453 u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */
1454 u32 ptr; /* SRAM byte address of log data */
1455 u32 ev, time, data; /* event log data */
1456 unsigned long reg_flags;
1457
1458 if (num_events == 0)
1459 return pos;
1460
1461 base = priv->device_pointers.log_event_table;
1462 if (priv->ucode_type == IWL_UCODE_INIT) {
1463 if (!base)
1464 base = priv->init_evtlog_ptr;
1465 } else {
1466 if (!base)
1467 base = priv->inst_evtlog_ptr;
1468 }
1469
1470 if (mode == 0)
1471 event_size = 2 * sizeof(u32);
1472 else
1473 event_size = 3 * sizeof(u32);
1474
1475 ptr = base + EVENT_START_OFFSET + (start_idx * event_size);
1476
1477 /* Make sure device is powered up for SRAM reads */
1478 spin_lock_irqsave(&priv->reg_lock, reg_flags);
1479 iwl_grab_nic_access(priv);
1480
1481 /* Set starting address; reads will auto-increment */
1482 iwl_write32(priv, HBUS_TARG_MEM_RADDR, ptr);
1483 rmb();
1484
1485 /* "time" is actually "data" for mode 0 (no timestamp).
1486 * place event id # at far right for easier visual parsing. */
1487 for (i = 0; i < num_events; i++) {
1488 ev = iwl_read32(priv, HBUS_TARG_MEM_RDAT);
1489 time = iwl_read32(priv, HBUS_TARG_MEM_RDAT);
1490 if (mode == 0) {
1491 /* data, ev */
1492 if (bufsz) {
1493 pos += scnprintf(*buf + pos, bufsz - pos,
1494 "EVT_LOG:0x%08x:%04u\n",
1495 time, ev);
1496 } else {
1497 trace_iwlwifi_dev_ucode_event(priv, 0,
1498 time, ev);
1499 IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n",
1500 time, ev);
1501 }
1502 } else {
1503 data = iwl_read32(priv, HBUS_TARG_MEM_RDAT);
1504 if (bufsz) {
1505 pos += scnprintf(*buf + pos, bufsz - pos,
1506 "EVT_LOGT:%010u:0x%08x:%04u\n",
1507 time, data, ev);
1508 } else {
1509 IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n",
1510 time, data, ev);
1511 trace_iwlwifi_dev_ucode_event(priv, time,
1512 data, ev);
1513 }
1514 }
1515 }
1516
1517 /* Allow device to power down */
1518 iwl_release_nic_access(priv);
1519 spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
1520 return pos;
1521}
1522
1523/**
1524 * iwl_print_last_event_logs - Dump the newest # of event log to syslog
1525 */
1526static int iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
1527 u32 num_wraps, u32 next_entry,
1528 u32 size, u32 mode,
1529 int pos, char **buf, size_t bufsz)
1530{
1531 /*
1532 * display the newest DEFAULT_LOG_ENTRIES entries
1533 * i.e the entries just before the next ont that uCode would fill.
1534 */
1535 if (num_wraps) {
1536 if (next_entry < size) {
1537 pos = iwl_print_event_log(priv,
1538 capacity - (size - next_entry),
1539 size - next_entry, mode,
1540 pos, buf, bufsz);
1541 pos = iwl_print_event_log(priv, 0,
1542 next_entry, mode,
1543 pos, buf, bufsz);
1544 } else
1545 pos = iwl_print_event_log(priv, next_entry - size,
1546 size, mode, pos, buf, bufsz);
1547 } else {
1548 if (next_entry < size) {
1549 pos = iwl_print_event_log(priv, 0, next_entry,
1550 mode, pos, buf, bufsz);
1551 } else {
1552 pos = iwl_print_event_log(priv, next_entry - size,
1553 size, mode, pos, buf, bufsz);
1554 }
1555 }
1556 return pos;
1557}
1558
1559#define DEFAULT_DUMP_EVENT_LOG_ENTRIES (20)
1560
1561int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
1562 char **buf, bool display)
1563{
1564 u32 base; /* SRAM byte address of event log header */
1565 u32 capacity; /* event log capacity in # entries */
1566 u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */
1567 u32 num_wraps; /* # times uCode wrapped to top of log */
1568 u32 next_entry; /* index of next entry to be written by uCode */
1569 u32 size; /* # entries that we'll print */
1570 u32 logsize;
1571 int pos = 0;
1572 size_t bufsz = 0;
1573
1574 base = priv->device_pointers.log_event_table;
1575 if (priv->ucode_type == IWL_UCODE_INIT) {
1576 logsize = priv->init_evtlog_size;
1577 if (!base)
1578 base = priv->init_evtlog_ptr;
1579 } else {
1580 logsize = priv->inst_evtlog_size;
1581 if (!base)
1582 base = priv->inst_evtlog_ptr;
1583 }
1584
1585 if (!iwlagn_hw_valid_rtc_data_addr(base)) {
1586 IWL_ERR(priv,
1587 "Invalid event log pointer 0x%08X for %s uCode\n",
1588 base,
1589 (priv->ucode_type == IWL_UCODE_INIT)
1590 ? "Init" : "RT");
1591 return -EINVAL;
1592 }
1593
1594 /* event log header */
1595 capacity = iwl_read_targ_mem(priv, base);
1596 mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32)));
1597 num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
1598 next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32)));
1599
1600 if (capacity > logsize) {
1601 IWL_ERR(priv, "Log capacity %d is bogus, limit to %d entries\n",
1602 capacity, logsize);
1603 capacity = logsize;
1604 }
1605
1606 if (next_entry > logsize) {
1607 IWL_ERR(priv, "Log write index %d is bogus, limit to %d\n",
1608 next_entry, logsize);
1609 next_entry = logsize;
1610 }
1611
1612 size = num_wraps ? capacity : next_entry;
1613
1614 /* bail out if nothing in log */
1615 if (size == 0) {
1616 IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n");
1617 return pos;
1618 }
1619
1620 /* enable/disable bt channel inhibition */
1621 priv->bt_ch_announce = iwlagn_mod_params.bt_ch_announce;
1622
1623#ifdef CONFIG_IWLWIFI_DEBUG
1624 if (!(iwl_get_debug_level(priv->shrd) & IWL_DL_FW_ERRORS) && !full_log)
1625 size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES)
1626 ? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size;
1627#else
1628 size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES)
1629 ? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size;
1630#endif
1631 IWL_ERR(priv, "Start IWL Event Log Dump: display last %u entries\n",
1632 size);
1633
1634#ifdef CONFIG_IWLWIFI_DEBUG
1635 if (display) {
1636 if (full_log)
1637 bufsz = capacity * 48;
1638 else
1639 bufsz = size * 48;
1640 *buf = kmalloc(bufsz, GFP_KERNEL);
1641 if (!*buf)
1642 return -ENOMEM;
1643 }
1644 if ((iwl_get_debug_level(priv->shrd) & IWL_DL_FW_ERRORS) || full_log) {
1645 /*
1646 * if uCode has wrapped back to top of log,
1647 * start at the oldest entry,
1648 * i.e the next one that uCode would fill.
1649 */
1650 if (num_wraps)
1651 pos = iwl_print_event_log(priv, next_entry,
1652 capacity - next_entry, mode,
1653 pos, buf, bufsz);
1654 /* (then/else) start at top of log */
1655 pos = iwl_print_event_log(priv, 0,
1656 next_entry, mode, pos, buf, bufsz);
1657 } else
1658 pos = iwl_print_last_event_logs(priv, capacity, num_wraps,
1659 next_entry, size, mode,
1660 pos, buf, bufsz);
1661#else
1662 pos = iwl_print_last_event_logs(priv, capacity, num_wraps,
1663 next_entry, size, mode,
1664 pos, buf, bufsz);
1665#endif
1666 return pos;
1667}
1668
1669static void iwl_rf_kill_ct_config(struct iwl_priv *priv) 1311static void iwl_rf_kill_ct_config(struct iwl_priv *priv)
1670{ 1312{
1671 struct iwl_ct_kill_config cmd; 1313 struct iwl_ct_kill_config cmd;
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index d77af6969a5b..88fc39619214 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -902,44 +902,6 @@ void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand)
902 } 902 }
903} 903}
904 904
905/**
906 * iwl_irq_handle_error - called for HW or SW error interrupt from card
907 */
908void iwl_irq_handle_error(struct iwl_priv *priv)
909{
910 /* W/A for WiFi/WiMAX coex and WiMAX own the RF */
911 if (priv->cfg->internal_wimax_coex &&
912 (!(iwl_read_prph(priv, APMG_CLK_CTRL_REG) &
913 APMS_CLK_VAL_MRB_FUNC_MODE) ||
914 (iwl_read_prph(priv, APMG_PS_CTRL_REG) &
915 APMG_PS_CTRL_VAL_RESET_REQ))) {
916 /*
917 * Keep the restart process from trying to send host
918 * commands by clearing the ready bit.
919 */
920 clear_bit(STATUS_READY, &priv->shrd->status);
921 clear_bit(STATUS_HCMD_ACTIVE, &priv->shrd->status);
922 wake_up_interruptible(&priv->wait_command_queue);
923 IWL_ERR(priv, "RF is used by WiMAX\n");
924 return;
925 }
926
927 IWL_ERR(priv, "Loaded firmware version: %s\n",
928 priv->hw->wiphy->fw_version);
929
930 iwl_dump_nic_error_log(priv);
931 iwl_dump_csr(priv);
932 iwl_dump_fh(priv, NULL, false);
933 iwl_dump_nic_event_log(priv, false, NULL, false);
934#ifdef CONFIG_IWLWIFI_DEBUG
935 if (iwl_get_debug_level(priv->shrd) & IWL_DL_FW_ERRORS)
936 iwl_print_rx_config_cmd(priv,
937 &priv->contexts[IWL_RXON_CTX_BSS]);
938#endif
939
940 iwlagn_fw_error(priv, false);
941}
942
943static int iwl_apm_stop_master(struct iwl_priv *priv) 905static int iwl_apm_stop_master(struct iwl_priv *priv)
944{ 906{
945 int ret = 0; 907 int ret = 0;
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 797fefa1bf2a..aa6211837b48 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -266,7 +266,6 @@ bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
266void iwl_connection_init_rx_config(struct iwl_priv *priv, 266void iwl_connection_init_rx_config(struct iwl_priv *priv,
267 struct iwl_rxon_context *ctx); 267 struct iwl_rxon_context *ctx);
268void iwl_set_rate(struct iwl_priv *priv); 268void iwl_set_rate(struct iwl_priv *priv);
269void iwl_irq_handle_error(struct iwl_priv *priv);
270int iwl_mac_add_interface(struct ieee80211_hw *hw, 269int iwl_mac_add_interface(struct ieee80211_hw *hw,
271 struct ieee80211_vif *vif); 270 struct ieee80211_vif *vif);
272void iwl_mac_remove_interface(struct ieee80211_hw *hw, 271void iwl_mac_remove_interface(struct ieee80211_hw *hw,
@@ -376,9 +375,6 @@ __le32 iwl_add_beacon_time(struct iwl_priv *priv, u32 base,
376/***************************************************** 375/*****************************************************
377* Error Handling Debugging 376* Error Handling Debugging
378******************************************************/ 377******************************************************/
379void iwl_dump_nic_error_log(struct iwl_priv *priv);
380int iwl_dump_nic_event_log(struct iwl_priv *priv,
381 bool full_log, char **buf, bool display);
382void iwl_dump_csr(struct iwl_priv *priv); 378void iwl_dump_csr(struct iwl_priv *priv);
383int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display); 379int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display);
384#ifdef CONFIG_IWLWIFI_DEBUG 380#ifdef CONFIG_IWLWIFI_DEBUG
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index d3223214a801..fa070de2840c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -442,46 +442,6 @@ static ssize_t iwl_dbgfs_nvm_read(struct file *file,
442 return ret; 442 return ret;
443} 443}
444 444
445static ssize_t iwl_dbgfs_log_event_read(struct file *file,
446 char __user *user_buf,
447 size_t count, loff_t *ppos)
448{
449 struct iwl_priv *priv = file->private_data;
450 char *buf;
451 int pos = 0;
452 ssize_t ret = -ENOMEM;
453
454 ret = pos = iwl_dump_nic_event_log(priv, true, &buf, true);
455 if (buf) {
456 ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
457 kfree(buf);
458 }
459 return ret;
460}
461
462static ssize_t iwl_dbgfs_log_event_write(struct file *file,
463 const char __user *user_buf,
464 size_t count, loff_t *ppos)
465{
466 struct iwl_priv *priv = file->private_data;
467 u32 event_log_flag;
468 char buf[8];
469 int buf_size;
470
471 memset(buf, 0, sizeof(buf));
472 buf_size = min(count, sizeof(buf) - 1);
473 if (copy_from_user(buf, user_buf, buf_size))
474 return -EFAULT;
475 if (sscanf(buf, "%d", &event_log_flag) != 1)
476 return -EFAULT;
477 if (event_log_flag == 1)
478 iwl_dump_nic_event_log(priv, true, NULL, false);
479
480 return count;
481}
482
483
484
485static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf, 445static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf,
486 size_t count, loff_t *ppos) 446 size_t count, loff_t *ppos)
487{ 447{
@@ -870,7 +830,6 @@ static ssize_t iwl_dbgfs_current_sleep_command_read(struct file *file,
870 830
871DEBUGFS_READ_WRITE_FILE_OPS(sram); 831DEBUGFS_READ_WRITE_FILE_OPS(sram);
872DEBUGFS_READ_FILE_OPS(wowlan_sram); 832DEBUGFS_READ_FILE_OPS(wowlan_sram);
873DEBUGFS_READ_WRITE_FILE_OPS(log_event);
874DEBUGFS_READ_FILE_OPS(nvm); 833DEBUGFS_READ_FILE_OPS(nvm);
875DEBUGFS_READ_FILE_OPS(stations); 834DEBUGFS_READ_FILE_OPS(stations);
876DEBUGFS_READ_FILE_OPS(channels); 835DEBUGFS_READ_FILE_OPS(channels);
@@ -2509,7 +2468,6 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
2509 DEBUGFS_ADD_FILE(nvm, dir_data, S_IRUSR); 2468 DEBUGFS_ADD_FILE(nvm, dir_data, S_IRUSR);
2510 DEBUGFS_ADD_FILE(sram, dir_data, S_IWUSR | S_IRUSR); 2469 DEBUGFS_ADD_FILE(sram, dir_data, S_IWUSR | S_IRUSR);
2511 DEBUGFS_ADD_FILE(wowlan_sram, dir_data, S_IRUSR); 2470 DEBUGFS_ADD_FILE(wowlan_sram, dir_data, S_IRUSR);
2512 DEBUGFS_ADD_FILE(log_event, dir_data, S_IWUSR | S_IRUSR);
2513 DEBUGFS_ADD_FILE(stations, dir_data, S_IRUSR); 2471 DEBUGFS_ADD_FILE(stations, dir_data, S_IRUSR);
2514 DEBUGFS_ADD_FILE(channels, dir_data, S_IRUSR); 2472 DEBUGFS_ADD_FILE(channels, dir_data, S_IRUSR);
2515 DEBUGFS_ADD_FILE(status, dir_data, S_IRUSR); 2473 DEBUGFS_ADD_FILE(status, dir_data, S_IRUSR);
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-int-pcie.h b/drivers/net/wireless/iwlwifi/iwl-trans-int-pcie.h
index 7e2f954c95f2..4694c462ed4e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans-int-pcie.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-int-pcie.h
@@ -141,6 +141,12 @@ void iwl_trans_tx_queue_set_status(struct iwl_priv *priv,
141void iwl_trans_pcie_txq_agg_setup(struct iwl_priv *priv, int sta_id, int tid, 141void iwl_trans_pcie_txq_agg_setup(struct iwl_priv *priv, int sta_id, int tid,
142 int frame_limit); 142 int frame_limit);
143 143
144/*****************************************************
145* Error handling
146******************************************************/
147int iwl_dump_nic_event_log(struct iwl_priv *priv,
148 bool full_log, char **buf, bool display);
149
144static inline void iwl_disable_interrupts(struct iwl_trans *trans) 150static inline void iwl_disable_interrupts(struct iwl_trans *trans)
145{ 151{
146 clear_bit(STATUS_INT_ENABLED, &trans->shrd->status); 152 clear_bit(STATUS_INT_ENABLED, &trans->shrd->status);
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-rx-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-rx-pcie.c
index 15e2645c2fb3..aa7ced4324b8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans-rx-pcie.c
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-rx-pcie.c
@@ -496,6 +496,402 @@ static void iwl_rx_handle(struct iwl_trans *trans)
496 iwlagn_rx_queue_restock(trans); 496 iwlagn_rx_queue_restock(trans);
497} 497}
498 498
499static const char * const desc_lookup_text[] = {
500 "OK",
501 "FAIL",
502 "BAD_PARAM",
503 "BAD_CHECKSUM",
504 "NMI_INTERRUPT_WDG",
505 "SYSASSERT",
506 "FATAL_ERROR",
507 "BAD_COMMAND",
508 "HW_ERROR_TUNE_LOCK",
509 "HW_ERROR_TEMPERATURE",
510 "ILLEGAL_CHAN_FREQ",
511 "VCC_NOT_STABLE",
512 "FH_ERROR",
513 "NMI_INTERRUPT_HOST",
514 "NMI_INTERRUPT_ACTION_PT",
515 "NMI_INTERRUPT_UNKNOWN",
516 "UCODE_VERSION_MISMATCH",
517 "HW_ERROR_ABS_LOCK",
518 "HW_ERROR_CAL_LOCK_FAIL",
519 "NMI_INTERRUPT_INST_ACTION_PT",
520 "NMI_INTERRUPT_DATA_ACTION_PT",
521 "NMI_TRM_HW_ER",
522 "NMI_INTERRUPT_TRM",
523 "NMI_INTERRUPT_BREAK_POINT",
524 "DEBUG_0",
525 "DEBUG_1",
526 "DEBUG_2",
527 "DEBUG_3",
528};
529
530static struct { char *name; u8 num; } advanced_lookup[] = {
531 { "NMI_INTERRUPT_WDG", 0x34 },
532 { "SYSASSERT", 0x35 },
533 { "UCODE_VERSION_MISMATCH", 0x37 },
534 { "BAD_COMMAND", 0x38 },
535 { "NMI_INTERRUPT_DATA_ACTION_PT", 0x3C },
536 { "FATAL_ERROR", 0x3D },
537 { "NMI_TRM_HW_ERR", 0x46 },
538 { "NMI_INTERRUPT_TRM", 0x4C },
539 { "NMI_INTERRUPT_BREAK_POINT", 0x54 },
540 { "NMI_INTERRUPT_WDG_RXF_FULL", 0x5C },
541 { "NMI_INTERRUPT_WDG_NO_RBD_RXF_FULL", 0x64 },
542 { "NMI_INTERRUPT_HOST", 0x66 },
543 { "NMI_INTERRUPT_ACTION_PT", 0x7C },
544 { "NMI_INTERRUPT_UNKNOWN", 0x84 },
545 { "NMI_INTERRUPT_INST_ACTION_PT", 0x86 },
546 { "ADVANCED_SYSASSERT", 0 },
547};
548
549static const char *desc_lookup(u32 num)
550{
551 int i;
552 int max = ARRAY_SIZE(desc_lookup_text);
553
554 if (num < max)
555 return desc_lookup_text[num];
556
557 max = ARRAY_SIZE(advanced_lookup) - 1;
558 for (i = 0; i < max; i++) {
559 if (advanced_lookup[i].num == num)
560 break;
561 }
562 return advanced_lookup[i].name;
563}
564
565#define ERROR_START_OFFSET (1 * sizeof(u32))
566#define ERROR_ELEM_SIZE (7 * sizeof(u32))
567
568static void iwl_dump_nic_error_log(struct iwl_priv *priv)
569{
570 u32 base;
571 struct iwl_error_event_table table;
572
573 base = priv->device_pointers.error_event_table;
574 if (priv->ucode_type == IWL_UCODE_INIT) {
575 if (!base)
576 base = priv->init_errlog_ptr;
577 } else {
578 if (!base)
579 base = priv->inst_errlog_ptr;
580 }
581
582 if (!iwlagn_hw_valid_rtc_data_addr(base)) {
583 IWL_ERR(priv,
584 "Not valid error log pointer 0x%08X for %s uCode\n",
585 base,
586 (priv->ucode_type == IWL_UCODE_INIT)
587 ? "Init" : "RT");
588 return;
589 }
590
591 iwl_read_targ_mem_words(priv, base, &table, sizeof(table));
592
593 if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
594 IWL_ERR(priv, "Start IWL Error Log Dump:\n");
595 IWL_ERR(priv, "Status: 0x%08lX, count: %d\n",
596 priv->shrd->status, table.valid);
597 }
598
599 priv->isr_stats.err_code = table.error_id;
600
601 trace_iwlwifi_dev_ucode_error(priv, table.error_id, table.tsf_low,
602 table.data1, table.data2, table.line,
603 table.blink1, table.blink2, table.ilink1,
604 table.ilink2, table.bcon_time, table.gp1,
605 table.gp2, table.gp3, table.ucode_ver,
606 table.hw_ver, table.brd_ver);
607 IWL_ERR(priv, "0x%08X | %-28s\n", table.error_id,
608 desc_lookup(table.error_id));
609 IWL_ERR(priv, "0x%08X | uPc\n", table.pc);
610 IWL_ERR(priv, "0x%08X | branchlink1\n", table.blink1);
611 IWL_ERR(priv, "0x%08X | branchlink2\n", table.blink2);
612 IWL_ERR(priv, "0x%08X | interruptlink1\n", table.ilink1);
613 IWL_ERR(priv, "0x%08X | interruptlink2\n", table.ilink2);
614 IWL_ERR(priv, "0x%08X | data1\n", table.data1);
615 IWL_ERR(priv, "0x%08X | data2\n", table.data2);
616 IWL_ERR(priv, "0x%08X | line\n", table.line);
617 IWL_ERR(priv, "0x%08X | beacon time\n", table.bcon_time);
618 IWL_ERR(priv, "0x%08X | tsf low\n", table.tsf_low);
619 IWL_ERR(priv, "0x%08X | tsf hi\n", table.tsf_hi);
620 IWL_ERR(priv, "0x%08X | time gp1\n", table.gp1);
621 IWL_ERR(priv, "0x%08X | time gp2\n", table.gp2);
622 IWL_ERR(priv, "0x%08X | time gp3\n", table.gp3);
623 IWL_ERR(priv, "0x%08X | uCode version\n", table.ucode_ver);
624 IWL_ERR(priv, "0x%08X | hw version\n", table.hw_ver);
625 IWL_ERR(priv, "0x%08X | board version\n", table.brd_ver);
626 IWL_ERR(priv, "0x%08X | hcmd\n", table.hcmd);
627}
628
629/**
630 * iwl_irq_handle_error - called for HW or SW error interrupt from card
631 */
632static void iwl_irq_handle_error(struct iwl_priv *priv)
633{
634 /* W/A for WiFi/WiMAX coex and WiMAX own the RF */
635 if (priv->cfg->internal_wimax_coex &&
636 (!(iwl_read_prph(priv, APMG_CLK_CTRL_REG) &
637 APMS_CLK_VAL_MRB_FUNC_MODE) ||
638 (iwl_read_prph(priv, APMG_PS_CTRL_REG) &
639 APMG_PS_CTRL_VAL_RESET_REQ))) {
640 /*
641 * Keep the restart process from trying to send host
642 * commands by clearing the ready bit.
643 */
644 clear_bit(STATUS_READY, &priv->shrd->status);
645 clear_bit(STATUS_HCMD_ACTIVE, &priv->shrd->status);
646 wake_up_interruptible(&priv->wait_command_queue);
647 IWL_ERR(priv, "RF is used by WiMAX\n");
648 return;
649 }
650
651 IWL_ERR(priv, "Loaded firmware version: %s\n",
652 priv->hw->wiphy->fw_version);
653
654 iwl_dump_nic_error_log(priv);
655 iwl_dump_csr(priv);
656 iwl_dump_fh(priv, NULL, false);
657 iwl_dump_nic_event_log(priv, false, NULL, false);
658#ifdef CONFIG_IWLWIFI_DEBUG
659 if (iwl_get_debug_level(priv->shrd) & IWL_DL_FW_ERRORS)
660 iwl_print_rx_config_cmd(priv,
661 &priv->contexts[IWL_RXON_CTX_BSS]);
662#endif
663
664 iwlagn_fw_error(priv, false);
665}
666
667#define EVENT_START_OFFSET (4 * sizeof(u32))
668
669/**
670 * iwl_print_event_log - Dump error event log to syslog
671 *
672 */
673static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
674 u32 num_events, u32 mode,
675 int pos, char **buf, size_t bufsz)
676{
677 u32 i;
678 u32 base; /* SRAM byte address of event log header */
679 u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */
680 u32 ptr; /* SRAM byte address of log data */
681 u32 ev, time, data; /* event log data */
682 unsigned long reg_flags;
683
684 if (num_events == 0)
685 return pos;
686
687 base = priv->device_pointers.log_event_table;
688 if (priv->ucode_type == IWL_UCODE_INIT) {
689 if (!base)
690 base = priv->init_evtlog_ptr;
691 } else {
692 if (!base)
693 base = priv->inst_evtlog_ptr;
694 }
695
696 if (mode == 0)
697 event_size = 2 * sizeof(u32);
698 else
699 event_size = 3 * sizeof(u32);
700
701 ptr = base + EVENT_START_OFFSET + (start_idx * event_size);
702
703 /* Make sure device is powered up for SRAM reads */
704 spin_lock_irqsave(&priv->reg_lock, reg_flags);
705 iwl_grab_nic_access(priv);
706
707 /* Set starting address; reads will auto-increment */
708 iwl_write32(priv, HBUS_TARG_MEM_RADDR, ptr);
709 rmb();
710
711 /* "time" is actually "data" for mode 0 (no timestamp).
712 * place event id # at far right for easier visual parsing. */
713 for (i = 0; i < num_events; i++) {
714 ev = iwl_read32(priv, HBUS_TARG_MEM_RDAT);
715 time = iwl_read32(priv, HBUS_TARG_MEM_RDAT);
716 if (mode == 0) {
717 /* data, ev */
718 if (bufsz) {
719 pos += scnprintf(*buf + pos, bufsz - pos,
720 "EVT_LOG:0x%08x:%04u\n",
721 time, ev);
722 } else {
723 trace_iwlwifi_dev_ucode_event(priv, 0,
724 time, ev);
725 IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n",
726 time, ev);
727 }
728 } else {
729 data = iwl_read32(priv, HBUS_TARG_MEM_RDAT);
730 if (bufsz) {
731 pos += scnprintf(*buf + pos, bufsz - pos,
732 "EVT_LOGT:%010u:0x%08x:%04u\n",
733 time, data, ev);
734 } else {
735 IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n",
736 time, data, ev);
737 trace_iwlwifi_dev_ucode_event(priv, time,
738 data, ev);
739 }
740 }
741 }
742
743 /* Allow device to power down */
744 iwl_release_nic_access(priv);
745 spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
746 return pos;
747}
748
749/**
750 * iwl_print_last_event_logs - Dump the newest # of event log to syslog
751 */
752static int iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
753 u32 num_wraps, u32 next_entry,
754 u32 size, u32 mode,
755 int pos, char **buf, size_t bufsz)
756{
757 /*
758 * display the newest DEFAULT_LOG_ENTRIES entries
759 * i.e the entries just before the next ont that uCode would fill.
760 */
761 if (num_wraps) {
762 if (next_entry < size) {
763 pos = iwl_print_event_log(priv,
764 capacity - (size - next_entry),
765 size - next_entry, mode,
766 pos, buf, bufsz);
767 pos = iwl_print_event_log(priv, 0,
768 next_entry, mode,
769 pos, buf, bufsz);
770 } else
771 pos = iwl_print_event_log(priv, next_entry - size,
772 size, mode, pos, buf, bufsz);
773 } else {
774 if (next_entry < size) {
775 pos = iwl_print_event_log(priv, 0, next_entry,
776 mode, pos, buf, bufsz);
777 } else {
778 pos = iwl_print_event_log(priv, next_entry - size,
779 size, mode, pos, buf, bufsz);
780 }
781 }
782 return pos;
783}
784
785#define DEFAULT_DUMP_EVENT_LOG_ENTRIES (20)
786
787int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
788 char **buf, bool display)
789{
790 u32 base; /* SRAM byte address of event log header */
791 u32 capacity; /* event log capacity in # entries */
792 u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */
793 u32 num_wraps; /* # times uCode wrapped to top of log */
794 u32 next_entry; /* index of next entry to be written by uCode */
795 u32 size; /* # entries that we'll print */
796 u32 logsize;
797 int pos = 0;
798 size_t bufsz = 0;
799
800 base = priv->device_pointers.log_event_table;
801 if (priv->ucode_type == IWL_UCODE_INIT) {
802 logsize = priv->init_evtlog_size;
803 if (!base)
804 base = priv->init_evtlog_ptr;
805 } else {
806 logsize = priv->inst_evtlog_size;
807 if (!base)
808 base = priv->inst_evtlog_ptr;
809 }
810
811 if (!iwlagn_hw_valid_rtc_data_addr(base)) {
812 IWL_ERR(priv,
813 "Invalid event log pointer 0x%08X for %s uCode\n",
814 base,
815 (priv->ucode_type == IWL_UCODE_INIT)
816 ? "Init" : "RT");
817 return -EINVAL;
818 }
819
820 /* event log header */
821 capacity = iwl_read_targ_mem(priv, base);
822 mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32)));
823 num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
824 next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32)));
825
826 if (capacity > logsize) {
827 IWL_ERR(priv, "Log capacity %d is bogus, limit to %d entries\n",
828 capacity, logsize);
829 capacity = logsize;
830 }
831
832 if (next_entry > logsize) {
833 IWL_ERR(priv, "Log write index %d is bogus, limit to %d\n",
834 next_entry, logsize);
835 next_entry = logsize;
836 }
837
838 size = num_wraps ? capacity : next_entry;
839
840 /* bail out if nothing in log */
841 if (size == 0) {
842 IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n");
843 return pos;
844 }
845
846 /* enable/disable bt channel inhibition */
847 priv->bt_ch_announce = iwlagn_mod_params.bt_ch_announce;
848
849#ifdef CONFIG_IWLWIFI_DEBUG
850 if (!(iwl_get_debug_level(priv->shrd) & IWL_DL_FW_ERRORS) && !full_log)
851 size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES)
852 ? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size;
853#else
854 size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES)
855 ? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size;
856#endif
857 IWL_ERR(priv, "Start IWL Event Log Dump: display last %u entries\n",
858 size);
859
860#ifdef CONFIG_IWLWIFI_DEBUG
861 if (display) {
862 if (full_log)
863 bufsz = capacity * 48;
864 else
865 bufsz = size * 48;
866 *buf = kmalloc(bufsz, GFP_KERNEL);
867 if (!*buf)
868 return -ENOMEM;
869 }
870 if ((iwl_get_debug_level(priv->shrd) & IWL_DL_FW_ERRORS) || full_log) {
871 /*
872 * if uCode has wrapped back to top of log,
873 * start at the oldest entry,
874 * i.e the next one that uCode would fill.
875 */
876 if (num_wraps)
877 pos = iwl_print_event_log(priv, next_entry,
878 capacity - next_entry, mode,
879 pos, buf, bufsz);
880 /* (then/else) start at top of log */
881 pos = iwl_print_event_log(priv, 0,
882 next_entry, mode, pos, buf, bufsz);
883 } else
884 pos = iwl_print_last_event_logs(priv, capacity, num_wraps,
885 next_entry, size, mode,
886 pos, buf, bufsz);
887#else
888 pos = iwl_print_last_event_logs(priv, capacity, num_wraps,
889 next_entry, size, mode,
890 pos, buf, bufsz);
891#endif
892 return pos;
893}
894
499/* tasklet for iwlagn interrupt */ 895/* tasklet for iwlagn interrupt */
500void iwl_irq_tasklet(struct iwl_trans *trans) 896void iwl_irq_tasklet(struct iwl_trans *trans)
501{ 897{
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.c b/drivers/net/wireless/iwlwifi/iwl-trans.c
index 687a09226e6d..5926cac711b3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.c
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.c
@@ -1458,7 +1458,46 @@ static ssize_t iwl_dbgfs_rx_queue_read(struct file *file,
1458 return simple_read_from_buffer(user_buf, count, ppos, buf, pos); 1458 return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1459} 1459}
1460 1460
1461static ssize_t iwl_dbgfs_log_event_read(struct file *file,
1462 char __user *user_buf,
1463 size_t count, loff_t *ppos)
1464{
1465 struct iwl_trans *trans = file->private_data;
1466 char *buf;
1467 int pos = 0;
1468 ssize_t ret = -ENOMEM;
1469
1470 ret = pos = iwl_dump_nic_event_log(priv(trans), true, &buf, true);
1471 if (buf) {
1472 ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1473 kfree(buf);
1474 }
1475 return ret;
1476}
1477
1478static ssize_t iwl_dbgfs_log_event_write(struct file *file,
1479 const char __user *user_buf,
1480 size_t count, loff_t *ppos)
1481{
1482 struct iwl_trans *trans = file->private_data;
1483 u32 event_log_flag;
1484 char buf[8];
1485 int buf_size;
1486
1487 memset(buf, 0, sizeof(buf));
1488 buf_size = min(count, sizeof(buf) - 1);
1489 if (copy_from_user(buf, user_buf, buf_size))
1490 return -EFAULT;
1491 if (sscanf(buf, "%d", &event_log_flag) != 1)
1492 return -EFAULT;
1493 if (event_log_flag == 1)
1494 iwl_dump_nic_event_log(priv(trans), true, NULL, false);
1495
1496 return count;
1497}
1498
1461DEBUGFS_READ_WRITE_FILE_OPS(traffic_log); 1499DEBUGFS_READ_WRITE_FILE_OPS(traffic_log);
1500DEBUGFS_READ_WRITE_FILE_OPS(log_event);
1462DEBUGFS_READ_FILE_OPS(rx_queue); 1501DEBUGFS_READ_FILE_OPS(rx_queue);
1463DEBUGFS_READ_FILE_OPS(tx_queue); 1502DEBUGFS_READ_FILE_OPS(tx_queue);
1464 1503
@@ -1472,6 +1511,7 @@ static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
1472 DEBUGFS_ADD_FILE(traffic_log, dir, S_IWUSR | S_IRUSR); 1511 DEBUGFS_ADD_FILE(traffic_log, dir, S_IWUSR | S_IRUSR);
1473 DEBUGFS_ADD_FILE(rx_queue, dir, S_IRUSR); 1512 DEBUGFS_ADD_FILE(rx_queue, dir, S_IRUSR);
1474 DEBUGFS_ADD_FILE(tx_queue, dir, S_IRUSR); 1513 DEBUGFS_ADD_FILE(tx_queue, dir, S_IRUSR);
1514 DEBUGFS_ADD_FILE(log_event, dir, S_IWUSR | S_IRUSR);
1475 return 0; 1515 return 0;
1476} 1516}
1477#else 1517#else