All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 -next 1/4] tg3: Add common function tg3_ape_event_lock()
@ 2012-06-27  0:53 Michael Chan
  2012-06-27  0:53 ` [PATCH v2 -next 2/4] tg3: Add APE scratchpad read and write functions Michael Chan
  0 siblings, 1 reply; 8+ messages in thread
From: Michael Chan @ 2012-06-27  0:53 UTC (permalink / raw)
  To: davem; +Cc: netdev, nsujir

From: Matt Carlson <mcarlson@broadcom.com>

by refactoring code in tg3_ape_send_event().  The common function will
be used in subsequent patches.

Signed-off-by: Matt Carlson <mcarlson@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
---
 drivers/net/ethernet/broadcom/tg3.c |   56 ++++++++++++++++++++---------------
 1 files changed, 32 insertions(+), 24 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index e47ff8b..7c515db 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -730,44 +730,52 @@ static void tg3_ape_unlock(struct tg3 *tp, int locknum)
 	tg3_ape_write32(tp, gnt + 4 * locknum, bit);
 }
 
-static void tg3_ape_send_event(struct tg3 *tp, u32 event)
+static int tg3_ape_event_lock(struct tg3 *tp, u32 timeout_us)
 {
-	int i;
 	u32 apedata;
 
-	/* NCSI does not support APE events */
-	if (tg3_flag(tp, APE_HAS_NCSI))
-		return;
+	while (timeout_us) {
+		if (tg3_ape_lock(tp, TG3_APE_LOCK_MEM))
+			return -EBUSY;
+
+		apedata = tg3_ape_read32(tp, TG3_APE_EVENT_STATUS);
+		if (!(apedata & APE_EVENT_STATUS_EVENT_PENDING))
+			break;
+
+		tg3_ape_unlock(tp, TG3_APE_LOCK_MEM);
+
+		udelay(10);
+		timeout_us -= (timeout_us > 10) ? 10 : timeout_us;
+	}
+
+	return timeout_us ? 0 : -EBUSY;
+}
+
+static int tg3_ape_send_event(struct tg3 *tp, u32 event)
+{
+	int err;
+	u32 apedata;
 
 	apedata = tg3_ape_read32(tp, TG3_APE_SEG_SIG);
 	if (apedata != APE_SEG_SIG_MAGIC)
-		return;
+		return -EAGAIN;
 
 	apedata = tg3_ape_read32(tp, TG3_APE_FW_STATUS);
 	if (!(apedata & APE_FW_STATUS_READY))
-		return;
+		return -EAGAIN;
 
 	/* Wait for up to 1 millisecond for APE to service previous event. */
-	for (i = 0; i < 10; i++) {
-		if (tg3_ape_lock(tp, TG3_APE_LOCK_MEM))
-			return;
-
-		apedata = tg3_ape_read32(tp, TG3_APE_EVENT_STATUS);
-
-		if (!(apedata & APE_EVENT_STATUS_EVENT_PENDING))
-			tg3_ape_write32(tp, TG3_APE_EVENT_STATUS,
-					event | APE_EVENT_STATUS_EVENT_PENDING);
+	err = tg3_ape_event_lock(tp, 1000);
+	if (err)
+		return err;
 
-		tg3_ape_unlock(tp, TG3_APE_LOCK_MEM);
+	tg3_ape_write32(tp, TG3_APE_EVENT_STATUS,
+			event | APE_EVENT_STATUS_EVENT_PENDING);
 
-		if (!(apedata & APE_EVENT_STATUS_EVENT_PENDING))
-			break;
+	tg3_ape_unlock(tp, TG3_APE_LOCK_MEM);
+	tg3_ape_write32(tp, TG3_APE_EVENT, APE_EVENT_1);
 
-		udelay(100);
-	}
-
-	if (!(apedata & APE_EVENT_STATUS_EVENT_PENDING))
-		tg3_ape_write32(tp, TG3_APE_EVENT, APE_EVENT_1);
+	return 0;
 }
 
 static void tg3_ape_driver_state_change(struct tg3 *tp, int kind)
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 -next 2/4] tg3: Add APE scratchpad read and write functions.
  2012-06-27  0:53 [PATCH v2 -next 1/4] tg3: Add common function tg3_ape_event_lock() Michael Chan
@ 2012-06-27  0:53 ` Michael Chan
  2012-06-27  0:53   ` [PATCH v2 -next 3/4] tg3: Add hwmon support Michael Chan
  0 siblings, 1 reply; 8+ messages in thread
From: Michael Chan @ 2012-06-27  0:53 UTC (permalink / raw)
  To: davem; +Cc: netdev, nsujir

From: Matt Carlson <mcarlson@broadcom.com>

Signed-off-by: Matt Carlson <mcarlson@broadcom.com>
Signed-off-by: Nithin Nayak Sujir <nsujir@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
---
 drivers/net/ethernet/broadcom/tg3.c |  137 +++++++++++++++++++++++++++++++++++
 drivers/net/ethernet/broadcom/tg3.h |   10 ++-
 2 files changed, 145 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index 7c515db..693a584 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -751,6 +751,143 @@ static int tg3_ape_event_lock(struct tg3 *tp, u32 timeout_us)
 	return timeout_us ? 0 : -EBUSY;
 }
 
+static int tg3_ape_wait_for_event(struct tg3 *tp, u32 timeout_us)
+{
+	u32 i, apedata;
+
+	for (i = 0; i < timeout_us / 10; i++) {
+		apedata = tg3_ape_read32(tp, TG3_APE_EVENT_STATUS);
+
+		if (!(apedata & APE_EVENT_STATUS_EVENT_PENDING))
+			break;
+
+		udelay(10);
+	}
+
+	return i == timeout_us / 10;
+}
+
+int tg3_ape_scratchpad_read(struct tg3 *tp, u32 *data, u32 base_off, u32 len)
+{
+	int err;
+	u32 i, bufoff, msgoff, maxlen, apedata;
+
+	if (!tg3_flag(tp, APE_HAS_NCSI))
+		return 0;
+
+	apedata = tg3_ape_read32(tp, TG3_APE_SEG_SIG);
+	if (apedata != APE_SEG_SIG_MAGIC)
+		return -ENODEV;
+
+	apedata = tg3_ape_read32(tp, TG3_APE_FW_STATUS);
+	if (!(apedata & APE_FW_STATUS_READY))
+		return -EAGAIN;
+
+	bufoff = tg3_ape_read32(tp, TG3_APE_SEG_MSG_BUF_OFF) +
+		 TG3_APE_SHMEM_BASE;
+	msgoff = bufoff + 2 * sizeof(u32);
+	maxlen = tg3_ape_read32(tp, TG3_APE_SEG_MSG_BUF_LEN);
+
+	while (len) {
+		u32 length;
+
+		/* Cap xfer sizes to scratchpad limits. */
+		length = (len > maxlen) ? maxlen : len;
+		len -= length;
+
+		apedata = tg3_ape_read32(tp, TG3_APE_FW_STATUS);
+		if (!(apedata & APE_FW_STATUS_READY))
+			return -EAGAIN;
+
+		/* Wait for up to 1 msec for APE to service previous event. */
+		err = tg3_ape_event_lock(tp, 1000);
+		if (err)
+			return err;
+
+		apedata = APE_EVENT_STATUS_DRIVER_EVNT |
+			  APE_EVENT_STATUS_SCRTCHPD_READ |
+			  APE_EVENT_STATUS_EVENT_PENDING;
+		tg3_ape_write32(tp, TG3_APE_EVENT_STATUS, apedata);
+
+		tg3_ape_write32(tp, bufoff, base_off);
+		tg3_ape_write32(tp, bufoff + sizeof(u32), length);
+
+		tg3_ape_unlock(tp, TG3_APE_LOCK_MEM);
+		tg3_ape_write32(tp, TG3_APE_EVENT, APE_EVENT_1);
+
+		base_off += length;
+
+		if (tg3_ape_wait_for_event(tp, 30000))
+			return -EAGAIN;
+
+		for (i = 0; length; i += 4, length -= 4) {
+			u32 val = tg3_ape_read32(tp, msgoff + i);
+			memcpy(data, &val, sizeof(u32));
+			data++;
+		}
+	}
+
+	return 0;
+}
+
+int tg3_ape_scratchpad_write(struct tg3 *tp, u32 dstoff, u32 *data, u32 len)
+{
+	u32 i, bufoff, msgoff, maxlen, apedata;
+
+	if (!tg3_flag(tp, APE_HAS_NCSI))
+		return 0;
+
+	apedata = tg3_ape_read32(tp, TG3_APE_SEG_SIG);
+	if (apedata != APE_SEG_SIG_MAGIC)
+		return -ENODEV;
+
+	apedata = tg3_ape_read32(tp, TG3_APE_FW_STATUS);
+	if (!(apedata & APE_FW_STATUS_READY))
+		return -EAGAIN;
+
+	bufoff = tg3_ape_read32(tp, TG3_APE_SEG_MSG_BUF_OFF) +
+		 TG3_APE_SHMEM_BASE;
+	msgoff = bufoff + 2 * sizeof(u32);
+	maxlen = tg3_ape_read32(tp, TG3_APE_SEG_MSG_BUF_LEN);
+
+	while (len) {
+		int err;
+		u32 length;
+
+		/* Cap xfer sizes to scratchpad limits. */
+		length = (len > maxlen) ? maxlen : len;
+		len -= length;
+
+		/* Wait for up to 1 millisecond for
+		 * APE to service previous event.
+		 */
+		err = tg3_ape_event_lock(tp, 1000);
+		if (err)
+			return err;
+
+		tg3_ape_write32(tp, bufoff, dstoff);
+		tg3_ape_write32(tp, bufoff + sizeof(u32), length);
+		apedata = msgoff;
+
+		dstoff += length;
+
+		for (i = 0; length; i += 4, length -= sizeof(u32)) {
+			tg3_ape_write32(tp, apedata, *data++);
+			apedata += sizeof(u32);
+		}
+
+		apedata = APE_EVENT_STATUS_DRIVER_EVNT |
+			  APE_EVENT_STATUS_SCRTCHPD_WRITE |
+			  APE_EVENT_STATUS_EVENT_PENDING;
+		tg3_ape_write32(tp, TG3_APE_EVENT_STATUS, apedata);
+
+		tg3_ape_unlock(tp, TG3_APE_LOCK_MEM);
+		tg3_ape_write32(tp, TG3_APE_EVENT, APE_EVENT_1);
+	}
+
+	return 0;
+}
+
 static int tg3_ape_send_event(struct tg3 *tp, u32 event)
 {
 	int err;
diff --git a/drivers/net/ethernet/broadcom/tg3.h b/drivers/net/ethernet/broadcom/tg3.h
index 93865f8..d167a1c 100644
--- a/drivers/net/ethernet/broadcom/tg3.h
+++ b/drivers/net/ethernet/broadcom/tg3.h
@@ -2311,10 +2311,12 @@
 #define  APE_LOCK_REQ_DRIVER		 0x00001000
 #define TG3_APE_LOCK_GRANT		0x004c
 #define  APE_LOCK_GRANT_DRIVER		 0x00001000
-#define TG3_APE_SEG_SIG			0x4000
-#define  APE_SEG_SIG_MAGIC		 0x41504521
+#define TG3_APE_STICKY_TMR		0x00b0
 
 /* APE shared memory.  Accessible through BAR1 */
+#define TG3_APE_SHMEM_BASE		0x4000
+#define TG3_APE_SEG_SIG			0x4000
+#define  APE_SEG_SIG_MAGIC		 0x41504521
 #define TG3_APE_FW_STATUS		0x400c
 #define  APE_FW_STATUS_READY		 0x00000100
 #define TG3_APE_FW_FEATURES		0x4010
@@ -2327,6 +2329,8 @@
 #define  APE_FW_VERSION_REVMSK		 0x0000ff00
 #define  APE_FW_VERSION_REVSFT		 8
 #define  APE_FW_VERSION_BLDMSK		 0x000000ff
+#define TG3_APE_SEG_MSG_BUF_OFF		0x401c
+#define TG3_APE_SEG_MSG_BUF_LEN		0x4020
 #define TG3_APE_HOST_SEG_SIG		0x4200
 #define  APE_HOST_SEG_SIG_MAGIC		 0x484f5354
 #define TG3_APE_HOST_SEG_LEN		0x4204
@@ -2353,6 +2357,8 @@
 
 #define  APE_EVENT_STATUS_DRIVER_EVNT	 0x00000010
 #define  APE_EVENT_STATUS_STATE_CHNGE	 0x00000500
+#define  APE_EVENT_STATUS_SCRTCHPD_READ	 0x00001600
+#define  APE_EVENT_STATUS_SCRTCHPD_WRITE 0x00001700
 #define  APE_EVENT_STATUS_STATE_START	 0x00010000
 #define  APE_EVENT_STATUS_STATE_UNLOAD	 0x00020000
 #define  APE_EVENT_STATUS_STATE_WOL	 0x00030000
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 -next 3/4] tg3: Add hwmon support
  2012-06-27  0:53 ` [PATCH v2 -next 2/4] tg3: Add APE scratchpad read and write functions Michael Chan
