diff options
author | Ben Hutchings <bhutchings@solarflare.com> | 2010-06-20 23:06:53 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-06-25 01:13:14 -0400 |
commit | 5b98c1bfcfc745604985e6a50ef7481c39a9fcea (patch) | |
tree | 229ee3aebc005882769cac7139d02779b5880a25 /drivers/net/sfc | |
parent | 565b7b2d2e632b5792879c0c9cccdd9eecd31195 (diff) |
sfc: Implement ethtool register dump operation
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Acked-by: Jeff Garzik <jgarzik@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/sfc')
-rw-r--r-- | drivers/net/sfc/ethtool.c | 16 | ||||
-rw-r--r-- | drivers/net/sfc/io.h | 7 | ||||
-rw-r--r-- | drivers/net/sfc/nic.c | 266 | ||||
-rw-r--r-- | drivers/net/sfc/nic.h | 3 |
4 files changed, 292 insertions, 0 deletions
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index 22026bfbc4c1..81b7f39ca5fb 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c | |||
@@ -242,6 +242,20 @@ static void efx_ethtool_get_drvinfo(struct net_device *net_dev, | |||
242 | strlcpy(info->bus_info, pci_name(efx->pci_dev), sizeof(info->bus_info)); | 242 | strlcpy(info->bus_info, pci_name(efx->pci_dev), sizeof(info->bus_info)); |
243 | } | 243 | } |
244 | 244 | ||
245 | static int efx_ethtool_get_regs_len(struct net_device *net_dev) | ||
246 | { | ||
247 | return efx_nic_get_regs_len(netdev_priv(net_dev)); | ||
248 | } | ||
249 | |||
250 | static void efx_ethtool_get_regs(struct net_device *net_dev, | ||
251 | struct ethtool_regs *regs, void *buf) | ||
252 | { | ||
253 | struct efx_nic *efx = netdev_priv(net_dev); | ||
254 | |||
255 | regs->version = efx->type->revision; | ||
256 | efx_nic_get_regs(efx, buf); | ||
257 | } | ||
258 | |||
245 | /** | 259 | /** |
246 | * efx_fill_test - fill in an individual self-test entry | 260 | * efx_fill_test - fill in an individual self-test entry |
247 | * @test_index: Index of the test | 261 | * @test_index: Index of the test |
@@ -834,6 +848,8 @@ const struct ethtool_ops efx_ethtool_ops = { | |||
834 | .get_settings = efx_ethtool_get_settings, | 848 | .get_settings = efx_ethtool_get_settings, |
835 | .set_settings = efx_ethtool_set_settings, | 849 | .set_settings = efx_ethtool_set_settings, |
836 | .get_drvinfo = efx_ethtool_get_drvinfo, | 850 | .get_drvinfo = efx_ethtool_get_drvinfo, |
851 | .get_regs_len = efx_ethtool_get_regs_len, | ||
852 | .get_regs = efx_ethtool_get_regs, | ||
837 | .nway_reset = efx_ethtool_nway_reset, | 853 | .nway_reset = efx_ethtool_nway_reset, |
838 | .get_link = efx_ethtool_get_link, | 854 | .get_link = efx_ethtool_get_link, |
839 | .get_eeprom_len = efx_ethtool_get_eeprom_len, | 855 | .get_eeprom_len = efx_ethtool_get_eeprom_len, |
diff --git a/drivers/net/sfc/io.h b/drivers/net/sfc/io.h index b89177c27f4a..4317574c772d 100644 --- a/drivers/net/sfc/io.h +++ b/drivers/net/sfc/io.h | |||
@@ -211,6 +211,13 @@ static inline void efx_writed_table(struct efx_nic *efx, efx_dword_t *value, | |||
211 | efx_writed(efx, value, reg + index * sizeof(efx_oword_t)); | 211 | efx_writed(efx, value, reg + index * sizeof(efx_oword_t)); |
212 | } | 212 | } |
213 | 213 | ||
214 | /* Read from a dword register forming part of a table */ | ||
215 | static inline void efx_readd_table(struct efx_nic *efx, efx_dword_t *value, | ||
216 | unsigned int reg, unsigned int index) | ||
217 | { | ||
218 | efx_readd(efx, value, reg + index * sizeof(efx_dword_t)); | ||
219 | } | ||
220 | |||
214 | /* Page-mapped register block size */ | 221 | /* Page-mapped register block size */ |
215 | #define EFX_PAGE_BLOCK_SIZE 0x2000 | 222 | #define EFX_PAGE_BLOCK_SIZE 0x2000 |
216 | 223 | ||
diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c index 0ee6fd367e6f..67235f1c2550 100644 --- a/drivers/net/sfc/nic.c +++ b/drivers/net/sfc/nic.c | |||
@@ -1627,3 +1627,269 @@ void efx_nic_init_common(struct efx_nic *efx) | |||
1627 | EFX_SET_OWORD_FIELD(temp, FRF_BZ_TX_FLUSH_MIN_LEN_EN, 1); | 1627 | EFX_SET_OWORD_FIELD(temp, FRF_BZ_TX_FLUSH_MIN_LEN_EN, 1); |
1628 | efx_writeo(efx, &temp, FR_AZ_TX_RESERVED); | 1628 | efx_writeo(efx, &temp, FR_AZ_TX_RESERVED); |
1629 | } | 1629 | } |
1630 | |||
1631 | /* Register dump */ | ||
1632 | |||
1633 | #define REGISTER_REVISION_A 1 | ||
1634 | #define REGISTER_REVISION_B 2 | ||
1635 | #define REGISTER_REVISION_C 3 | ||
1636 | #define REGISTER_REVISION_Z 3 /* latest revision */ | ||
1637 | |||
1638 | struct efx_nic_reg { | ||
1639 | u32 offset:24; | ||
1640 | u32 min_revision:2, max_revision:2; | ||
1641 | }; | ||
1642 | |||
1643 | #define REGISTER(name, min_rev, max_rev) { \ | ||
1644 | FR_ ## min_rev ## max_rev ## _ ## name, \ | ||
1645 | REGISTER_REVISION_ ## min_rev, REGISTER_REVISION_ ## max_rev \ | ||
1646 | } | ||
1647 | #define REGISTER_AA(name) REGISTER(name, A, A) | ||
1648 | #define REGISTER_AB(name) REGISTER(name, A, B) | ||
1649 | #define REGISTER_AZ(name) REGISTER(name, A, Z) | ||
1650 | #define REGISTER_BB(name) REGISTER(name, B, B) | ||
1651 | #define REGISTER_BZ(name) REGISTER(name, B, Z) | ||
1652 | #define REGISTER_CZ(name) REGISTER(name, C, Z) | ||
1653 | |||
1654 | static const struct efx_nic_reg efx_nic_regs[] = { | ||
1655 | REGISTER_AZ(ADR_REGION), | ||
1656 | REGISTER_AZ(INT_EN_KER), | ||
1657 | REGISTER_BZ(INT_EN_CHAR), | ||
1658 | REGISTER_AZ(INT_ADR_KER), | ||
1659 | REGISTER_BZ(INT_ADR_CHAR), | ||
1660 | /* INT_ACK_KER is WO */ | ||
1661 | /* INT_ISR0 is RC */ | ||
1662 | REGISTER_AZ(HW_INIT), | ||
1663 | REGISTER_CZ(USR_EV_CFG), | ||
1664 | REGISTER_AB(EE_SPI_HCMD), | ||
1665 | REGISTER_AB(EE_SPI_HADR), | ||
1666 | REGISTER_AB(EE_SPI_HDATA), | ||
1667 | REGISTER_AB(EE_BASE_PAGE), | ||
1668 | REGISTER_AB(EE_VPD_CFG0), | ||
1669 | /* EE_VPD_SW_CNTL and EE_VPD_SW_DATA are not used */ | ||
1670 | /* PMBX_DBG_IADDR and PBMX_DBG_IDATA are indirect */ | ||
1671 | /* PCIE_CORE_INDIRECT is indirect */ | ||
1672 | REGISTER_AB(NIC_STAT), | ||
1673 | REGISTER_AB(GPIO_CTL), | ||
1674 | REGISTER_AB(GLB_CTL), | ||
1675 | /* FATAL_INTR_KER and FATAL_INTR_CHAR are partly RC */ | ||
1676 | REGISTER_BZ(DP_CTRL), | ||
1677 | REGISTER_AZ(MEM_STAT), | ||
1678 | REGISTER_AZ(CS_DEBUG), | ||
1679 | REGISTER_AZ(ALTERA_BUILD), | ||
1680 | REGISTER_AZ(CSR_SPARE), | ||
1681 | REGISTER_AB(PCIE_SD_CTL0123), | ||
1682 | REGISTER_AB(PCIE_SD_CTL45), | ||
1683 | REGISTER_AB(PCIE_PCS_CTL_STAT), | ||
1684 | /* DEBUG_DATA_OUT is not used */ | ||
1685 | /* DRV_EV is WO */ | ||
1686 | REGISTER_AZ(EVQ_CTL), | ||
1687 | REGISTER_AZ(EVQ_CNT1), | ||
1688 | REGISTER_AZ(EVQ_CNT2), | ||
1689 | REGISTER_AZ(BUF_TBL_CFG), | ||
1690 | REGISTER_AZ(SRM_RX_DC_CFG), | ||
1691 | REGISTER_AZ(SRM_TX_DC_CFG), | ||
1692 | REGISTER_AZ(SRM_CFG), | ||
1693 | /* BUF_TBL_UPD is WO */ | ||
1694 | REGISTER_AZ(SRM_UPD_EVQ), | ||
1695 | REGISTER_AZ(SRAM_PARITY), | ||
1696 | REGISTER_AZ(RX_CFG), | ||
1697 | REGISTER_BZ(RX_FILTER_CTL), | ||
1698 | /* RX_FLUSH_DESCQ is WO */ | ||
1699 | REGISTER_AZ(RX_DC_CFG), | ||
1700 | REGISTER_AZ(RX_DC_PF_WM), | ||
1701 | REGISTER_BZ(RX_RSS_TKEY), | ||
1702 | /* RX_NODESC_DROP is RC */ | ||
1703 | REGISTER_AA(RX_SELF_RST), | ||
1704 | /* RX_DEBUG, RX_PUSH_DROP are not used */ | ||
1705 | REGISTER_CZ(RX_RSS_IPV6_REG1), | ||
1706 | REGISTER_CZ(RX_RSS_IPV6_REG2), | ||
1707 | REGISTER_CZ(RX_RSS_IPV6_REG3), | ||
1708 | /* TX_FLUSH_DESCQ is WO */ | ||
1709 | REGISTER_AZ(TX_DC_CFG), | ||
1710 | REGISTER_AA(TX_CHKSM_CFG), | ||
1711 | REGISTER_AZ(TX_CFG), | ||
1712 | /* TX_PUSH_DROP is not used */ | ||
1713 | REGISTER_AZ(TX_RESERVED), | ||
1714 | REGISTER_BZ(TX_PACE), | ||
1715 | /* TX_PACE_DROP_QID is RC */ | ||
1716 | REGISTER_BB(TX_VLAN), | ||
1717 | REGISTER_BZ(TX_IPFIL_PORTEN), | ||
1718 | REGISTER_AB(MD_TXD), | ||
1719 | REGISTER_AB(MD_RXD), | ||
1720 | REGISTER_AB(MD_CS), | ||
1721 | REGISTER_AB(MD_PHY_ADR), | ||
1722 | REGISTER_AB(MD_ID), | ||
1723 | /* MD_STAT is RC */ | ||
1724 | REGISTER_AB(MAC_STAT_DMA), | ||
1725 | REGISTER_AB(MAC_CTRL), | ||
1726 | REGISTER_BB(GEN_MODE), | ||
1727 | REGISTER_AB(MAC_MC_HASH_REG0), | ||
1728 | REGISTER_AB(MAC_MC_HASH_REG1), | ||
1729 | REGISTER_AB(GM_CFG1), | ||
1730 | REGISTER_AB(GM_CFG2), | ||
1731 | /* GM_IPG and GM_HD are not used */ | ||
1732 | REGISTER_AB(GM_MAX_FLEN), | ||
1733 | /* GM_TEST is not used */ | ||
1734 | REGISTER_AB(GM_ADR1), | ||
1735 | REGISTER_AB(GM_ADR2), | ||
1736 | REGISTER_AB(GMF_CFG0), | ||
1737 | REGISTER_AB(GMF_CFG1), | ||
1738 | REGISTER_AB(GMF_CFG2), | ||
1739 | REGISTER_AB(GMF_CFG3), | ||
1740 | REGISTER_AB(GMF_CFG4), | ||
1741 | REGISTER_AB(GMF_CFG5), | ||
1742 | REGISTER_BB(TX_SRC_MAC_CTL), | ||
1743 | REGISTER_AB(XM_ADR_LO), | ||
1744 | REGISTER_AB(XM_ADR_HI), | ||
1745 | REGISTER_AB(XM_GLB_CFG), | ||
1746 | REGISTER_AB(XM_TX_CFG), | ||
1747 | REGISTER_AB(XM_RX_CFG), | ||
1748 | REGISTER_AB(XM_MGT_INT_MASK), | ||
1749 | REGISTER_AB(XM_FC), | ||
1750 | REGISTER_AB(XM_PAUSE_TIME), | ||
1751 | REGISTER_AB(XM_TX_PARAM), | ||
1752 | REGISTER_AB(XM_RX_PARAM), | ||
1753 | /* XM_MGT_INT_MSK (note no 'A') is RC */ | ||
1754 | REGISTER_AB(XX_PWR_RST), | ||
1755 | REGISTER_AB(XX_SD_CTL), | ||
1756 | REGISTER_AB(XX_TXDRV_CTL), | ||
1757 | /* XX_PRBS_CTL, XX_PRBS_CHK and XX_PRBS_ERR are not used */ | ||
1758 | /* XX_CORE_STAT is partly RC */ | ||
1759 | }; | ||
1760 | |||
1761 | struct efx_nic_reg_table { | ||
1762 | u32 offset:24; | ||
1763 | u32 min_revision:2, max_revision:2; | ||
1764 | u32 step:6, rows:21; | ||
1765 | }; | ||
1766 | |||
1767 | #define REGISTER_TABLE_DIMENSIONS(_, offset, min_rev, max_rev, step, rows) { \ | ||
1768 | offset, \ | ||
1769 | REGISTER_REVISION_ ## min_rev, REGISTER_REVISION_ ## max_rev, \ | ||
1770 | step, rows \ | ||
1771 | } | ||
1772 | #define REGISTER_TABLE(name, min_rev, max_rev) \ | ||
1773 | REGISTER_TABLE_DIMENSIONS( \ | ||
1774 | name, FR_ ## min_rev ## max_rev ## _ ## name, \ | ||
1775 | min_rev, max_rev, \ | ||
1776 | FR_ ## min_rev ## max_rev ## _ ## name ## _STEP, \ | ||
1777 | FR_ ## min_rev ## max_rev ## _ ## name ## _ROWS) | ||
1778 | #define REGISTER_TABLE_AA(name) REGISTER_TABLE(name, A, A) | ||
1779 | #define REGISTER_TABLE_AZ(name) REGISTER_TABLE(name, A, Z) | ||
1780 | #define REGISTER_TABLE_BB(name) REGISTER_TABLE(name, B, B) | ||
1781 | #define REGISTER_TABLE_BZ(name) REGISTER_TABLE(name, B, Z) | ||
1782 | #define REGISTER_TABLE_BB_CZ(name) \ | ||
1783 | REGISTER_TABLE_DIMENSIONS(name, FR_BZ_ ## name, B, B, \ | ||
1784 | FR_BZ_ ## name ## _STEP, \ | ||
1785 | FR_BB_ ## name ## _ROWS), \ | ||
1786 | REGISTER_TABLE_DIMENSIONS(name, FR_BZ_ ## name, C, Z, \ | ||
1787 | FR_BZ_ ## name ## _STEP, \ | ||
1788 | FR_CZ_ ## name ## _ROWS) | ||
1789 | #define REGISTER_TABLE_CZ(name) REGISTER_TABLE(name, C, Z) | ||
1790 | |||
1791 | static const struct efx_nic_reg_table efx_nic_reg_tables[] = { | ||
1792 | /* DRIVER is not used */ | ||
1793 | /* EVQ_RPTR, TIMER_COMMAND, USR_EV and {RX,TX}_DESC_UPD are WO */ | ||
1794 | REGISTER_TABLE_BB(TX_IPFIL_TBL), | ||
1795 | REGISTER_TABLE_BB(TX_SRC_MAC_TBL), | ||
1796 | REGISTER_TABLE_AA(RX_DESC_PTR_TBL_KER), | ||
1797 | REGISTER_TABLE_BB_CZ(RX_DESC_PTR_TBL), | ||
1798 | REGISTER_TABLE_AA(TX_DESC_PTR_TBL_KER), | ||
1799 | REGISTER_TABLE_BB_CZ(TX_DESC_PTR_TBL), | ||
1800 | REGISTER_TABLE_AA(EVQ_PTR_TBL_KER), | ||
1801 | REGISTER_TABLE_BB_CZ(EVQ_PTR_TBL), | ||
1802 | /* The register buffer is allocated with slab, so we can't | ||
1803 | * reasonably read all of the buffer table (up to 8MB!). | ||
1804 | * However this driver will only use a few entries. Reading | ||
1805 | * 1K entries allows for some expansion of queue count and | ||
1806 | * size before we need to change the version. */ | ||
1807 | REGISTER_TABLE_DIMENSIONS(BUF_FULL_TBL_KER, FR_AA_BUF_FULL_TBL_KER, | ||
1808 | A, A, 8, 1024), | ||
1809 | REGISTER_TABLE_DIMENSIONS(BUF_FULL_TBL, FR_BZ_BUF_FULL_TBL, | ||
1810 | B, Z, 8, 1024), | ||
1811 | /* RX_FILTER_TBL{0,1} is huge and not used by this driver */ | ||
1812 | REGISTER_TABLE_CZ(RX_MAC_FILTER_TBL0), | ||
1813 | REGISTER_TABLE_BB_CZ(TIMER_TBL), | ||
1814 | REGISTER_TABLE_BB_CZ(TX_PACE_TBL), | ||
1815 | REGISTER_TABLE_BZ(RX_INDIRECTION_TBL), | ||
1816 | /* TX_FILTER_TBL0 is huge and not used by this driver */ | ||
1817 | REGISTER_TABLE_CZ(TX_MAC_FILTER_TBL0), | ||
1818 | REGISTER_TABLE_CZ(MC_TREG_SMEM), | ||
1819 | /* MSIX_PBA_TABLE is not mapped */ | ||
1820 | /* SRM_DBG is not mapped (and is redundant with BUF_FLL_TBL) */ | ||
1821 | }; | ||
1822 | |||
1823 | size_t efx_nic_get_regs_len(struct efx_nic *efx) | ||
1824 | { | ||
1825 | const struct efx_nic_reg *reg; | ||
1826 | const struct efx_nic_reg_table *table; | ||
1827 | size_t len = 0; | ||
1828 | |||
1829 | for (reg = efx_nic_regs; | ||
1830 | reg < efx_nic_regs + ARRAY_SIZE(efx_nic_regs); | ||
1831 | reg++) | ||
1832 | if (efx->type->revision >= reg->min_revision && | ||
1833 | efx->type->revision <= reg->max_revision) | ||
1834 | len += sizeof(efx_oword_t); | ||
1835 | |||
1836 | for (table = efx_nic_reg_tables; | ||
1837 | table < efx_nic_reg_tables + ARRAY_SIZE(efx_nic_reg_tables); | ||
1838 | table++) | ||
1839 | if (efx->type->revision >= table->min_revision && | ||
1840 | efx->type->revision <= table->max_revision) | ||
1841 | len += table->rows * min_t(size_t, table->step, 16); | ||
1842 | |||
1843 | return len; | ||
1844 | } | ||
1845 | |||
1846 | void efx_nic_get_regs(struct efx_nic *efx, void *buf) | ||
1847 | { | ||
1848 | const struct efx_nic_reg *reg; | ||
1849 | const struct efx_nic_reg_table *table; | ||
1850 | |||
1851 | for (reg = efx_nic_regs; | ||
1852 | reg < efx_nic_regs + ARRAY_SIZE(efx_nic_regs); | ||
1853 | reg++) { | ||
1854 | if (efx->type->revision >= reg->min_revision && | ||
1855 | efx->type->revision <= reg->max_revision) { | ||
1856 | efx_reado(efx, (efx_oword_t *)buf, reg->offset); | ||
1857 | buf += sizeof(efx_oword_t); | ||
1858 | } | ||
1859 | } | ||
1860 | |||
1861 | for (table = efx_nic_reg_tables; | ||
1862 | table < efx_nic_reg_tables + ARRAY_SIZE(efx_nic_reg_tables); | ||
1863 | table++) { | ||
1864 | size_t size, i; | ||
1865 | |||
1866 | if (!(efx->type->revision >= table->min_revision && | ||
1867 | efx->type->revision <= table->max_revision)) | ||
1868 | continue; | ||
1869 | |||
1870 | size = min_t(size_t, table->step, 16); | ||
1871 | |||
1872 | for (i = 0; i < table->rows; i++) { | ||
1873 | switch (table->step) { | ||
1874 | case 4: /* 32-bit register or SRAM */ | ||
1875 | efx_readd_table(efx, buf, table->offset, i); | ||
1876 | break; | ||
1877 | case 8: /* 64-bit SRAM */ | ||
1878 | efx_sram_readq(efx, | ||
1879 | efx->membase + table->offset, | ||
1880 | buf, i); | ||
1881 | break; | ||
1882 | case 16: /* 128-bit register */ | ||
1883 | efx_reado_table(efx, buf, table->offset, i); | ||
1884 | break; | ||
1885 | case 32: /* 128-bit register, interleaved */ | ||
1886 | efx_reado_table(efx, buf, table->offset, 2 * i); | ||
1887 | break; | ||
1888 | default: | ||
1889 | WARN_ON(1); | ||
1890 | return; | ||
1891 | } | ||
1892 | buf += size; | ||
1893 | } | ||
1894 | } | ||
1895 | } | ||
diff --git a/drivers/net/sfc/nic.h b/drivers/net/sfc/nic.h index 95770e15115d..534461ffece8 100644 --- a/drivers/net/sfc/nic.h +++ b/drivers/net/sfc/nic.h | |||
@@ -222,6 +222,9 @@ extern int efx_nic_test_registers(struct efx_nic *efx, | |||
222 | const struct efx_nic_register_test *regs, | 222 | const struct efx_nic_register_test *regs, |
223 | size_t n_regs); | 223 | size_t n_regs); |
224 | 224 | ||
225 | extern size_t efx_nic_get_regs_len(struct efx_nic *efx); | ||
226 | extern void efx_nic_get_regs(struct efx_nic *efx, void *buf); | ||
227 | |||
225 | /************************************************************************** | 228 | /************************************************************************** |
226 | * | 229 | * |
227 | * Falcon MAC stats | 230 | * Falcon MAC stats |