#include <linux/slab.h>
 #include <linux/u64_stats_sync.h>
 #include <linux/cpumask.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
 
 #include "be_hw.h"
 #include "be_roce.h"
 } ____cacheline_aligned_in_smp;
 
 struct be_drv_stats {
-       u32 be_on_die_temperature;
        u32 eth_red_drops;
        u32 dma_map_errors;
        u32 rx_drops_no_pbuf;
        u8 rss_hkey[RSS_HASH_KEY_LEN];
 };
 
+#define BE_INVALID_DIE_TEMP    0xFF
+struct be_hwmon {
+       struct device *hwmon_dev;
+       u8 be_on_die_temp;  /* Unit: millidegree Celsius */
+};
+
 /* Macros to read/write the 'features' word of be_wrb_params structure.
  */
 #define        BE_WRB_F_BIT(name)                      BE_WRB_F_##name##_BIT
        u16 qnq_vid;
        u32 msg_enable;
        int be_get_temp_freq;
+       struct be_hwmon hwmon_info;
        u8 pf_number;
        struct rss_info rss_info;
 };
 
                if (base_status == MCC_STATUS_SUCCESS) {
                        struct be_cmd_resp_get_cntl_addnl_attribs *resp =
                                                        (void *)resp_hdr;
-                       adapter->drv_stats.be_on_die_temperature =
+                       adapter->hwmon_info.be_on_die_temp =
                                                resp->on_die_temperature;
                } else {
                        adapter->be_get_temp_freq = 0;
+                       adapter->hwmon_info.be_on_die_temp =
+                                               BE_INVALID_DIE_TEMP;
                }
                return;
        }
 
        {DRVSTAT_INFO(dma_map_errors)},
        /* Number of packets dropped due to random early drop function */
        {DRVSTAT_INFO(eth_red_drops)},
-       {DRVSTAT_INFO(be_on_die_temperature)},
        {DRVSTAT_INFO(rx_roce_bytes_lsd)},
        {DRVSTAT_INFO(rx_roce_bytes_msd)},
        {DRVSTAT_INFO(rx_roce_frames)},
 
        free_netdev(adapter->netdev);
 }
 
+ssize_t be_hwmon_show_temp(struct device *dev,
+                          struct device_attribute *dev_attr,
+                          char *buf)
+{
+       struct be_adapter *adapter = dev_get_drvdata(dev);
+
+       /* Unit: millidegree Celsius */
+       if (adapter->hwmon_info.be_on_die_temp == BE_INVALID_DIE_TEMP)
+               return -EIO;
+       else
+               return sprintf(buf, "%u\n",
+                              adapter->hwmon_info.be_on_die_temp * 1000);
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
+                         be_hwmon_show_temp, NULL, 1);
+
+static struct attribute *be_hwmon_attrs[] = {
+       &sensor_dev_attr_temp1_input.dev_attr.attr,
+       NULL
+};
+
+ATTRIBUTE_GROUPS(be_hwmon);
+
 static char *mc_name(struct be_adapter *adapter)
 {
        char *str = ""; /* default */
 
        be_schedule_err_detection(adapter);
 
+       /* On Die temperature not supported for VF. */
+       if (be_physfn(adapter)) {
+               adapter->hwmon_info.hwmon_dev =
+                       devm_hwmon_device_register_with_groups(&pdev->dev,
+                                                              DRV_NAME,
+                                                              adapter,
+                                                              be_hwmon_groups);
+               adapter->hwmon_info.be_on_die_temp = BE_INVALID_DIE_TEMP;
+       }
+
        dev_info(&pdev->dev, "%s: %s %s port %c\n", nic_name(pdev),
                 func_name(adapter), mc_name(adapter), adapter->port_name);