@ 2012-06-27  0:53   ` Michael Chan
  2012-06-27  0:53     ` [PATCH v2 -next 4/4] tg3: Add binary sysfs file to export bulk sensor data Michael Chan
  0 siblings, 1 reply; 8+ messages in thread
From: Michael Chan @ 2012-06-27  0:53 UTC (permalink / raw)
  To: davem; +Cc: netdev, nsujir

Some tg3 devices have management firmware that can export sensor data such
as temperature and other real time diagnostics data.  Export temperature
sensor reading via hwmon sysfs.

[hwmon interface suggested by Ben Hutchings <bhutchings@solarflare.com>]

Signed-off-by: Matt Carlson <mcarlson@broadcom.com>
Signed-off-by: Nithin Nayak Sujir <nsujir@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
---
 drivers/net/ethernet/broadcom/tg3.c |  189 +++++++++++++++++++++++++++++++++++
 drivers/net/ethernet/broadcom/tg3.h |   63 ++++++++++++
 2 files changed, 252 insertions(+), 0 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index 693a584..6b51e3a 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -44,6 +44,10 @@
 #include <linux/prefetch.h>
 #include <linux/dma-mapping.h>
 #include <linux/firmware.h>
+#if IS_ENABLED(CONFIG_HWMON)
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#endif
 
 #include <net/checksum.h>
 #include <net/ip.h>
