diff options
author | Emmanuel Grumbach <emmanuel.grumbach@intel.com> | 2011-08-26 02:10:54 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-08-29 15:25:33 -0400 |
commit | 7ff94706a055f3e21710b08ffbe3979d7db615db (patch) | |
tree | 453cabac4b495e4ee8d7fe63a193435e90920883 | |
parent | 0c325769a394559941acda83e888a1d9b1ef8b7f (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.c | 358 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.c | 38 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.h | 4 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-debugfs.c | 42 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-trans-int-pcie.h | 6 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-trans-rx-pcie.c | 396 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-trans.c | 40 |
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 | ||
1311 | static 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 | |||
1342 | static 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 | |||
1361 | static 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 | |||
1380 | void 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 | */ | ||
1447 | static 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 | */ | ||
1526 | static 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 | |||
1561 | int 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 | |||
1669 | static void iwl_rf_kill_ct_config(struct iwl_priv *priv) | 1311 | static 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 | */ | ||
908 | void 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 | |||
943 | static int iwl_apm_stop_master(struct iwl_priv *priv) | 905 | static 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, | |||
266 | void iwl_connection_init_rx_config(struct iwl_priv *priv, | 266 | void iwl_connection_init_rx_config(struct iwl_priv *priv, |
267 | struct iwl_rxon_context *ctx); | 267 | struct iwl_rxon_context *ctx); |
268 | void iwl_set_rate(struct iwl_priv *priv); | 268 | void iwl_set_rate(struct iwl_priv *priv); |
269 | void iwl_irq_handle_error(struct iwl_priv *priv); | ||
270 | int iwl_mac_add_interface(struct ieee80211_hw *hw, | 269 | int iwl_mac_add_interface(struct ieee80211_hw *hw, |
271 | struct ieee80211_vif *vif); | 270 | struct ieee80211_vif *vif); |
272 | void iwl_mac_remove_interface(struct ieee80211_hw *hw, | 271 | void 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 | ******************************************************/ |
379 | void iwl_dump_nic_error_log(struct iwl_priv *priv); | ||
380 | int iwl_dump_nic_event_log(struct iwl_priv *priv, | ||
381 | bool full_log, char **buf, bool display); | ||
382 | void iwl_dump_csr(struct iwl_priv *priv); | 378 | void iwl_dump_csr(struct iwl_priv *priv); |
383 | int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display); | 379 | int 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 | ||
445 | static 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 | |||
462 | static 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 | |||
485 | static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf, | 445 | static 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 | ||
871 | DEBUGFS_READ_WRITE_FILE_OPS(sram); | 831 | DEBUGFS_READ_WRITE_FILE_OPS(sram); |
872 | DEBUGFS_READ_FILE_OPS(wowlan_sram); | 832 | DEBUGFS_READ_FILE_OPS(wowlan_sram); |
873 | DEBUGFS_READ_WRITE_FILE_OPS(log_event); | ||
874 | DEBUGFS_READ_FILE_OPS(nvm); | 833 | DEBUGFS_READ_FILE_OPS(nvm); |
875 | DEBUGFS_READ_FILE_OPS(stations); | 834 | DEBUGFS_READ_FILE_OPS(stations); |
876 | DEBUGFS_READ_FILE_OPS(channels); | 835 | DEBUGFS_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, | |||
141 | void iwl_trans_pcie_txq_agg_setup(struct iwl_priv *priv, int sta_id, int tid, | 141 | void 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 | ******************************************************/ | ||
147 | int iwl_dump_nic_event_log(struct iwl_priv *priv, | ||
148 | bool full_log, char **buf, bool display); | ||
149 | |||
144 | static inline void iwl_disable_interrupts(struct iwl_trans *trans) | 150 | static 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 | ||
499 | static 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 | |||
530 | static 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 | |||
549 | static 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 | |||
568 | static 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 | */ | ||
632 | static 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 | */ | ||
673 | static 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 | */ | ||
752 | static 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 | |||
787 | int 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 */ |
500 | void iwl_irq_tasklet(struct iwl_trans *trans) | 896 | void 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 | ||
1461 | static 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 | |||
1478 | static 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 | |||
1461 | DEBUGFS_READ_WRITE_FILE_OPS(traffic_log); | 1499 | DEBUGFS_READ_WRITE_FILE_OPS(traffic_log); |
1500 | DEBUGFS_READ_WRITE_FILE_OPS(log_event); | ||
1462 | DEBUGFS_READ_FILE_OPS(rx_queue); | 1501 | DEBUGFS_READ_FILE_OPS(rx_queue); |
1463 | DEBUGFS_READ_FILE_OPS(tx_queue); | 1502 | DEBUGFS_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 |