Add ability to read some mib values.

The code from marvel only writes mib stat values to the console which
is less than useful.  Provide a way to read the stats we care about.

Change-Id: I28766441e1004de2e34623e44a5f1c9f2bcd4a04
diff --git a/arch/arm/plat-feroceon/mv_drivers_lsp/mv_neta/net_dev/Makefile b/arch/arm/plat-feroceon/mv_drivers_lsp/mv_neta/net_dev/Makefile
index 866029a..627471c 100755
--- a/arch/arm/plat-feroceon/mv_drivers_lsp/mv_neta/net_dev/Makefile
+++ b/arch/arm/plat-feroceon/mv_drivers_lsp/mv_neta/net_dev/Makefile
@@ -16,12 +16,14 @@
 
 ifeq ($(CONFIG_MV_ETH_NFP_LIB),y)
 	obj-$(CONFIG_MV_ETHERNET) += mv_netdev.o mv_ethernet.o mv_eth_sysfs.o
+	obj-$(CONFIG_MV_ETHERNET) += goog_eth_sysfs.o
 	obj-$(CONFIG_MV_PON)      += mv_pon_sysfs.o
 	obj-$(CONFIG_MV_ETH_SWITCH) +=  mv_eth_switch.o
 	obj-$(CONFIG_MV_ETH_TOOL) += mv_eth_tool.o
 	obj-y += ../nfplib.a
 else
 	obj-$(CONFIG_MV_ETHERNET) += mv_netdev.o mv_ethernet.o mv_eth_sysfs.o
+	obj-$(CONFIG_MV_ETHERNET) += goog_eth_sysfs.o
 	obj-$(CONFIG_MV_PON)      += mv_pon_sysfs.o
 	obj-$(CONFIG_MV_ETH_SWITCH) +=  mv_eth_switch.o
 	obj-$(CONFIG_MV_ETH_TOOL) += mv_eth_tool.o