@@ -9538,6 +9542,182 @@ static int tg3_init_hw(struct tg3 *tp, int reset_phy)
 	return tg3_reset_hw(tp, reset_phy);
 }
 
+static void tg3_sd_scan_scratchpad(struct tg3 *tp, struct tg3_ocir *ocir)
+{
+	int i;
+
+	for (i = 0; i < TG3_SD_NUM_RECS; i++, ocir++) {
+		u32 off = i * TG3_OCIR_LEN, len = TG3_OCIR_LEN;
+
+		tg3_ape_scratchpad_read(tp, (u32 *) ocir, off, len);
+		off += len;
+
+		if (ocir->signature != TG3_OCIR_SIG_MAGIC ||
+		    !(ocir->version_flags & TG3_OCIR_FLAG_ACTIVE))
+			memset(ocir, 0, TG3_OCIR_LEN);
+	}
+}
+
+#if IS_ENABLED(CONFIG_HWMON)
+/* sysfs attributes for hwmon */
+static ssize_t tg3_show_temp(struct device *dev,
+			     struct device_attribute *devattr, char *buf)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct tg3 *tp = netdev_priv(netdev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	u32 temperature;
+
+	spin_lock_bh(&tp->lock);
+	tg3_ape_scratchpad_read(tp, &temperature, attr->index,
+				sizeof(temperature));
+	spin_unlock_bh(&tp->lock);
+	return sprintf(buf, "%u\n", temperature);
+}
+
+#define TG3_TEMP_SENSOR_OFFSET 0xd4
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, tg3_show_temp, NULL,
+			  TG3_TEMP_SENSOR_OFFSET);
+static struct attribute *tg3_attributes[] = {
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group tg3_group = {
+	.attrs = tg3_attributes,
+};
+
+static void tg3_hwmon_open(struct tg3 *tp)
+{
+	int err;
+	struct tg3_sd *sd = tp->sd;
+	struct pci_dev *pdev = tp->pdev;
+
+	/* Register hwmon sysfs hooks */
+	err = sysfs_create_group(&pdev->dev.kobj, &tg3_group);
+	if (err) {
+		dev_err(&pdev->dev, "Cannot create sysfs group, aborting\n");
+		return;
+	}
+
+	sd->hwmon_dev = hwmon_device_register(&pdev->dev);
+	if (IS_ERR(sd->hwmon_dev)) {
+		sd->hwmon_dev = NULL;
+		dev_err(&pdev->dev, "Cannot register hwmon device, aborting\n");
+		sysfs_remove_group(&pdev->dev.kobj, &tg3_group);
+	}
+}
+#endif
+
+static int tg3_sd_init(struct tg3 *tp)
+{
+	int i;
+	u32 size = 0;
+	struct tg3_sd *sd;
+	struct tg3_ocir ocirs[TG3_SD_NUM_RECS];
+
+	if (!tg3_flag(tp, ENABLE_APE))
+		return 0;
+
+	tp->sd = kzalloc(sizeof(struct tg3_sd), GFP_KERNEL);
+	if (!tp->sd)
+		return -ENOMEM;
+
+	sd = tp->sd;
+	tg3_sd_scan_scratchpad(tp, ocirs);
+
+	for (i = 0; i < TG3_SD_NUM_RECS; i++) {
+		u32 val = 1;
+		struct tg3_sd_record *rec = &sd->rec[i];
+
+		if (!ocirs[i].src_data_length)
+			continue;
+
+		rec->hdr_len = ocirs[i].src_hdr_length;
+		rec->hdr_off = ocirs[i].src_hdr_offset;
+		rec->data_len = ocirs[i].src_data_length;
+		rec->data_off = ocirs[i].src_data_offset;
+
+		size += ocirs[i].src_hdr_length;
+		size += ocirs[i].src_data_length;
+
+		rec->utmr_off = i * TG3_OCIR_LEN + TG3_OCIR_UPDATE_TMR_OFF;
+		rec->rtmr_off = i * TG3_OCIR_LEN + TG3_OCIR_REFRESH_TMR_OFF;
+		rec->rtmr_int = ocirs[i].refresh_int;
+
+		/* Initialize utmr_off to non-zero so that we read the region
+		 * at least once */
+		if (tg3_ape_scratchpad_write(tp, rec->utmr_off, &val, 4))
+			netdev_err(tp->dev, "write scratchpad error\n");
+
+		ocirs[i].update_tmr = 0;
+	}
+	if (!size) {
+		kfree(sd);
+		tp->sd = NULL;
+		return -ENODEV;
+	}
+
+	size += sizeof(ocirs);
+
+	sd->buf = kzalloc(size, GFP_KERNEL);
+	if (!sd->buf) {
+		kfree(sd);
+		tp->sd = NULL;
+		return -ENOMEM;
+	}
+
+	sd->buf_size = size;
+	memcpy(sd->buf, ocirs, sizeof(ocirs));
+
+	sd->sd_flags_off = 2 * TG3_OCIR_LEN + (tp->pci_fn * sizeof(u32)) +
+				TG3_OCIR_PORT0_FLGS_OFF;
+
+	return 0;
+}
+
+static void tg3_sd_fini(struct tg3 *tp)
+{
+	struct tg3_sd *sd = tp->sd;
+
+	if (!sd)
+		return;
+
+	kfree(sd->buf);
+	kfree(sd);
+	tp->sd = NULL;
+}
+
+static void tg3_sd_close(struct tg3 *tp)
+{
+	struct tg3_sd *sd = tp->sd;
+
+	if (!sd)
+		return;
+
+#if IS_ENABLED(CONFIG_HWMON)
+	if (sd->hwmon_dev) {
+		hwmon_device_unregister(sd->hwmon_dev);
+		sd->hwmon_dev = NULL;
+		sysfs_remove_group(&tp->pdev->dev.kobj, &tg3_group);
+	}
+#endif
+}
+
+static int tg3_sd_open(struct tg3 *tp)
+{
+	struct tg3_sd *sd = tp->sd;
+
+	if (!sd)
+		return -ENODEV;
+
+#if IS_ENABLED(CONFIG_HWMON)
+	tg3_hwmon_open(tp);
+#endif
+	return 0;
+}
+
 #define TG3_STAT_ADD32(PSTAT, REG) \
 do {	u32 __val = tr32(REG); \
 	(PSTAT)->low += __val; \
@@ -10246,6 +10426,8 @@ static int tg3_open(struct net_device *dev)
 
 	tg3_phy_start(tp);
 
+	tg3_sd_open(tp);
+
 	tg3_full_lock(tp, 0);
 
 	tg3_timer_start(tp);
@@ -10295,6 +10477,8 @@ static int tg3_close(struct net_device *dev)
 
 	tg3_timer_stop(tp);
 
+	tg3_sd_close(tp);
+
 	tg3_phy_stop(tp);
 
 	tg3_full_lock(tp, 1);
@@ -15945,6 +16129,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
 
 	tg3_timer_init(tp);
 
+	tg3_sd_init(tp);
+
 	err = register_netdev(dev);
 	if (err) {
 		dev_err(&pdev->dev, "Cannot register net device, aborting\n");
@@ -16039,6 +16225,9 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev)
 		}
 
 		unregister_netdev(dev);
+
+		tg3_sd_fini(tp);
+
 		if (tp->aperegs) {
 			iounmap(tp->aperegs);
 			tp->aperegs = NULL;
diff --git a/drivers/net/ethernet/broadcom/tg3.h b/drivers/net/ethernet/broadcom/tg3.h
index d167a1c..a3a51c9 100644
--- a/drivers/net/ethernet/broadcom/tg3.h
+++ b/drivers/net/ethernet/broadcom/tg3.h
@@ -2379,6 +2379,18 @@
 #define TG3_APE_LOCK_PHY3		5
 #define TG3_APE_LOCK_GPIO		7
 
+/* SD flags */
+#define TG3_OCIR_SIG_MAGIC		0x5253434f
+#define TG3_OCIR_FLAG_ACTIVE		0x00000001
+
+#define TG3_OCIR_DRVR_FEAT_CSUM		0x00000001
+#define TG3_OCIR_DRVR_FEAT_TSO		0x00000002
+#define TG3_OCIR_DRVR_FEAT_MASK		0xff
+
+#define TG3_OCIR_REFRESH_TMR_OFF	0x00000008
+#define TG3_OCIR_UPDATE_TMR_OFF		0x0000000c
+#define TG3_OCIR_PORT0_FLGS_OFF		0x0000002c
+
 #define TG3_EEPROM_SB_F1R2_MBA_OFF	0x10
 
 
@@ -2677,6 +2689,55 @@ struct tg3_hw_stats {
 	u8				__reserved4[0xb00-0x9c8];
 };
 
+#define TG3_SD_NUM_RECS			3
+#define TG3_OCIR_LEN			(sizeof(struct tg3_ocir))
+
+
+struct tg3_ocir {
+	u32				signature;
+	u16				version_flags;
+	u16				refresh_int;
+	u32				refresh_tmr;
+	u32				update_tmr;
+	u32				dst_base_addr;
+	u16				src_hdr_offset;
+	u16				src_hdr_length;
+	u16				src_data_offset;
+	u16				src_data_length;
+	u16				dst_hdr_offset;
+	u16				dst_data_offset;
+	u16				dst_reg_upd_offset;
+	u16				dst_sem_offset;
+	u32				reserved1[2];
+	u32				port0_flags;
+	u32				port1_flags;
+	u32				port2_flags;
+	u32				port3_flags;
+	u32				reserved2[1];
+};
+
+struct tg3_sd_record {
+	u16				hdr_off;
+	u16				hdr_len;
+	u16				data_off;
+	u16				data_len;
+	u32				updated_seq;
+	u16				utmr_off;
+	u16				rtmr_off;
+	u32				rtmr_val;
+	u16				rtmr_int;
+};
+
+struct tg3_sd {
+#if IS_ENABLED(CONFIG_HWMON)
+	struct device			*hwmon_dev;
+#endif
+	struct tg3_sd_record		rec[TG3_SD_NUM_RECS];
+	u32				sd_flags_off;
+	int				buf_size;
+	u8				*buf;
+};
+
 /* 'mapping' is superfluous as the chip does not write into
  * the tx/rx post rings so we could just fetch it from there.
  * But the cache behavior is better how we are doing it now.
@@ -3212,6 +3273,8 @@ struct tg3 {
 	const char			*fw_needed;
 	const struct firmware		*fw;
 	u32				fw_len; /* includes BSS */
+
+	struct tg3_sd			*sd;
 };
 
 #endif /* !(_T3_H) */
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 -next 4/4] tg3: Add binary sysfs file to export bulk sensor data
  2012-06-27  0:53   ` [PATCH v2 -next 3/4] tg3: Add hwmon support Michael Chan
@ 2012-06-27  0:53     ` Michael Chan
  2012-06-27  4:02       ` David Miller
  0 siblings, 1 reply; 8+ messages in thread
From: Michael Chan @ 2012-06-27  0:53 UTC (permalink / raw)
  To: davem; +Cc: netdev, nsujir

The bulk of the sensor data is exported as binary data to sysfs for
userspace access.

[binary sysfs suggested by Ben Hutchings <bhutchings@solarflare.com>]

Signed-off-by: Matt Carlson <mcarlson@broadcom.com>
Signed-off-by: Nithin Nayak Sujir <nsujir@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
---
 drivers/net/ethernet/broadcom/tg3.c |  130 ++++++++++++++++++++++++++++++++++-
 1 files changed, 129 insertions(+), 1 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index 6b51e3a..109a7cb 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -9542,6 +9542,48 @@ static int tg3_init_hw(struct tg3 *tp, int reset_phy)
 	return tg3_reset_hw(tp, reset_phy);
 }
 
+static void tg3_sd_xfer(struct tg3 *tp, u32 off, u32 size)
+{
+	struct tg3_sd *sd = tp->sd;
+
+	if (!size)
+		return;
+
+	tg3_ape_scratchpad_read(tp, (u32 *) &sd->buf[off], off, size);
+}
+
+static void tg3_sd_update_host(struct tg3 *tp, struct tg3_sd_record *rec)
+{
+	tg3_sd_xfer(tp, rec->data_off, rec->data_len);
+	tg3_sd_xfer(tp, rec->hdr_off, rec->hdr_len);
+}
+
+static void tg3_sd_update_drvflags(struct tg3 *tp, bool unloading)
+{
+	struct tg3_sd *sd = tp->sd;
+	u32 flags;
+
+	if (!sd || !sd->sd_flags_off)
+		return;
+
+	tg3_ape_scratchpad_read(tp, &flags, sd->sd_flags_off, 4);
+
+	flags &= ~TG3_OCIR_DRVR_FEAT_MASK;
+
+	if (!unloading) {
+		u32 mask = NETIF_F_RXCSUM | NETIF_F_IP_CSUM |
+			   NETIF_F_IPV6_CSUM | NETIF_F_HW_CSUM;
+
+		if (tp->dev->features & mask)
+			flags |= TG3_OCIR_DRVR_FEAT_CSUM;
+
+		if (tp->dev->features & NETIF_F_ALL_TSO)
+			flags |= TG3_OCIR_DRVR_FEAT_TSO;
+	}
+
+	tg3_ape_scratchpad_write(tp, sd->sd_flags_off, &flags, 4);
+}
+
 static void tg3_sd_scan_scratchpad(struct tg3 *tp, struct tg3_ocir *ocir)
 {
 	int i;
@@ -9610,6 +9652,32 @@ static void tg3_hwmon_open(struct tg3 *tp)
 }
 #endif
 
+static ssize_t tg3_sd_read(struct file *filep, struct kobject *kobj,
+			   struct bin_attribute *attr, char *buff,
+			   loff_t offset, size_t size)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct tg3 *tp = netdev_priv(netdev);
+	struct tg3_sd *sd = tp->sd;
+	int len = size < sd->buf_size ? size : sd->buf_size;
+
+	if (offset > sd->buf_size)
+		return 0;
+
+	if (offset + len > sd->buf_size)
+		len = sd->buf_size - offset;
+
+	memcpy(buff, sd->buf + offset, len);
+	return len;
+}
+
+static struct bin_attribute bin_attr_tg3_sd = {
+	.attr = {.name = "tg3_sd", .mode = S_IRUSR},
+	.read = tg3_sd_read,
+};
+
 static int tg3_sd_init(struct tg3 *tp)
 {
 	int i;
@@ -9674,6 +9742,7 @@ static int tg3_sd_init(struct tg3 *tp)
 	sd->sd_flags_off = 2 * TG3_OCIR_LEN + (tp->pci_fn * sizeof(u32)) +
 				TG3_OCIR_PORT0_FLGS_OFF;
 
+	tg3_sd_update_drvflags(tp, false);
 	return 0;
 }
 
@@ -9684,6 +9753,8 @@ static void tg3_sd_fini(struct tg3 *tp)
 	if (!sd)
 		return;
 
+	tg3_sd_update_drvflags(tp, true);
+
 	kfree(sd->buf);
 	kfree(sd);
 	tp->sd = NULL;
@@ -9703,6 +9774,7 @@ static void tg3_sd_close(struct tg3 *tp)
 		sysfs_remove_group(&tp->pdev->dev.kobj, &tg3_group);
 	}
 #endif
+	device_remove_bin_file(&tp->pdev->dev, &bin_attr_tg3_sd);
 }
 
 static int tg3_sd_open(struct tg3 *tp)
@@ -9715,7 +9787,7 @@ static int tg3_sd_open(struct tg3 *tp)
 #if IS_ENABLED(CONFIG_HWMON)
 	tg3_hwmon_open(tp);
 #endif
-	return 0;
+	return device_create_bin_file(&tp->pdev->dev, &bin_attr_tg3_sd);
 }
 
 #define TG3_STAT_ADD32(PSTAT, REG) \
@@ -9803,6 +9875,59 @@ static void tg3_chk_missed_msi(struct tg3 *tp)
 	}
 }
 
+
+static void tg3_sd_timer(struct tg3 *tp)
+{
+	int i;
+	u32 val;
+	struct tg3_sd *sd = tp->sd;
+	struct tg3_ocir *ocirp = (struct tg3_ocir *) sd->buf;
+
+	if (!netif_running(tp->dev))
+		return;
+
+	for (i = 0; i < TG3_SD_NUM_RECS; i++, ocirp++) {
+		struct tg3_sd_record *rec = &sd->rec[i];
+
+		if (!rec->data_len)
+			continue;
+
+		tg3_ape_scratchpad_read(tp, &val, rec->utmr_off, 4);
+		/* Check if data has changed */
+		if (val) {
+
+			if (!rec->rtmr_int) {
+				tg3_sd_update_host(tp, rec);
+
+				rec->updated_seq++;
+				ocirp->update_tmr = rec->updated_seq;
+			} else {
+				u32 curr;
+				unsigned long tgt;
+
+				curr = tg3_ape_read32(tp, TG3_APE_STICKY_TMR);
+				tgt = rec->rtmr_val + rec->rtmr_int;
+				if (time_after((unsigned long) curr, tgt)) {
+					tg3_sd_update_host(tp, rec);
+
+					rec->rtmr_val = curr;
+					tg3_ape_scratchpad_write(tp,
+							rec->rtmr_off,
+							&curr, 4);
+
+					rec->updated_seq++;
+					ocirp->update_tmr = rec->updated_seq;
+				}
+			}
+
+			val = 0;
+			if (tg3_ape_scratchpad_write(tp, rec->utmr_off,
+						     &val, 4))
+				netdev_err(tp->dev, "write scratchpad error\n");
+		}
+	}
+}
+
 static void tg3_timer(unsigned long __opaque)
 {
 	struct tg3 *tp = (struct tg3 *) __opaque;
@@ -9841,6 +9966,9 @@ static void tg3_timer(unsigned long __opaque)
 		if (tg3_flag(tp, 5705_PLUS))
 			tg3_periodic_fetch_stats(tp);
 
+		if (tp->sd)
+			tg3_sd_timer(tp);
+
 		if (tp->setlpicnt && !--tp->setlpicnt)
 			tg3_phy_eee_enable(tp);
 
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 -next 4/4] tg3: Add binary sysfs file to export bulk sensor data
  2012-06-27  0:53     ` [PATCH v2 -next 4/4] tg3: Add binary sysfs file to export bulk sensor data Michael Chan
