aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/broadcom
diff options
context:
space:
mode:
authorMichael Chan <mchan@broadcom.com>2012-07-16 12:24:02 -0400
committerDavid S. Miller <davem@davemloft.net>2012-07-17 02:10:30 -0400
commitaed93e0bf493535c25c27270001226bb1dd379b2 (patch)
treeac90051c0b2f86ad78b67a6c33e8620f2c845d30 /drivers/net/ethernet/broadcom
parentcf8d55ae08459d6412779559fb1e88252db86c9d (diff)
tg3: Add hwmon support for temperature
Some tg3 devices have management firmware that can export sensor 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> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/broadcom')
-rw-r--r--drivers/net/ethernet/broadcom/tg3.c112
-rw-r--r--drivers/net/ethernet/broadcom/tg3.h38
2 files changed, 150 insertions, 0 deletions
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index 26ca36810e72..fce4c1e4dd3f 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -44,6 +44,10 @@
44#include <linux/prefetch.h> 44#include <linux/prefetch.h>
45#include <linux/dma-mapping.h> 45#include <linux/dma-mapping.h>
46#include <linux/firmware.h> 46#include <linux/firmware.h>
47#if IS_ENABLED(CONFIG_HWMON)
48#include <linux/hwmon.h>
49#include <linux/hwmon-sysfs.h>
50#endif
47 51
48#include <net/checksum.h> 52#include <net/checksum.h>
49#include <net/ip.h> 53#include <net/ip.h>
@@ -9481,6 +9485,110 @@ static int tg3_init_hw(struct tg3 *tp, int reset_phy)
9481 return tg3_reset_hw(tp, reset_phy); 9485 return tg3_reset_hw(tp, reset_phy);
9482} 9486}
9483 9487
9488#if IS_ENABLED(CONFIG_HWMON)
9489static void tg3_sd_scan_scratchpad(struct tg3 *tp, struct tg3_ocir *ocir)
9490{
9491 int i;
9492
9493 for (i = 0; i < TG3_SD_NUM_RECS; i++, ocir++) {
9494 u32 off = i * TG3_OCIR_LEN, len = TG3_OCIR_LEN;
9495
9496 tg3_ape_scratchpad_read(tp, (u32 *) ocir, off, len);
9497 off += len;
9498
9499 if (ocir->signature != TG3_OCIR_SIG_MAGIC ||
9500 !(ocir->version_flags & TG3_OCIR_FLAG_ACTIVE))
9501 memset(ocir, 0, TG3_OCIR_LEN);
9502 }
9503}
9504
9505/* sysfs attributes for hwmon */
9506static ssize_t tg3_show_temp(struct device *dev,
9507 struct device_attribute *devattr, char *buf)
9508{
9509 struct pci_dev *pdev = to_pci_dev(dev);
9510 struct net_device *netdev = pci_get_drvdata(pdev);
9511 struct tg3 *tp = netdev_priv(netdev);
9512 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
9513 u32 temperature;
9514
9515 spin_lock_bh(&tp->lock);
9516 tg3_ape_scratchpad_read(tp, &temperature, attr->index,
9517 sizeof(temperature));
9518 spin_unlock_bh(&tp->lock);
9519 return sprintf(buf, "%u\n", temperature);
9520}
9521
9522
9523static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, tg3_show_temp, NULL,
9524 TG3_TEMP_SENSOR_OFFSET);
9525static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, tg3_show_temp, NULL,
9526 TG3_TEMP_CAUTION_OFFSET);
9527static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, tg3_show_temp, NULL,
9528 TG3_TEMP_MAX_OFFSET);
9529
9530static struct attribute *tg3_attributes[] = {
9531 &sensor_dev_attr_temp1_input.dev_attr.attr,
9532 &sensor_dev_attr_temp1_crit.dev_attr.attr,
9533 &sensor_dev_attr_temp1_max.dev_attr.attr,
9534 NULL
9535};
9536
9537static const struct attribute_group tg3_group = {
9538 .attrs = tg3_attributes,
9539};
9540
9541#endif
9542
9543static void tg3_hwmon_close(struct tg3 *tp)
9544{
9545#if IS_ENABLED(CONFIG_HWMON)
9546 if (tp->hwmon_dev) {
9547 hwmon_device_unregister(tp->hwmon_dev);
9548 tp->hwmon_dev = NULL;
9549 sysfs_remove_group(&tp->pdev->dev.kobj, &tg3_group);
9550 }
9551#endif
9552}
9553
9554static void tg3_hwmon_open(struct tg3 *tp)
9555{
9556#if IS_ENABLED(CONFIG_HWMON)
9557 int i, err;
9558 u32 size = 0;
9559 struct pci_dev *pdev = tp->pdev;
9560 struct tg3_ocir ocirs[TG3_SD_NUM_RECS];
9561
9562 tg3_sd_scan_scratchpad(tp, ocirs);
9563
9564 for (i = 0; i < TG3_SD_NUM_RECS; i++) {
9565 if (!ocirs[i].src_data_length)
9566 continue;
9567
9568 size += ocirs[i].src_hdr_length;
9569 size += ocirs[i].src_data_length;
9570 }
9571
9572 if (!size)
9573 return;
9574
9575 /* Register hwmon sysfs hooks */
9576 err = sysfs_create_group(&pdev->dev.kobj, &tg3_group);
9577 if (err) {
9578 dev_err(&pdev->dev, "Cannot create sysfs group, aborting\n");
9579 return;
9580 }
9581
9582 tp->hwmon_dev = hwmon_device_register(&pdev->dev);
9583 if (IS_ERR(tp->hwmon_dev)) {
9584 tp->hwmon_dev = NULL;
9585 dev_err(&pdev->dev, "Cannot register hwmon device, aborting\n");
9586 sysfs_remove_group(&pdev->dev.kobj, &tg3_group);
9587 }
9588#endif
9589}
9590
9591
9484#define TG3_STAT_ADD32(PSTAT, REG) \ 9592#define TG3_STAT_ADD32(PSTAT, REG) \
9485do { u32 __val = tr32(REG); \ 9593do { u32 __val = tr32(REG); \
9486 (PSTAT)->low += __val; \ 9594 (PSTAT)->low += __val; \
@@ -10189,6 +10297,8 @@ static int tg3_open(struct net_device *dev)
10189 10297
10190 tg3_phy_start(tp); 10298 tg3_phy_start(tp);
10191 10299
10300 tg3_hwmon_open(tp);
10301
10192 tg3_full_lock(tp, 0); 10302 tg3_full_lock(tp, 0);
10193 10303
10194 tg3_timer_start(tp); 10304 tg3_timer_start(tp);
@@ -10238,6 +10348,8 @@ static int tg3_close(struct net_device *dev)
10238 10348
10239 tg3_timer_stop(tp); 10349 tg3_timer_stop(tp);
10240 10350
10351 tg3_hwmon_close(tp);
10352
10241 tg3_phy_stop(tp); 10353 tg3_phy_stop(tp);
10242 10354
10243 tg3_full_lock(tp, 1); 10355 tg3_full_lock(tp, 1);
diff --git a/drivers/net/ethernet/broadcom/tg3.h b/drivers/net/ethernet/broadcom/tg3.h
index f8a0d9c0e990..a1b75cd67b9d 100644
--- a/drivers/net/ethernet/broadcom/tg3.h
+++ b/drivers/net/ethernet/broadcom/tg3.h
@@ -2676,6 +2676,40 @@ struct tg3_hw_stats {
2676 u8 __reserved4[0xb00-0x9c8]; 2676 u8 __reserved4[0xb00-0x9c8];
2677}; 2677};
2678 2678
2679#define TG3_SD_NUM_RECS 3
2680#define TG3_OCIR_LEN (sizeof(struct tg3_ocir))
2681#define TG3_OCIR_SIG_MAGIC 0x5253434f
2682#define TG3_OCIR_FLAG_ACTIVE 0x00000001
2683
2684#define TG3_TEMP_CAUTION_OFFSET 0xc8
2685#define TG3_TEMP_MAX_OFFSET 0xcc
2686#define TG3_TEMP_SENSOR_OFFSET 0xd4
2687
2688
2689struct tg3_ocir {
2690 u32 signature;
2691 u16 version_flags;
2692 u16 refresh_int;
2693 u32 refresh_tmr;
2694 u32 update_tmr;
2695 u32 dst_base_addr;
2696 u16 src_hdr_offset;
2697 u16 src_hdr_length;
2698 u16 src_data_offset;
2699 u16 src_data_length;
2700 u16 dst_hdr_offset;
2701 u16 dst_data_offset;
2702 u16 dst_reg_upd_offset;
2703 u16 dst_sem_offset;
2704 u32 reserved1[2];
2705 u32 port0_flags;
2706 u32 port1_flags;
2707 u32 port2_flags;
2708 u32 port3_flags;
2709 u32 reserved2[1];
2710};
2711
2712
2679/* 'mapping' is superfluous as the chip does not write into 2713/* 'mapping' is superfluous as the chip does not write into
2680 * the tx/rx post rings so we could just fetch it from there. 2714 * the tx/rx post rings so we could just fetch it from there.
2681 * But the cache behavior is better how we are doing it now. 2715 * But the cache behavior is better how we are doing it now.
@@ -3211,6 +3245,10 @@ struct tg3 {
3211 const char *fw_needed; 3245 const char *fw_needed;
3212 const struct firmware *fw; 3246 const struct firmware *fw;
3213 u32 fw_len; /* includes BSS */ 3247 u32 fw_len; /* includes BSS */
3248
3249#if IS_ENABLED(CONFIG_HWMON)
3250 struct device *hwmon_dev;
3251#endif
3214}; 3252};
3215 3253
3216#endif /* !(_T3_H) */ 3254#endif /* !(_T3_H) */