diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-agn.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn.c | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 00457bff1ed1..cdc07c477457 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c | |||
@@ -1526,6 +1526,191 @@ static int iwl_read_ucode(struct iwl_priv *priv) | |||
1526 | return ret; | 1526 | return ret; |
1527 | } | 1527 | } |
1528 | 1528 | ||
1529 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
1530 | static const char *desc_lookup_text[] = { | ||
1531 | "OK", | ||
1532 | "FAIL", | ||
1533 | "BAD_PARAM", | ||
1534 | "BAD_CHECKSUM", | ||
1535 | "NMI_INTERRUPT_WDG", | ||
1536 | "SYSASSERT", | ||
1537 | "FATAL_ERROR", | ||
1538 | "BAD_COMMAND", | ||
1539 | "HW_ERROR_TUNE_LOCK", | ||
1540 | "HW_ERROR_TEMPERATURE", | ||
1541 | "ILLEGAL_CHAN_FREQ", | ||
1542 | "VCC_NOT_STABLE", | ||
1543 | "FH_ERROR", | ||
1544 | "NMI_INTERRUPT_HOST", | ||
1545 | "NMI_INTERRUPT_ACTION_PT", | ||
1546 | "NMI_INTERRUPT_UNKNOWN", | ||
1547 | "UCODE_VERSION_MISMATCH", | ||
1548 | "HW_ERROR_ABS_LOCK", | ||
1549 | "HW_ERROR_CAL_LOCK_FAIL", | ||
1550 | "NMI_INTERRUPT_INST_ACTION_PT", | ||
1551 | "NMI_INTERRUPT_DATA_ACTION_PT", | ||
1552 | "NMI_TRM_HW_ER", | ||
1553 | "NMI_INTERRUPT_TRM", | ||
1554 | "NMI_INTERRUPT_BREAK_POINT" | ||
1555 | "DEBUG_0", | ||
1556 | "DEBUG_1", | ||
1557 | "DEBUG_2", | ||
1558 | "DEBUG_3", | ||
1559 | "UNKNOWN" | ||
1560 | }; | ||
1561 | |||
1562 | static const char *desc_lookup(int i) | ||
1563 | { | ||
1564 | int max = ARRAY_SIZE(desc_lookup_text) - 1; | ||
1565 | |||
1566 | if (i < 0 || i > max) | ||
1567 | i = max; | ||
1568 | |||
1569 | return desc_lookup_text[i]; | ||
1570 | } | ||
1571 | |||
1572 | #define ERROR_START_OFFSET (1 * sizeof(u32)) | ||
1573 | #define ERROR_ELEM_SIZE (7 * sizeof(u32)) | ||
1574 | |||
1575 | void iwl_dump_nic_error_log(struct iwl_priv *priv) | ||
1576 | { | ||
1577 | u32 data2, line; | ||
1578 | u32 desc, time, count, base, data1; | ||
1579 | u32 blink1, blink2, ilink1, ilink2; | ||
1580 | |||
1581 | if (priv->ucode_type == UCODE_INIT) | ||
1582 | base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr); | ||
1583 | else | ||
1584 | base = le32_to_cpu(priv->card_alive.error_event_table_ptr); | ||
1585 | |||
1586 | if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { | ||
1587 | IWL_ERR(priv, "Not valid error log pointer 0x%08X\n", base); | ||
1588 | return; | ||
1589 | } | ||
1590 | |||
1591 | count = iwl_read_targ_mem(priv, base); | ||
1592 | |||
1593 | if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) { | ||
1594 | IWL_ERR(priv, "Start IWL Error Log Dump:\n"); | ||
1595 | IWL_ERR(priv, "Status: 0x%08lX, count: %d\n", | ||
1596 | priv->status, count); | ||
1597 | } | ||
1598 | |||
1599 | desc = iwl_read_targ_mem(priv, base + 1 * sizeof(u32)); | ||
1600 | blink1 = iwl_read_targ_mem(priv, base + 3 * sizeof(u32)); | ||
1601 | blink2 = iwl_read_targ_mem(priv, base + 4 * sizeof(u32)); | ||
1602 | ilink1 = iwl_read_targ_mem(priv, base + 5 * sizeof(u32)); | ||
1603 | ilink2 = iwl_read_targ_mem(priv, base + 6 * sizeof(u32)); | ||
1604 | data1 = iwl_read_targ_mem(priv, base + 7 * sizeof(u32)); | ||
1605 | data2 = iwl_read_targ_mem(priv, base + 8 * sizeof(u32)); | ||
1606 | line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32)); | ||
1607 | time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32)); | ||
1608 | |||
1609 | IWL_ERR(priv, "Desc Time " | ||
1610 | "data1 data2 line\n"); | ||
1611 | IWL_ERR(priv, "%-28s (#%02d) %010u 0x%08X 0x%08X %u\n", | ||
1612 | desc_lookup(desc), desc, time, data1, data2, line); | ||
1613 | IWL_ERR(priv, "blink1 blink2 ilink1 ilink2\n"); | ||
1614 | IWL_ERR(priv, "0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2, | ||
1615 | ilink1, ilink2); | ||
1616 | |||
1617 | } | ||
1618 | |||
1619 | #define EVENT_START_OFFSET (4 * sizeof(u32)) | ||
1620 | |||
1621 | /** | ||
1622 | * iwl_print_event_log - Dump error event log to syslog | ||
1623 | * | ||
1624 | */ | ||
1625 | static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, | ||
1626 | u32 num_events, u32 mode) | ||
1627 | { | ||
1628 | u32 i; | ||
1629 | u32 base; /* SRAM byte address of event log header */ | ||
1630 | u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */ | ||
1631 | u32 ptr; /* SRAM byte address of log data */ | ||
1632 | u32 ev, time, data; /* event log data */ | ||
1633 | |||
1634 | if (num_events == 0) | ||
1635 | return; | ||
1636 | if (priv->ucode_type == UCODE_INIT) | ||
1637 | base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); | ||
1638 | else | ||
1639 | base = le32_to_cpu(priv->card_alive.log_event_table_ptr); | ||
1640 | |||
1641 | if (mode == 0) | ||
1642 | event_size = 2 * sizeof(u32); | ||
1643 | else | ||
1644 | event_size = 3 * sizeof(u32); | ||
1645 | |||
1646 | ptr = base + EVENT_START_OFFSET + (start_idx * event_size); | ||
1647 | |||
1648 | /* "time" is actually "data" for mode 0 (no timestamp). | ||
1649 | * place event id # at far right for easier visual parsing. */ | ||
1650 | for (i = 0; i < num_events; i++) { | ||
1651 | ev = iwl_read_targ_mem(priv, ptr); | ||
1652 | ptr += sizeof(u32); | ||
1653 | time = iwl_read_targ_mem(priv, ptr); | ||
1654 | ptr += sizeof(u32); | ||
1655 | if (mode == 0) { | ||
1656 | /* data, ev */ | ||
1657 | IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n", time, ev); | ||
1658 | } else { | ||
1659 | data = iwl_read_targ_mem(priv, ptr); | ||
1660 | ptr += sizeof(u32); | ||
1661 | IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n", | ||
1662 | time, data, ev); | ||
1663 | } | ||
1664 | } | ||
1665 | } | ||
1666 | |||
1667 | void iwl_dump_nic_event_log(struct iwl_priv *priv) | ||
1668 | { | ||
1669 | u32 base; /* SRAM byte address of event log header */ | ||
1670 | u32 capacity; /* event log capacity in # entries */ | ||
1671 | u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */ | ||
1672 | u32 num_wraps; /* # times uCode wrapped to top of log */ | ||
1673 | u32 next_entry; /* index of next entry to be written by uCode */ | ||
1674 | u32 size; /* # entries that we'll print */ | ||
1675 | |||
1676 | if (priv->ucode_type == UCODE_INIT) | ||
1677 | base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); | ||
1678 | else | ||
1679 | base = le32_to_cpu(priv->card_alive.log_event_table_ptr); | ||
1680 | |||
1681 | if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { | ||
1682 | IWL_ERR(priv, "Invalid event log pointer 0x%08X\n", base); | ||
1683 | return; | ||
1684 | } | ||
1685 | |||
1686 | /* event log header */ | ||
1687 | capacity = iwl_read_targ_mem(priv, base); | ||
1688 | mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32))); | ||
1689 | num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32))); | ||
1690 | next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32))); | ||
1691 | |||
1692 | size = num_wraps ? capacity : next_entry; | ||
1693 | |||
1694 | /* bail out if nothing in log */ | ||
1695 | if (size == 0) { | ||
1696 | IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n"); | ||
1697 | return; | ||
1698 | } | ||
1699 | |||
1700 | IWL_ERR(priv, "Start IWL Event Log Dump: display count %d, wraps %d\n", | ||
1701 | size, num_wraps); | ||
1702 | |||
1703 | /* if uCode has wrapped back to top of log, start at the oldest entry, | ||
1704 | * i.e the next one that uCode would fill. */ | ||
1705 | if (num_wraps) | ||
1706 | iwl_print_event_log(priv, next_entry, | ||
1707 | capacity - next_entry, mode); | ||
1708 | /* (then/else) start at top of log */ | ||
1709 | iwl_print_event_log(priv, 0, next_entry, mode); | ||
1710 | |||
1711 | } | ||
1712 | #endif | ||
1713 | |||
1529 | /** | 1714 | /** |
1530 | * iwl_alive_start - called after REPLY_ALIVE notification received | 1715 | * iwl_alive_start - called after REPLY_ALIVE notification received |
1531 | * from protocol/runtime uCode (initialization uCode's | 1716 | * from protocol/runtime uCode (initialization uCode's |