@ 2012-06-27  4:02       ` David Miller
  2012-06-27  5:00         ` Michael Chan
  0 siblings, 1 reply; 8+ messages in thread
From: David Miller @ 2012-06-27  4:02 UTC (permalink / raw)
  To: mchan; +Cc: netdev, nsujir

From: "Michael Chan" <mchan@broadcom.com>
Date: Tue, 26 Jun 2012 17:53:35 -0700

> The bulk of the sensor data is exported as binary data to sysfs for
> userspace access.
> 
> [binary sysfs suggested by Ben Hutchings <bhutchings@solarflare.com>]
> 
> Signed-off-by: Matt Carlson <mcarlson@broadcom.com>
> Signed-off-by: Nithin Nayak Sujir <nsujir@broadcom.com>
> Signed-off-by: Michael Chan <mchan@broadcom.com>

Ben stated merely that a binary attribute existed for sysfs files.  He
did not, however, say that this is the path down which you should
implement your feature.

He, instead, encoraged you to use hwmon and other generic interfaces
to export this sensor information.

I think you were eager to implement things this way because it was the
least amount of work on your part, and that disappoints me greatly.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 -next 4/4] tg3: Add binary sysfs file to export bulk sensor data
  2012-06-27  4:02       ` David Miller
@ 2012-06-27  5:00         ` Michael Chan
  2012-06-27  5:04           ` David Miller
  0 siblings, 1 reply; 8+ messages in thread
From: Michael Chan @ 2012-06-27  5:00 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, nsujir

On Tue, 2012-06-26 at 21:02 -0700, David Miller wrote:
> Ben stated merely that a binary attribute existed for sysfs files.  He
> did not, however, say that this is the path down which you should
> implement your feature.

He said that if the data was difficult to parse in the driver, then a
binary sysfs or private ioctl (which we would stay away) would be
appropriate.  There are hundreds of bytes of this data, most of which is
not useful to the user but needed for Lights out management.  It will
greatly bloat the tg3 driver to add code to parse all that data and
export each one separately.
> 
> He, instead, encoraged you to use hwmon and other generic interfaces
> to export this sensor information.

Temperature is useful to the user, defined by hwmon, and easily
extracted so we added this in patch #3.
> 
> I think you were eager to implement things this way because it was the
> least amount of work on your part, and that disappoints me greatly.
> 
Our purpose is not to bloat the tg3 driver unnecessarily. 
> 

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 -next 4/4] tg3: Add binary sysfs file to export bulk sensor data
  2012-06-27  5:00         ` Michael Chan
