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;