stmmac: add HW DMA feature register (v3)
authorGiuseppe CAVALLARO <peppe.cavallaro@st.com>
Thu, 1 Sep 2011 21:51:41 +0000 (21:51 +0000)
committerDavid S. Miller <davem@davemloft.net>
Thu, 15 Sep 2011 19:40:01 +0000 (15:40 -0400)
New GMAC chips have an extra register to indicate
the presence of the optional features/functions of
the DMA core.

This patch adds this support and all the HW cap
are exported via debugfs.

Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/stmicro/stmmac/Kconfig
drivers/net/ethernet/stmicro/stmmac/common.h
drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
drivers/net/ethernet/stmicro/stmmac/stmmac.h
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c

index ae7f56312f080a87d65e2d216cac5b3afe26c997..2e35be7ccfaeada23702fa16dd9852cae9ea5860 100644 (file)
@@ -16,7 +16,8 @@ config STMMAC_DEBUG_FS
        default n
        depends on STMMAC_ETH && DEBUG_FS
        -- help
-         The stmmac entry in /sys reports DMA TX/RX rings.
+         The stmmac entry in /sys reports DMA TX/RX rings
+         or (if supported) the HW cap register.
 
 config STMMAC_DA
        bool "STMMAC DMA arbitration scheme"
index 65b1e56a97c9693d1910f79120d468d886651e31..22c61b2ebfa3ce5a6c73ac97abea1234b8f0b3ff 100644 (file)
@@ -116,6 +116,37 @@ enum tx_dma_irq_status {
        handle_tx_rx = 3,
 };
 
+/* DMA HW capabilities */
+struct dma_features {
+       unsigned int mbps_10_100;
+       unsigned int mbps_1000;
+       unsigned int half_duplex;
+       unsigned int hash_filter;
+       unsigned int multi_addr;
+       unsigned int pcs;
+       unsigned int sma_mdio;
+       unsigned int pmt_remote_wake_up;
+       unsigned int pmt_magic_frame;
+       unsigned int rmon;
+       /* IEEE 1588-2002*/
+       unsigned int time_stamp;
+       /* IEEE 1588-2008*/
+       unsigned int atime_stamp;
+       /* 802.3az - Energy-Efficient Ethernet (EEE) */
+       unsigned int eee;
+       unsigned int av;
+       /* TX and RX csum */
+       unsigned int tx_coe;
+       unsigned int rx_coe_type1;
+       unsigned int rx_coe_type2;
+       unsigned int rxfifo_over_2048;
+       /* TX and RX number of channels */
+       unsigned int number_rx_channel;
+       unsigned int number_tx_channel;
+       /* Alternate (enhanced) DESC mode*/
+       unsigned int enh_desc;
+};
+
 /* GMAC TX FIFO is 8K, Rx FIFO is 16K */
 #define BUF_SIZE_16KiB 16384
 #define BUF_SIZE_8KiB 8192
@@ -188,6 +219,8 @@ struct stmmac_dma_ops {
        void (*stop_rx) (void __iomem *ioaddr);
        int (*dma_interrupt) (void __iomem *ioaddr,
                              struct stmmac_extra_stats *x);
+       /* If supported then get the optional core features */
+       unsigned int (*get_hw_feature) (void __iomem *ioaddr);
 };
 
 struct stmmac_ops {
index a89384c07513ee1acbdb77fb39f413b6b47b95c2..da66ac511c4c60df8dabe849cd02ba9ae2d76dad 100644 (file)
@@ -132,6 +132,11 @@ static void dwmac1000_dump_dma_regs(void __iomem *ioaddr)
        }
 }
 
+static unsigned int dwmac1000_get_hw_feature(void __iomem *ioaddr)
+{
+       return readl(ioaddr + DMA_HW_FEATURE);
+}
+
 const struct stmmac_dma_ops dwmac1000_dma_ops = {
        .init = dwmac1000_dma_init,
        .dump_regs = dwmac1000_dump_dma_regs,
@@ -144,4 +149,5 @@ const struct stmmac_dma_ops dwmac1000_dma_ops = {
        .start_rx = dwmac_dma_start_rx,
        .stop_rx = dwmac_dma_stop_rx,
        .dma_interrupt = dwmac_dma_interrupt,
+       .get_hw_feature = dwmac1000_get_hw_feature,
 };
index da3f5ccf83d300e09d1b7804717ad2c16e722977..437edacd602e2de94ae46dd658fd9fa23f7c1849 100644 (file)
@@ -34,6 +34,7 @@
 #define DMA_MISSED_FRAME_CTR   0x00001020      /* Missed Frame Counter */
 #define DMA_CUR_TX_BUF_ADDR    0x00001050      /* Current Host Tx Buffer */
 #define DMA_CUR_RX_BUF_ADDR    0x00001054      /* Current Host Rx Buffer */
+#define DMA_HW_FEATURE         0x00001058      /* HW Feature Register */
 
 /* DMA Control register defines */
 #define DMA_CONTROL_ST         0x00002000      /* Start/Stop Transmission */
index ef037965493d05b6154a2c13b243223b5e29c387..c3a2da71d1e6427b6bd78479c99e932b8f232f6e 100644 (file)
@@ -78,6 +78,7 @@ struct stmmac_priv {
 #endif
        struct plat_stmmacenet_data *plat;
        struct stmmac_counters mmc;
+       struct dma_features dma_cap;
 };
 
 extern int stmmac_mdio_unregister(struct net_device *ndev);
index eb210ca2497bac813ef540308cff247861faf1af..d0fbc5477d10e72563e8dc679544fdad2b39c056 100644 (file)
@@ -780,6 +780,49 @@ static u32 stmmac_get_synopsys_id(struct stmmac_priv *priv)
        }
        return 0;
 }
