RISC-V: Fix a race condition during kernel stack overflow
[platform/kernel/linux-starfive.git] / drivers / net / ethernet / aquantia / atlantic / aq_drvinfo.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Atlantic Network Driver
3  *
4  * Copyright (C) 2014-2019 aQuantia Corporation
5  * Copyright (C) 2019-2020 Marvell International Ltd.
6  */
7
8 /* File aq_drvinfo.c: Definition of common code for firmware info in sys.*/
9
10 #include <linux/init.h>
11 #include <linux/kobject.h>
12 #include <linux/module.h>
13 #include <linux/stat.h>
14 #include <linux/string.h>
15 #include <linux/hwmon.h>
16 #include <linux/uaccess.h>
17
18 #include "aq_drvinfo.h"
19 #include "aq_nic.h"
20
21 #if IS_REACHABLE(CONFIG_HWMON)
22 static const char * const atl_temp_label[] = {
23         "PHY Temperature",
24         "MAC Temperature",
25 };
26
27 static int aq_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
28                          u32 attr, int channel, long *value)
29 {
30         struct aq_nic_s *aq_nic = dev_get_drvdata(dev);
31         int err = 0;
32         int temp;
33
34         if (!aq_nic)
35                 return -EIO;
36
37         if (type != hwmon_temp || attr != hwmon_temp_input)
38                 return -EOPNOTSUPP;
39
40         switch (channel) {
41         case 0:
42                 if (!aq_nic->aq_fw_ops->get_phy_temp)
43                         return -EOPNOTSUPP;
44
45                 err = aq_nic->aq_fw_ops->get_phy_temp(aq_nic->aq_hw, &temp);
46                 *value = temp;
47                 break;
48         case 1:
49                 if (!aq_nic->aq_fw_ops->get_mac_temp &&
50                     !aq_nic->aq_hw_ops->hw_get_mac_temp)
51                         return -EOPNOTSUPP;
52
53                 if (aq_nic->aq_fw_ops->get_mac_temp)
54                         err = aq_nic->aq_fw_ops->get_mac_temp(aq_nic->aq_hw, &temp);
55                 else
56                         err = aq_nic->aq_hw_ops->hw_get_mac_temp(aq_nic->aq_hw, &temp);
57                 *value = temp;
58                 break;
59         default:
60                 return -EOPNOTSUPP;
61         }
62
63         return err;
64 }
65
66 static int aq_hwmon_read_string(struct device *dev,
67                                 enum hwmon_sensor_types type,
68                                 u32 attr, int channel, const char **str)
69 {
70         struct aq_nic_s *aq_nic = dev_get_drvdata(dev);
71
72         if (!aq_nic)
73                 return -EIO;
74
75         if (type != hwmon_temp || attr != hwmon_temp_label)
76                 return -EOPNOTSUPP;
77
78         if (channel < ARRAY_SIZE(atl_temp_label))
79                 *str = atl_temp_label[channel];
80         else
81                 return -EOPNOTSUPP;
82
83         return 0;
84 }
85
86 static umode_t aq_hwmon_is_visible(const void *data,
87                                    enum hwmon_sensor_types type,
88                                    u32 attr, int channel)
89 {
90         const struct aq_nic_s *nic = data;
91
92         if (type != hwmon_temp)
93                 return 0;
94
95         if (channel == 0 && !nic->aq_fw_ops->get_phy_temp)
96                 return 0;
97         else if (channel == 1 && !nic->aq_fw_ops->get_mac_temp &&
98                  !nic->aq_hw_ops->hw_get_mac_temp)
99                 return 0;
100
101         switch (attr) {
102         case hwmon_temp_input:
103         case hwmon_temp_label:
104                 return 0444;
105         default:
106                 return 0;
107         }
108 }
109
110 static const struct hwmon_ops aq_hwmon_ops = {
111         .is_visible = aq_hwmon_is_visible,
112         .read = aq_hwmon_read,
113         .read_string = aq_hwmon_read_string,
114 };
115
116 static u32 aq_hwmon_temp_config[] = {
117         HWMON_T_INPUT | HWMON_T_LABEL,
118         HWMON_T_INPUT | HWMON_T_LABEL,
119         0,
120 };
121
122 static const struct hwmon_channel_info aq_hwmon_temp = {
123         .type = hwmon_temp,
124         .config = aq_hwmon_temp_config,
125 };
126
127 static const struct hwmon_channel_info *aq_hwmon_info[] = {
128         &aq_hwmon_temp,
129         NULL,
130 };
131
132 static const struct hwmon_chip_info aq_hwmon_chip_info = {
133         .ops = &aq_hwmon_ops,
134         .info = aq_hwmon_info,
135 };
136
137 int aq_drvinfo_init(struct net_device *ndev)
138 {
139         struct aq_nic_s *aq_nic = netdev_priv(ndev);
140         struct device *dev = &aq_nic->pdev->dev;
141         struct device *hwmon_dev;
142         int err = 0;
143
144         hwmon_dev = devm_hwmon_device_register_with_info(dev,
145                                                          ndev->name,
146                                                          aq_nic,
147                                                          &aq_hwmon_chip_info,
148                                                          NULL);
149
150         if (IS_ERR(hwmon_dev))
151                 err = PTR_ERR(hwmon_dev);
152
153         return err;
154 }
155
156 #else
157 int aq_drvinfo_init(struct net_device *ndev) { return 0; }
158 #endif