OpenWrt Forum Archive

Topic: Ethtool support for ixp4xx

The content of this topic has been archived on 17 Apr 2018. There are no obvious gaps in this topic, but there may still be some posts missing at the end.

Hey All;

I'm doing a quick patch to enable ethtool support for the ixp4xx ethernet driver  ( for kernel 2.6.26.8 ).
I've got the basics working,  right now I'm working enabling extended statistics support.

I just need to port the dma all forward from the old driver.

From the old driver:

static void get_npe_stats(struct port *port, u32 *buf, int len)
{
    struct npe *npe = port->npe;
    u32 phys;

    memset(buf, len, 0);
    phys = dma_map_single(mac->npe_dev, buf, len, DMA_BIDIRECTIONAL);
    npe_get_stats(npe, port->plat, phys);
    dma_unmap_single(mac->npe_dev, phys, len, DMA_BIDIRECTIONAL);
}

just need to forward port the 2 dma calls.
Any suggestions?

GPW

Here's what I've got so far.
=============================================
--- linux-2.6.26.8/drivers/net/arm/ixp4xx_eth.c    2009-01-06 23:51:31.000000000 -0800
+++ linux-2.6.26.8_new/drivers/net/arm/ixp4xx_eth.c    2009-01-25 19:46:53.000000000 -0800
@@ -29,10 +29,11 @@
#include <linux/dmapool.h>
#include <linux/etherdevice.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/mii.h>
+#include <linux/ethtool.h>
#include <linux/platform_device.h>
#include <asm/arch/cpu.h>
#include <asm/arch/npe.h>
#include <asm/arch/qmgr.h>

@@ -43,10 +44,11 @@
#define DEBUG_PKT_BYTES        0
#define DEBUG_MDIO        0
#define DEBUG_CLOSE        0

#define DRV_NAME        "ixp4xx_eth"
+#define DRV_VERSION        "0.1.0"

#define MAX_NPES        3

#define RX_DESCS        64 /* also length of all RX queues */
#define TX_DESCS        16 /* also length of all TX queues */
@@ -363,10 +365,12 @@

}

static void eth_set_duplex(struct port *port, int full_duplex)
{
+    printk( KERN_ERR " ETH-DRV: %s:  called on port id: %d  set to %s \n",
+        __func__, port->id, ((full_duplex)?"FULL DUPLEX":"HALF DUPLEX") );
    if (full_duplex)
        __raw_writel(DEFAULT_TX_CNTRL0 & ~TX_CNTRL0_HALFDUPLEX,
                 &port->regs->tx_control[0]);
    else
        __raw_writel(DEFAULT_TX_CNTRL0 | TX_CNTRL0_HALFDUPLEX,
@@ -1237,10 +1241,162 @@
                eth_add_phy(dev, i);
    }

}

