diff options
author | Shahed Shaikh <shahed.shaikh@qlogic.com> | 2013-08-30 13:51:19 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-08-31 22:34:43 -0400 |
commit | 890b6e023bd7ff9b5fc89750d9ab2cd414fa302e (patch) | |
tree | 13a33a89110cc81c7b5c3c3796679cdac65c8dd5 | |
parent | 7010bb65ce01278abe6709fe90407183abc6cbef (diff) |
qlcnic: Store firmware dump state in CAMRAM register
-Use CAMRAM register to store firmware dump state in adapter
instead of maintaining it in each function driver separately.
-Return appropriate error code on failure
Signed-off-by: Shahed Shaikh <shahed.shaikh@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
5 files changed, 135 insertions, 32 deletions
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h index 4e74376fdd9b..f9cd2744b2a0 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h | |||
@@ -392,7 +392,7 @@ struct qlcnic_dump_template_hdr { | |||
392 | 392 | ||
393 | struct qlcnic_fw_dump { | 393 | struct qlcnic_fw_dump { |
394 | u8 clr; /* flag to indicate if dump is cleared */ | 394 | u8 clr; /* flag to indicate if dump is cleared */ |
395 | u8 enable; /* enable/disable dump */ | 395 | bool enable; /* enable/disable dump */ |
396 | u32 size; /* total size of the dump */ | 396 | u32 size; /* total size of the dump */ |
397 | void *data; /* dump data area */ | 397 | void *data; /* dump data area */ |
398 | struct qlcnic_dump_template_hdr *tmpl_hdr; | 398 | struct qlcnic_dump_template_hdr *tmpl_hdr; |
@@ -1477,6 +1477,8 @@ int qlcnic_wol_supported(struct qlcnic_adapter *adapter); | |||
1477 | void qlcnic_prune_lb_filters(struct qlcnic_adapter *adapter); | 1477 | void qlcnic_prune_lb_filters(struct qlcnic_adapter *adapter); |
1478 | void qlcnic_delete_lb_filters(struct qlcnic_adapter *adapter); | 1478 | void qlcnic_delete_lb_filters(struct qlcnic_adapter *adapter); |
1479 | int qlcnic_dump_fw(struct qlcnic_adapter *); | 1479 | int qlcnic_dump_fw(struct qlcnic_adapter *); |
1480 | int qlcnic_enable_fw_dump_state(struct qlcnic_adapter *); | ||
1481 | bool qlcnic_check_fw_dump_state(struct qlcnic_adapter *); | ||
1480 | 1482 | ||
1481 | /* Functions from qlcnic_init.c */ | 1483 | /* Functions from qlcnic_init.c */ |
1482 | void qlcnic_schedule_work(struct qlcnic_adapter *, work_func_t, int); | 1484 | void qlcnic_schedule_work(struct qlcnic_adapter *, work_func_t, int); |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h index 0fc56160d584..053a3a1770bb 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h | |||
@@ -297,6 +297,7 @@ struct qlc_83xx_reset { | |||
297 | 297 | ||
298 | #define QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY 0x1 | 298 | #define QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY 0x1 |
299 | #define QLC_83XX_IDC_GRACEFULL_RESET 0x2 | 299 | #define QLC_83XX_IDC_GRACEFULL_RESET 0x2 |
300 | #define QLC_83XX_IDC_DISABLE_FW_DUMP 0x4 | ||
300 | #define QLC_83XX_IDC_TIMESTAMP 0 | 301 | #define QLC_83XX_IDC_TIMESTAMP 0 |
301 | #define QLC_83XX_IDC_DURATION 1 | 302 | #define QLC_83XX_IDC_DURATION 1 |
302 | #define QLC_83XX_IDC_INIT_TIMEOUT_SECS 30 | 303 | #define QLC_83XX_IDC_INIT_TIMEOUT_SECS 30 |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c index 7b0c90efb365..332aa71798f6 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c | |||
@@ -1509,6 +1509,68 @@ static void qlcnic_set_msglevel(struct net_device *netdev, u32 msglvl) | |||
1509 | adapter->ahw->msg_enable = msglvl; | 1509 | adapter->ahw->msg_enable = msglvl; |
1510 | } | 1510 | } |
1511 | 1511 | ||
1512 | int qlcnic_enable_fw_dump_state(struct qlcnic_adapter *adapter) | ||
1513 | { | ||
1514 | struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump; | ||
1515 | u32 val; | ||
1516 | |||
1517 | if (qlcnic_84xx_check(adapter)) { | ||
1518 | if (qlcnic_83xx_lock_driver(adapter)) | ||
1519 | return -EBUSY; | ||
1520 | |||
1521 | val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL); | ||
1522 | val &= ~QLC_83XX_IDC_DISABLE_FW_DUMP; | ||
1523 | QLCWRX(adapter->ahw, QLC_83XX_IDC_CTRL, val); | ||
1524 | |||
1525 | qlcnic_83xx_unlock_driver(adapter); | ||
1526 | } else { | ||
1527 | fw_dump->enable = true; | ||
1528 | } | ||
1529 | |||
1530 | dev_info(&adapter->pdev->dev, "FW dump enabled\n"); | ||
1531 | |||
1532 | return 0; | ||
1533 | } | ||
1534 | |||
1535 | static int qlcnic_disable_fw_dump_state(struct qlcnic_adapter *adapter) | ||
1536 | { | ||
1537 | struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump; | ||
1538 | u32 val; | ||
1539 | |||
1540 | if (qlcnic_84xx_check(adapter)) { | ||
1541 | if (qlcnic_83xx_lock_driver(adapter)) | ||
1542 | return -EBUSY; | ||
1543 | |||
1544 | val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL); | ||
1545 | val |= QLC_83XX_IDC_DISABLE_FW_DUMP; | ||
1546 | QLCWRX(adapter->ahw, QLC_83XX_IDC_CTRL, val); | ||
1547 | |||
1548 | qlcnic_83xx_unlock_driver(adapter); | ||
1549 | } else { | ||
1550 | fw_dump->enable = false; | ||
1551 | } | ||
1552 | |||
1553 | dev_info(&adapter->pdev->dev, "FW dump disabled\n"); | ||
1554 | |||
1555 | return 0; | ||
1556 | } | ||
1557 | |||
1558 | bool qlcnic_check_fw_dump_state(struct qlcnic_adapter *adapter) | ||
1559 | { | ||
1560 | struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump; | ||
1561 | bool state; | ||
1562 | u32 val; | ||
1563 | |||
1564 | if (qlcnic_84xx_check(adapter)) { | ||
1565 | val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL); | ||
1566 | state = (val & QLC_83XX_IDC_DISABLE_FW_DUMP) ? false : true; | ||
1567 | } else { | ||
1568 | state = fw_dump->enable; | ||
1569 | } | ||
1570 | |||
1571 | return state; | ||
1572 | } | ||
1573 | |||
1512 | static int | 1574 | static int |
1513 | qlcnic_get_dump_flag(struct net_device *netdev, struct ethtool_dump *dump) | 1575 | qlcnic_get_dump_flag(struct net_device *netdev, struct ethtool_dump *dump) |
1514 | { | 1576 | { |
@@ -1525,7 +1587,7 @@ qlcnic_get_dump_flag(struct net_device *netdev, struct ethtool_dump *dump) | |||
1525 | else | 1587 | else |
1526 | dump->len = 0; | 1588 | dump->len = 0; |
1527 | 1589 | ||
1528 | if (!fw_dump->enable) | 1590 | if (!qlcnic_check_fw_dump_state(adapter)) |
1529 | dump->flag = ETH_FW_DUMP_DISABLE; | 1591 | dump->flag = ETH_FW_DUMP_DISABLE; |
1530 | else | 1592 | else |
1531 | dump->flag = fw_dump->tmpl_hdr->drv_cap_mask; | 1593 | dump->flag = fw_dump->tmpl_hdr->drv_cap_mask; |
@@ -1573,77 +1635,111 @@ qlcnic_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump, | |||
1573 | return 0; | 1635 | return 0; |
1574 | } | 1636 | } |
1575 | 1637 | ||
1638 | static int qlcnic_set_dump_mask(struct qlcnic_adapter *adapter, u32 mask) | ||
1639 | { | ||
1640 | struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump; | ||
1641 | struct net_device *netdev = adapter->netdev; | ||
1642 | |||
1643 | if (!qlcnic_check_fw_dump_state(adapter)) { | ||
1644 | netdev_info(netdev, | ||
1645 | "Can not change driver mask to 0x%x. FW dump not enabled\n", | ||
1646 | mask); | ||
1647 | return -EOPNOTSUPP; | ||
1648 | } | ||
1649 | |||
1650 | fw_dump->tmpl_hdr->drv_cap_mask = mask; | ||
1651 | netdev_info(netdev, "Driver mask changed to: 0x%x\n", mask); | ||
1652 | return 0; | ||
1653 | } | ||
1654 | |||
1576 | static int | 1655 | static int |
1577 | qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val) | 1656 | qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val) |
1578 | { | 1657 | { |
1579 | int i; | ||
1580 | struct qlcnic_adapter *adapter = netdev_priv(netdev); | 1658 | struct qlcnic_adapter *adapter = netdev_priv(netdev); |
1581 | struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump; | 1659 | struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump; |
1660 | bool valid_mask = false; | ||
1661 | int i, ret = 0; | ||
1582 | u32 state; | 1662 | u32 state; |
1583 | 1663 | ||
1584 | switch (val->flag) { | 1664 | switch (val->flag) { |
1585 | case QLCNIC_FORCE_FW_DUMP_KEY: | 1665 | case QLCNIC_FORCE_FW_DUMP_KEY: |
1586 | if (!fw_dump->tmpl_hdr) { | 1666 | if (!fw_dump->tmpl_hdr) { |
1587 | netdev_err(netdev, "FW dump not supported\n"); | 1667 | netdev_err(netdev, "FW dump not supported\n"); |
1588 | return -ENOTSUPP; | 1668 | ret = -EOPNOTSUPP; |
1669 | break; | ||
1589 | } | 1670 | } |
1590 | if (!fw_dump->enable) { | 1671 | |
1672 | if (!qlcnic_check_fw_dump_state(adapter)) { | ||
1591 | netdev_info(netdev, "FW dump not enabled\n"); | 1673 | netdev_info(netdev, "FW dump not enabled\n"); |
1592 | return 0; | 1674 | ret = -EOPNOTSUPP; |
1675 | break; | ||
1593 | } | 1676 | } |
1677 | |||
1594 | if (fw_dump->clr) { | 1678 | if (fw_dump->clr) { |
1595 | netdev_info(netdev, | 1679 | netdev_info(netdev, |
1596 | "Previous dump not cleared, not forcing dump\n"); | 1680 | "Previous dump not cleared, not forcing dump\n"); |
1597 | return 0; | 1681 | break; |
1598 | } | 1682 | } |
1683 | |||
1599 | netdev_info(netdev, "Forcing a FW dump\n"); | 1684 | netdev_info(netdev, "Forcing a FW dump\n"); |
1600 | qlcnic_dev_request_reset(adapter, val->flag); | 1685 | qlcnic_dev_request_reset(adapter, val->flag); |
1601 | break; | 1686 | break; |
1602 | case QLCNIC_DISABLE_FW_DUMP: | 1687 | case QLCNIC_DISABLE_FW_DUMP: |
1603 | if (fw_dump->enable && fw_dump->tmpl_hdr) { | 1688 | if (!fw_dump->tmpl_hdr) { |
1604 | netdev_info(netdev, "Disabling FW dump\n"); | 1689 | netdev_err(netdev, "FW dump not supported\n"); |
1605 | fw_dump->enable = 0; | 1690 | ret = -EOPNOTSUPP; |
1691 | break; | ||
1606 | } | 1692 | } |
1607 | return 0; | 1693 | |
1694 | ret = qlcnic_disable_fw_dump_state(adapter); | ||
1695 | break; | ||
1696 | |||
1608 | case QLCNIC_ENABLE_FW_DUMP: | 1697 | case QLCNIC_ENABLE_FW_DUMP: |
1609 | if (!fw_dump->tmpl_hdr) { | 1698 | if (!fw_dump->tmpl_hdr) { |
1610 | netdev_err(netdev, "FW dump not supported\n"); | 1699 | netdev_err(netdev, "FW dump not supported\n"); |
1611 | return -ENOTSUPP; | 1700 | ret = -EOPNOTSUPP; |
1612 | } | 1701 | break; |
1613 | if (!fw_dump->enable) { | ||
1614 | netdev_info(netdev, "Enabling FW dump\n"); | ||
1615 | fw_dump->enable = 1; | ||
1616 | } | 1702 | } |
1617 | return 0; | 1703 | |
1704 | ret = qlcnic_enable_fw_dump_state(adapter); | ||
1705 | break; | ||
1706 | |||
1618 | case QLCNIC_FORCE_FW_RESET: | 1707 | case QLCNIC_FORCE_FW_RESET: |
1619 | netdev_info(netdev, "Forcing a FW reset\n"); | 1708 | netdev_info(netdev, "Forcing a FW reset\n"); |
1620 | qlcnic_dev_request_reset(adapter, val->flag); | 1709 | qlcnic_dev_request_reset(adapter, val->flag); |
1621 | adapter->flags &= ~QLCNIC_FW_RESET_OWNER; | 1710 | adapter->flags &= ~QLCNIC_FW_RESET_OWNER; |
1622 | return 0; | 1711 | break; |
1712 | ; | ||
1623 | case QLCNIC_SET_QUIESCENT: | 1713 | case QLCNIC_SET_QUIESCENT: |
1624 | case QLCNIC_RESET_QUIESCENT: | 1714 | case QLCNIC_RESET_QUIESCENT: |
1625 | state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE); | 1715 | state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE); |
1626 | if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD)) | 1716 | if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD)) |
1627 | netdev_info(netdev, "Device in FAILED state\n"); | 1717 | netdev_info(netdev, "Device in FAILED state\n"); |
1628 | return 0; | 1718 | break; |
1719 | |||
1629 | default: | 1720 | default: |
1630 | if (!fw_dump->tmpl_hdr) { | 1721 | if (!fw_dump->tmpl_hdr) { |
1631 | netdev_err(netdev, "FW dump not supported\n"); | 1722 | netdev_err(netdev, "FW dump not supported\n"); |
1632 | return -ENOTSUPP; | 1723 | ret = -EOPNOTSUPP; |
1724 | break; | ||
1633 | } | 1725 | } |
1726 | |||
1634 | for (i = 0; i < ARRAY_SIZE(qlcnic_fw_dump_level); i++) { | 1727 | for (i = 0; i < ARRAY_SIZE(qlcnic_fw_dump_level); i++) { |
1635 | if (val->flag == qlcnic_fw_dump_level[i]) { | 1728 | if (val->flag == qlcnic_fw_dump_level[i]) { |
1636 | fw_dump->tmpl_hdr->drv_cap_mask = | 1729 | valid_mask = true; |
1637 | val->flag; | 1730 | break; |
1638 | netdev_info(netdev, "Driver mask changed to: 0x%x\n", | ||
1639 | fw_dump->tmpl_hdr->drv_cap_mask); | ||
1640 | return 0; | ||
1641 | } | 1731 | } |
1642 | } | 1732 | } |
1643 | netdev_info(netdev, "Invalid dump level: 0x%x\n", val->flag); | 1733 | |
1644 | return -EINVAL; | 1734 | if (valid_mask) { |
1735 | ret = qlcnic_set_dump_mask(adapter, val->flag); | ||
1736 | } else { | ||
1737 | netdev_info(netdev, "Invalid dump level: 0x%x\n", | ||
1738 | val->flag); | ||
1739 | ret = -EINVAL; | ||
1740 | } | ||
1645 | } | 1741 | } |
1646 | return 0; | 1742 | return ret; |
1647 | } | 1743 | } |
1648 | 1744 | ||
1649 | const struct ethtool_ops qlcnic_ethtool_ops = { | 1745 | const struct ethtool_ops qlcnic_ethtool_ops = { |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index d1ed4e351ab1..e380f0398165 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | |||
@@ -3045,7 +3045,7 @@ skip_ack_check: | |||
3045 | qlcnic_api_unlock(adapter); | 3045 | qlcnic_api_unlock(adapter); |
3046 | 3046 | ||
3047 | rtnl_lock(); | 3047 | rtnl_lock(); |
3048 | if (adapter->ahw->fw_dump.enable && | 3048 | if (qlcnic_check_fw_dump_state(adapter) && |
3049 | (adapter->flags & QLCNIC_FW_RESET_OWNER)) { | 3049 | (adapter->flags & QLCNIC_FW_RESET_OWNER)) { |
3050 | QLCDB(adapter, DRV, "Take FW dump\n"); | 3050 | QLCDB(adapter, DRV, "Take FW dump\n"); |
3051 | qlcnic_dump_fw(adapter); | 3051 | qlcnic_dump_fw(adapter); |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c index b7871fe99162..15513608d480 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c | |||
@@ -1092,7 +1092,7 @@ flash_temp: | |||
1092 | else | 1092 | else |
1093 | ahw->fw_dump.use_pex_dma = false; | 1093 | ahw->fw_dump.use_pex_dma = false; |
1094 | 1094 | ||
1095 | ahw->fw_dump.enable = 1; | 1095 | qlcnic_enable_fw_dump_state(adapter); |
1096 | 1096 | ||
1097 | return 0; | 1097 | return 0; |
1098 | } | 1098 | } |
@@ -1115,7 +1115,11 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter) | |||
1115 | 1115 | ||
1116 | ahw = adapter->ahw; | 1116 | ahw = adapter->ahw; |
1117 | 1117 | ||
1118 | if (!fw_dump->enable) { | 1118 | /* Return if we don't have firmware dump template header */ |
1119 | if (!tmpl_hdr) | ||
1120 | return -EIO; | ||
1121 | |||
1122 | if (!qlcnic_check_fw_dump_state(adapter)) { | ||
1119 | dev_info(&adapter->pdev->dev, "Dump not enabled\n"); | 1123 | dev_info(&adapter->pdev->dev, "Dump not enabled\n"); |
1120 | return -EIO; | 1124 | return -EIO; |
1121 | } | 1125 | } |