@ 2012-06-27  5:04           ` David Miller
  2012-06-27  5:12             ` Michael Chan
  0 siblings, 1 reply; 8+ messages in thread
From: David Miller @ 2012-06-27  5:04 UTC (permalink / raw)
  To: mchan; +Cc: netdev, nsujir

From: "Michael Chan" <mchan@broadcom.com>
Date: Tue, 26 Jun 2012 22:00:49 -0700

> On Tue, 2012-06-26 at 21:02 -0700, David Miller wrote:
>> Ben stated merely that a binary attribute existed for sysfs files.  He
>> did not, however, say that this is the path down which you should
>> implement your feature.
> 
> He said that if the data was difficult to parse in the driver, then a
> binary sysfs or private ioctl (which we would stay away) would be
> appropriate.  There are hundreds of bytes of this data, most of which is
> not useful to the user but needed for Lights out management.  It will
> greatly bloat the tg3 driver to add code to parse all that data and
> export each one separately.

I don't want us to get into the habit of just going "oh it's LOM
stuff, binary blob."  And that's the precedence you're setting here.

It also sets up a situation where functionality could end up only
being available in proprietary binary only tools.

It's not like this is some standardized format like a DMI table or
similar, is it?

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 -next 4/4] tg3: Add binary sysfs file to export bulk sensor data
  2012-06-27  5:04           ` David Miller
@ 2012-06-27  5:12             ` Michael Chan
  0 siblings, 0 replies; 8+ messages in thread