+
+/* New GMAC chips support a new register to indicate the
+ * presence of the optional feature/functions.
+ */
+static int stmmac_get_hw_features(struct stmmac_priv *priv)
+{
+       u32 hw_cap = priv->hw->dma->get_hw_feature(priv->ioaddr);
+
+       if (likely(hw_cap)) {
+               priv->dma_cap.mbps_10_100 = (hw_cap & 0x1);
+               priv->dma_cap.mbps_1000 = (hw_cap & 0x2) >> 1;
+               priv->dma_cap.half_duplex = (hw_cap & 0x4) >> 2;
+               priv->dma_cap.hash_filter = (hw_cap & 0x10) >> 4;
+               priv->dma_cap.multi_addr = (hw_cap & 0x20) >> 5;
+               priv->dma_cap.pcs = (hw_cap & 0x40) >> 6;
+               priv->dma_cap.sma_mdio = (hw_cap & 0x100) >> 8;
+               priv->dma_cap.pmt_remote_wake_up = (hw_cap & 0x200) >> 9;
+               priv->dma_cap.pmt_magic_frame = (hw_cap & 0x400) >> 10;
+               priv->dma_cap.rmon = (hw_cap & 0x800) >> 11; /* MMC */
+               /* IEEE 1588-2002*/
+               priv->dma_cap.time_stamp = (hw_cap & 0x1000) >> 12;
+               /* IEEE 1588-2008*/
+               priv->dma_cap.atime_stamp = (hw_cap & 0x2000) >> 13;
+               /* 802.3az - Energy-Efficient Ethernet (EEE) */
+               priv->dma_cap.eee = (hw_cap & 0x4000) >> 14;
+               priv->dma_cap.av = (hw_cap & 0x8000) >> 15;
+               /* TX and RX csum */
+               priv->dma_cap.tx_coe = (hw_cap & 0x10000) >> 16;
+               priv->dma_cap.rx_coe_type1 = (hw_cap & 0x20000) >> 17;
+               priv->dma_cap.rx_coe_type2 = (hw_cap & 0x40000) >> 18;
+               priv->dma_cap.rxfifo_over_2048 = (hw_cap & 0x80000) >> 19;
+               /* TX and RX number of channels */
+               priv->dma_cap.number_rx_channel = (hw_cap & 0x300000) >> 20;
+               priv->dma_cap.number_tx_channel = (hw_cap & 0xc00000) >> 22;
+               /* Alternate (enhanced) DESC mode*/
+               priv->dma_cap.enh_desc = (hw_cap & 0x1000000) >> 24;
+
+       } else
+               pr_debug("\tNo HW DMA feature register supported");
+
+       return hw_cap;
+}
+
 /**
  *  stmmac_open - open entry point of the driver
  *  @dev : pointer to the device structure.
@@ -854,6 +897,8 @@ static int stmmac_open(struct net_device *dev)
 
        stmmac_get_synopsys_id(priv);
 
+       stmmac_get_hw_features(priv);
+
        if (priv->rx_coe)
                pr_info("stmmac: Rx Checksum Offload Engine supported\n");
        if (priv->plat->tx_coe)
@@ -1450,6 +1495,7 @@ static int stmmac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 #ifdef CONFIG_STMMAC_DEBUG_FS
 static struct dentry *stmmac_fs_dir;
 static struct dentry *stmmac_rings_status;
+static struct dentry *stmmac_dma_cap;
 
 static int stmmac_sysfs_ring_read(struct seq_file *seq, void *v)
 {
@@ -1503,6 +1549,78 @@ static const struct file_operations stmmac_rings_status_fops = {
        .release = seq_release,
 };
 
+static int stmmac_sysfs_dma_cap_read(struct seq_file *seq, void *v)
+{
+       struct net_device *dev = seq->private;
+       struct stmmac_priv *priv = netdev_priv(dev);
+
+       if (!stmmac_get_hw_features(priv)) {
+               seq_printf(seq, "DMA HW features not supported\n");
+               return 0;
+       }
+
+       seq_printf(seq, "==============================\n");
+       seq_printf(seq, "\tDMA HW features\n");
+       seq_printf(seq, "==============================\n");
+
+       seq_printf(seq, "\t10/100 Mbps %s\n",
+                  (priv->dma_cap.mbps_10_100) ? "Y" : "N");
+       seq_printf(seq, "\t1000 Mbps %s\n",
+                  (priv->dma_cap.mbps_1000) ? "Y" : "N");
+       seq_printf(seq, "\tHalf duple %s\n",
+                  (priv->dma_cap.half_duplex) ? "Y" : "N");
+       seq_printf(seq, "\tHash Filter: %s\n",
+                  (priv->dma_cap.hash_filter) ? "Y" : "N");
+       seq_printf(seq, "\tMultiple MAC address registers: %s\n",
+                  (priv->dma_cap.multi_addr) ? "Y" : "N");
+       seq_printf(seq, "\tPCS (TBI/SGMII/RTBI PHY interfatces): %s\n",
+                  (priv->dma_cap.pcs) ? "Y" : "N");
+       seq_printf(seq, "\tSMA (MDIO) Interface: %s\n",
+                  (priv->dma_cap.sma_mdio) ? "Y" : "N");
+       seq_printf(seq, "\tPMT Remote wake up: %s\n",
+                  (priv->dma_cap.pmt_remote_wake_up) ? "Y" : "N");
+       seq_printf(seq, "\tPMT Magic Frame: %s\n",
+                  (priv->dma_cap.pmt_magic_frame) ? "Y" : "N");
+       seq_printf(seq, "\tRMON module: %s\n",
+                  (priv->dma_cap.rmon) ? "Y" : "N");
+       seq_printf(seq, "\tIEEE 1588-2002 Time Stamp: %s\n",
+                  (priv->dma_cap.time_stamp) ? "Y" : "N");
+       seq_printf(seq, "\tIEEE 1588-2008 Advanced Time Stamp:%s\n",
+                  (priv->dma_cap.atime_stamp) ? "Y" : "N");
+       seq_printf(seq, "\t802.3az - Energy-Efficient Ethernet (EEE) %s\n",
+                  (priv->dma_cap.eee) ? "Y" : "N");
+       seq_printf(seq, "\tAV features: %s\n", (priv->dma_cap.av) ? "Y" : "N");
+       seq_printf(seq, "\tChecksum Offload in TX: %s\n",
+                  (priv->dma_cap.tx_coe) ? "Y" : "N");
+       seq_printf(seq, "\tIP Checksum Offload (type1) in RX: %s\n",
+                  (priv->dma_cap.rx_coe_type1) ? "Y" : "N");
+       seq_printf(seq, "\tIP Checksum Offload (type2) in RX: %s\n",
+                  (priv->dma_cap.rx_coe_type2) ? "Y" : "N");
+       seq_printf(seq, "\tRXFIFO > 2048bytes: %s\n",
+                  (priv->dma_cap.rxfifo_over_2048) ? "Y" : "N");
+       seq_printf(seq, "\tNumber of Additional RX channel: %d\n",
+                  priv->dma_cap.number_rx_channel);
+       seq_printf(seq, "\tNumber of Additional TX channel: %d\n",
+                  priv->dma_cap.number_tx_channel);
+       seq_printf(seq, "\tEnhanced descriptors: %s\n",
+                  (priv->dma_cap.enh_desc) ? "Y" : "N");
+
+       return 0;
+}
+
+static int stmmac_sysfs_dma_cap_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, stmmac_sysfs_dma_cap_read, inode->i_private);
+}
+
+static const struct file_operations stmmac_dma_cap_fops = {
+       .owner = THIS_MODULE,
+       .open = stmmac_sysfs_dma_cap_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release,
+};
+
 static int stmmac_init_fs(struct net_device *dev)
 {
        /* Create debugfs entries */
@@ -1527,12 +1645,25 @@ static int stmmac_init_fs(struct net_device *dev)
                return -ENOMEM;
        }
 
+       /* Entry to report the DMA HW features */
+       stmmac_dma_cap = debugfs_create_file("dma_cap", S_IRUGO, stmmac_fs_dir,
+                                            dev, &stmmac_dma_cap_fops);
+
+       if (!stmmac_dma_cap || IS_ERR(stmmac_dma_cap)) {
+               pr_info("ERROR creating stmmac MMC debugfs file\n");
+               debugfs_remove(stmmac_rings_status);
+               debugfs_remove(stmmac_fs_dir);
+
+               return -ENOMEM;
+       }
+
        return 0;
 }
 
 static void stmmac_exit_fs(void)
 {
        debugfs_remove(stmmac_rings_status);
+       debugfs_remove(stmmac_dma_cap);
        debugfs_remove(stmmac_fs_dir);
 }
 #endif /* CONFIG_STMMAC_DEBUG_FS */