+static void ixp4xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+    strcpy(info->driver, DRV_NAME);
+    strcpy(info->version, DRV_VERSION);
+}
+
+static int ixp4xx_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+    struct port *port = netdev_priv(dev);
+    return mii_ethtool_gset(&port->mii[0], cmd);
+}
+
+static int ixp4xx_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+    struct port *port = netdev_priv(dev);
+    return mii_ethtool_sset(&port->mii[0], cmd);
+}
+
+static int ixp4xx_nway_reset(struct net_device *dev)
+{
+    struct port *port = netdev_priv(dev);
+    return mii_nway_restart(&port->mii[0]);
+}
+
+static u32 ixp4xx_get_link(struct net_device *dev)
+{
+    struct port *port = netdev_priv(dev);
+    return mii_link_ok(&port->mii[0]);
+}
+
+#define NPE_Q_STAT_NUM 4
+#define NPE_STAT_NUM 34
+#define NPE_Q_STAT_STRINGS \
+    {"RX ready to use queue len     "}, \
+    {"RX received queue len         "}, \
+    {"TX to be send queue len       "}, \
+    {"TX done queue len             "},
+
+#define NPE_STAT_STRINGS \
+    {"StatsAlignmentErrors          "}, \
+    {"StatsFCSErrors                "}, \
+    {"StatsInternalMacReceiveErrors "}, \
+    {"RxOverrunDiscards             "}, \
+    {"RxLearnedEntryDiscards        "}, \
+    {"RxLargeFramesDiscards         "}, \
+    {"RxSTPBlockedDiscards          "}, \
+    {"RxVLANTypeFilterDiscards      "}, \
+    {"RxVLANIdFilterDiscards        "}, \
+    {"RxInvalidSourceDiscards       "}, \
+    {"RxBlackListDiscards           "}, \
+    {"RxWhiteListDiscards           "}, \
+    {"RxUnderflowEntryDiscards      "}, \
+    {"StatsSingleCollisionFrames    "}, \
+    {"StatsMultipleCollisionFrames  "}, \
+    {"StatsDeferredTransmissions    "}, \
+    {"StatsLateCollisions           "}, \
+    {"StatsExcessiveCollsions       "}, \
+    {"StatsInternalMacTransmitErrors"}, \
+    {"StatsCarrierSenseErrors       "}, \
+    {"TxLargeFrameDiscards          "}, \
+    {"TxVLANIdFilterDiscards        "}, \
+\
+    {"RxValidFramesTotalOctets      "}, \
+    {"RxUcastPkts                   "}, \
+    {"RxBcastPkts                   "}, \
+    {"RxMcastPkts                   "}, \
+    {"RxPkts64Octets                "}, \
+    {"RxPkts65to127Octets           "}, \
+    {"RxPkts128to255Octets          "}, \
+    {"RxPkts256to511Octets          "}, \
+    {"RxPkts512to1023Octets         "}, \
+    {"RxPkts1024to1518Octets        "}, \
+    {"RxInternalNPEReceiveErrors    "}, \
+    {"TxInternalNPETransmitErrors   "}
+
+static struct {
+    const char str[ETH_GSTRING_LEN];
+} ethtool_stats_keys[NPE_STAT_NUM + NPE_Q_STAT_NUM] = {
+    NPE_Q_STAT_STRINGS
+    NPE_STAT_STRINGS
+};
+
+static void ixp4xx_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+    struct port *port = netdev_priv(dev);
+    printk( KERN_CRIT "%s: Copying ethtool strings to user space: %d strings of size %d \n", __func__ ,
+        (NPE_STAT_NUM+NPE_Q_STAT_NUM) , ETH_GSTRING_LEN);
+    memcpy(data, ethtool_stats_keys, (NPE_STAT_NUM+NPE_Q_STAT_NUM) * ETH_GSTRING_LEN);
+}
+
+static int ixp4xx_get_stats_count(struct net_device *dev)
+{
+    //struct port *port = netdev_priv(dev);
+    /*FIXME: See CH driver for satus ajustment */
+    printk( KERN_CRIT " %s:  stats count called : %d \n", __func__, (NPE_STAT_NUM+NPE_Q_STAT_NUM) );
+    return (NPE_STAT_NUM+NPE_Q_STAT_NUM);
+}
+
+/*
+int npe_get_stats(struct npe *npe, struct eth_plat_info *mp, u32 phys)
+{
+    struct npe_mh_msg msg;
+    memset(&msg, 0, sizeof(msg));
+    msg.u.byte[0] = NPE_GETSTATS;
+    msg.u.byte[1] = logical_id(mp);
+    msg.u.data[1] = cpu_to_npe32(cpu_to_be32(phys));
+    return npe_send_recv_message(npe, &msg, "ETH_GET_STATS");
+}
+
+static void get_npe_stats(struct port *port, u32 *buf, int len)
+{
+    struct npe *npe = port->npe;
+    u32 phys;
+
+    memset(buf, len, 0);
+    phys = dma_map_single(mac->npe_dev, buf, len, DMA_BIDIRECTIONAL);
+    npe_get_stats(npe, port->plat, phys);
+    dma_unmap_single(mac->npe_dev, phys, len, DMA_BIDIRECTIONAL);
+}
+*/
+static void ixp4xx_get_ethtool_stats(struct net_device *dev,
+        struct ethtool_stats *stats, u64 *data)
+{
+    int i;
+    struct port *port = netdev_priv(dev);
+    u32 buf[NPE_STAT_NUM];
+   
+    // must re-work these queue length settings
+    data[0] = 0;
+    data[1] = 0;
+    data[2] = 0;
+    data[3] = 0;
+    //get_npe_stats(port, buf, sizeof(buf), 0);
+   
+    for (i=0; (i<(stats->n_stats-4)) && (i<NPE_STAT_NUM); i++) {
+        data[i+4] = buf[i];
+    }
+}
+
+
+static struct ethtool_ops ixp4xx_ethtool_ops = {
+    .get_drvinfo        = ixp4xx_get_drvinfo,
+    .get_settings        = ixp4xx_get_settings,
+    .set_settings        = ixp4xx_set_settings,
+    .nway_reset        = ixp4xx_nway_reset,
+    .get_link        = ixp4xx_get_link,
+    .get_strings        = ixp4xx_get_strings,
+    .get_stats_count    = ixp4xx_get_stats_count,
+    .get_ethtool_stats    = ixp4xx_get_ethtool_stats,
+};
+
+
static int __devinit eth_init_one(struct platform_device *pdev)
{
    struct port *port;
    struct net_device *dev;
    struct eth_plat_info *plat = pdev->dev.platform_data;
@@ -1271,10 +1427,11 @@
    default:
        err = -ENOSYS;
        goto err_free;
    }

+    dev->ethtool_ops = &ixp4xx_ethtool_ops;
    dev->open = eth_open;
    dev->hard_start_xmit = eth_xmit;
    dev->stop = eth_close;
    dev->get_stats = eth_stats;
    dev->do_ioctl = eth_ioctl;

Wow;

Was that an adventure.

I can't see a way to port those 2 DMA calls forward  to the new driver.
Anyone have any ideas? 

I'd like to get the statistics operation working with the new driver.

GPW

The discussion might have continued from here.