From: Michael Chan @ 2012-06-27  5:12 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, nsujir

On Tue, 2012-06-26 at 22:04 -0700, David Miller wrote: 
> From: "Michael Chan" <mchan@broadcom.com>
> Date: Tue, 26 Jun 2012 22:00:49 -0700
> 
> > On Tue, 2012-06-26 at 21:02 -0700, David Miller wrote:
> >> Ben stated merely that a binary attribute existed for sysfs files.  He
> >> did not, however, say that this is the path down which you should
> >> implement your feature.
> > 
> > He said that if the data was difficult to parse in the driver, then a
> > binary sysfs or private ioctl (which we would stay away) would be
> > appropriate.  There are hundreds of bytes of this data, most of which is
> > not useful to the user but needed for Lights out management.  It will
> > greatly bloat the tg3 driver to add code to parse all that data and
> > export each one separately.
> 
> I don't want us to get into the habit of just going "oh it's LOM
> stuff, binary blob."  And that's the precedence you're setting here.
> 
> It also sets up a situation where functionality could end up only
> being available in proprietary binary only tools.

I will strongly encourage the OEM to opensource the userspace tool.  In
fact, we'll be writing it for them and we can influence them.

> 
> It's not like this is some standardized format like a DMI table or
> similar, is it?
> 

It is defined by the OEM.  I don't know whether they plan to publish it
or not, but I will check tomorrow.

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2012-06-27  5:12 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-06-27  0:53 [PATCH v2 -next 1/4] tg3: Add common function tg3_ape_event_lock() Michael Chan
2012-06-27  0:53 ` [PATCH v2 -next 2/4] tg3: Add APE scratchpad read and write functions Michael Chan
2012-06-27  0:53   ` [PATCH v2 -next 3/4] tg3: Add hwmon support Michael Chan
2012-06-27  0:53     ` [PATCH v2 -next 4/4] tg3: Add binary sysfs file to export bulk sensor data Michael Chan
2012-06-27  4:02       ` David Miller
2012-06-27  5:00         ` Michael Chan
2012-06-27  5:04           ` David Miller
2012-06-27  5:12             ` Michael Chan

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.