diff --git a/arch/arm/plat-feroceon/mv_drivers_lsp/mv_neta/net_dev/goog_eth_sysfs.c b/arch/arm/plat-feroceon/mv_drivers_lsp/mv_neta/net_dev/goog_eth_sysfs.c
new file mode 100755
index 0000000..a359ad5
--- /dev/null
+++ b/arch/arm/plat-feroceon/mv_drivers_lsp/mv_neta/net_dev/goog_eth_sysfs.c
@@ -0,0 +1,145 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) Google, 2013
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/capability.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/netdevice.h>
+
+#include "gbe/mvNeta.h"
+#include "mv_netdev.h"
+
+struct goog_net_attribute {
+	struct device_attribute dev_attr;
+	uint64_t val;
+	uint32_t mib;
+	uint32_t port;
+};
+
+#define GOOG_ATTR(_name, _portname, _show, _mib, _port)                 \
+		struct goog_net_attribute goog_attr_##_name##_##_portname = {      \
+			.dev_attr = __ATTR(_name, S_IRUSR, _show, NULL), \
+			.mib= _mib,                             \
+			.port = _port,                                   \
+		}
+
+static ssize_t goog_get_stat(struct device *dev,
+							 struct device_attribute *attr, char *buf)
+{
+	MV_U32 reg_low, reg_high = 0;
+	uint64_t reg_val;
+	struct goog_net_attribute *goog_attr = container_of(attr, struct goog_net_attribute, dev_attr);
+        // These mib registers are clear on read.
+	reg_low = mvNetaMibCounterRead(goog_attr->port, 0, goog_attr->mib, &reg_high);
+	reg_val = ((uint64_t)reg_high) << 32 | (uint64_t)reg_low;
+	goog_attr->val += reg_val;
+	return sprintf(buf, "%llu\n", goog_attr->val);
+}
+
+// Stats for the UNI port.
+static GOOG_ATTR(rx_good_packets, uni, goog_get_stat, ETH_MIB_GOOD_FRAMES_RECEIVED, 0);
+static GOOG_ATTR(rx_bad_packets, uni, goog_get_stat, ETH_MIB_BAD_FRAMES_RECEIVED, 0);
+static GOOG_ATTR(rx_broadcast_packets, uni, goog_get_stat, ETH_MIB_BROADCAST_FRAMES_RECEIVED, 0);
+static GOOG_ATTR(rx_multicast_packets, uni, goog_get_stat, ETH_MIB_MULTICAST_FRAMES_RECEIVED, 0);
+static GOOG_ATTR(tx_good_packets, uni, goog_get_stat, ETH_MIB_GOOD_FRAMES_SENT, 0);
+static GOOG_ATTR(tx_broadcast_packets, uni, goog_get_stat, ETH_MIB_BROADCAST_FRAMES_SENT, 0);
+static GOOG_ATTR(tx_multicast_packets, uni, goog_get_stat, ETH_MIB_MULTICAST_FRAMES_SENT, 0);
+
+static struct attribute *goog_uni_attrs[] = {
+	&goog_attr_rx_good_packets_uni.dev_attr.attr,
+	&goog_attr_rx_bad_packets_uni.dev_attr.attr,
+	&goog_attr_rx_multicast_packets_uni.dev_attr.attr,
+	&goog_attr_rx_broadcast_packets_uni.dev_attr.attr,
+	&goog_attr_tx_good_packets_uni.dev_attr.attr,
+	&goog_attr_tx_broadcast_packets_uni.dev_attr.attr,
+	&goog_attr_tx_multicast_packets_uni.dev_attr.attr,
+	NULL
+};
+
+
+static struct attribute_group goog_uni_stats = {
+	.name = "unistats",
+	.attrs = goog_uni_attrs,
+};
+
+
+// Stats for the ANI port.
+static GOOG_ATTR(rx_good_packets, ani, goog_get_stat, ETH_MIB_GOOD_FRAMES_RECEIVED, MV_PON_PORT_ID);
+static GOOG_ATTR(rx_bad_packets, ani, goog_get_stat, ETH_MIB_BAD_FRAMES_RECEIVED, MV_PON_PORT_ID);
+static GOOG_ATTR(rx_broadcast_packets, ani, goog_get_stat, ETH_MIB_BROADCAST_FRAMES_RECEIVED, MV_PON_PORT_ID);
+static GOOG_ATTR(rx_multicast_packets, ani, goog_get_stat, ETH_MIB_MULTICAST_FRAMES_RECEIVED, MV_PON_PORT_ID);
+static GOOG_ATTR(tx_good_packets, ani, goog_get_stat, ETH_MIB_GOOD_FRAMES_SENT, MV_PON_PORT_ID);
+static GOOG_ATTR(tx_broadcast_packets, ani, goog_get_stat, ETH_MIB_BROADCAST_FRAMES_SENT, MV_PON_PORT_ID);
+static GOOG_ATTR(tx_multicast_packets, ani, goog_get_stat, ETH_MIB_MULTICAST_FRAMES_SENT, MV_PON_PORT_ID);
+
+static struct attribute *goog_ani_attrs[] = {
+	&goog_attr_rx_good_packets_ani.dev_attr.attr,
+	&goog_attr_rx_bad_packets_ani.dev_attr.attr,
+	&goog_attr_rx_multicast_packets_ani.dev_attr.attr,
+	&goog_attr_rx_broadcast_packets_ani.dev_attr.attr,
+	&goog_attr_tx_good_packets_ani.dev_attr.attr,
+	&goog_attr_tx_broadcast_packets_ani.dev_attr.attr,
+	&goog_attr_tx_multicast_packets_ani.dev_attr.attr,
+	NULL
+};
+
+static struct attribute_group goog_ani_stats = {
+	.name = "anistats",
+	.attrs = goog_ani_attrs,
+};
+
+int __devinit goog_eth_sysfs_init(void)
+{
+	int err = 0;
+	struct device *pd = NULL;
+
+	pd = bus_find_device_by_name(&platform_bus_type, NULL, "neta");
+	if (!pd) {
+		platform_device_register_simple("neta", -1, NULL, 0);
+		pd = bus_find_device_by_name(&platform_bus_type, NULL, "neta");
+	}
+
+	if (!pd) {
+		printk(KERN_ERR"%s: cannot find neta device\n", __func__);
+		pd = &platform_bus;
+	}
+
+	err = sysfs_create_group(&pd->kobj, &goog_uni_stats);
+	if (err) {
+		printk(KERN_INFO "sysfs group failed %d\n", err);
+		goto out;
+	}
+
+	err = sysfs_create_group(&pd->kobj, &goog_ani_stats);
+	if (err) {
+		printk(KERN_INFO "sysfs group failed %d\n", err);
+		goto out;
+	}
+out:
+	return err;
+}
+
+
+
+module_init(goog_eth_sysfs_init);
+
+MODULE_AUTHOR("jnewlin@google.com");
+MODULE_DESCRIPTION("Readable netstats for Marvell 6601.");
+MODULE_LICENSE("GPL");