Skip to content

Commit aed93e0

Browse files
Michael Chandavem330
authored andcommitted
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 <[email protected]>] Signed-off-by: Matt Carlson <[email protected]> Signed-off-by: Nithin Nayak Sujir <[email protected]> Signed-off-by: Michael Chan <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent cf8d55a commit aed93e0

File tree

2 files changed

+150
-0
lines changed

2 files changed

+150
-0
lines changed

drivers/net/ethernet/broadcom/tg3.c

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@
4444
#include <linux/prefetch.h>
4545
#include <linux/dma-mapping.h>
4646
#include <linux/firmware.h>
47+
#if IS_ENABLED(CONFIG_HWMON)
48+
#include <linux/hwmon.h>
49+
#include <linux/hwmon-sysfs.h>
50+
#endif
4751

4852
#include <net/checksum.h>
4953
#include <net/ip.h>
@@ -9481,6 +9485,110 @@ static int tg3_init_hw(struct tg3 *tp, int reset_phy)
94819485
return tg3_reset_hw(tp, reset_phy);
94829486
}
94839487

9488+
#if IS_ENABLED(CONFIG_HWMON)
9489+
static 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 */
9506+
static 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+
9523+
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, tg3_show_temp, NULL,
9524+
TG3_TEMP_SENSOR_OFFSET);
9525+
static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, tg3_show_temp, NULL,
9526+
TG3_TEMP_CAUTION_OFFSET);
9527+
static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, tg3_show_temp, NULL,
9528+
TG3_TEMP_MAX_OFFSET);
9529+
9530+
static 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+
9537+
static const struct attribute_group tg3_group = {
9538+
.attrs = tg3_attributes,
9539+
};
9540+
9541+
#endif
9542+
9543+
static 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+
9554+
static 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+
94849592
#define TG3_STAT_ADD32(PSTAT, REG) \
94859593
do { u32 __val = tr32(REG); \
94869594
(PSTAT)->low += __val; \
@@ -10189,6 +10297,8 @@ static int tg3_open(struct net_device *dev)
1018910297

1019010298
tg3_phy_start(tp);
1019110299

10300+
tg3_hwmon_open(tp);
10301+
1019210302
tg3_full_lock(tp, 0);
1019310303

1019410304
tg3_timer_start(tp);
@@ -10238,6 +10348,8 @@ static int tg3_close(struct net_device *dev)
1023810348

1023910349
tg3_timer_stop(tp);
1024010350

10351+
tg3_hwmon_close(tp);
10352+
1024110353
tg3_phy_stop(tp);
1024210354

1024310355
tg3_full_lock(tp, 1);

drivers/net/ethernet/broadcom/tg3.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2676,6 +2676,40 @@ struct tg3_hw_stats {
26762676
u8 __reserved4[0xb00-0x9c8];
26772677
};
26782678

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+
2689+
struct 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+
26792713
/* 'mapping' is superfluous as the chip does not write into
26802714
* the tx/rx post rings so we could just fetch it from there.
26812715
* But the cache behavior is better how we are doing it now.
@@ -3211,6 +3245,10 @@ struct tg3 {
32113245
const char *fw_needed;
32123246
const struct firmware *fw;
32133247
u32 fw_len; /* includes BSS */
3248+
3249+
#if IS_ENABLED(CONFIG_HWMON)
3250+
struct device *hwmon_dev;
3251+
#endif
32143252
};
32153253

32163254
#endif /* !(_T3_H) */

0 commit comments

Comments
 (0)