mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-27 17:25:03 +07:00
b5c46a53ee
The OCC driver limits the rate of sending poll commands to the OCC. If a user reads a hwmon entry after a poll response resulted in an error and is rate-limited, the error is invisible to the user. Fix this by storing the last error and returning that in the rate-limited case. Signed-off-by: Eddie James <eajames@linux.ibm.com> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
131 lines
2.8 KiB
C
131 lines
2.8 KiB
C
/* SPDX-License-Identifier: GPL-2.0+ */
|
|
/* Copyright IBM Corp 2019 */
|
|
|
|
#ifndef OCC_COMMON_H
|
|
#define OCC_COMMON_H
|
|
|
|
#include <linux/hwmon-sysfs.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/sysfs.h>
|
|
|
|
struct device;
|
|
|
|
#define OCC_RESP_DATA_BYTES 4089
|
|
|
|
/*
|
|
* Same response format for all OCC versions.
|
|
* Allocate the largest possible response.
|
|
*/
|
|
struct occ_response {
|
|
u8 seq_no;
|
|
u8 cmd_type;
|
|
u8 return_status;
|
|
__be16 data_length;
|
|
u8 data[OCC_RESP_DATA_BYTES];
|
|
__be16 checksum;
|
|
} __packed;
|
|
|
|
struct occ_sensor_data_block_header {
|
|
u8 eye_catcher[4];
|
|
u8 reserved;
|
|
u8 sensor_format;
|
|
u8 sensor_length;
|
|
u8 num_sensors;
|
|
} __packed;
|
|
|
|
struct occ_sensor_data_block {
|
|
struct occ_sensor_data_block_header header;
|
|
u32 data;
|
|
} __packed;
|
|
|
|
struct occ_poll_response_header {
|
|
u8 status;
|
|
u8 ext_status;
|
|
u8 occs_present;
|
|
u8 config_data;
|
|
u8 occ_state;
|
|
u8 mode;
|
|
u8 ips_status;
|
|
u8 error_log_id;
|
|
__be32 error_log_start_address;
|
|
__be16 error_log_length;
|
|
u16 reserved;
|
|
u8 occ_code_level[16];
|
|
u8 eye_catcher[6];
|
|
u8 num_sensor_data_blocks;
|
|
u8 sensor_data_block_header_version;
|
|
} __packed;
|
|
|
|
struct occ_poll_response {
|
|
struct occ_poll_response_header header;
|
|
struct occ_sensor_data_block block;
|
|
} __packed;
|
|
|
|
struct occ_sensor {
|
|
u8 num_sensors;
|
|
u8 version;
|
|
void *data; /* pointer to sensor data start within response */
|
|
};
|
|
|
|
/*
|
|
* OCC only provides one sensor data block of each type, but any number of
|
|
* sensors within that block.
|
|
*/
|
|
struct occ_sensors {
|
|
struct occ_sensor temp;
|
|
struct occ_sensor freq;
|
|
struct occ_sensor power;
|
|
struct occ_sensor caps;
|
|
struct occ_sensor extended;
|
|
};
|
|
|
|
/*
|
|
* Use our own attribute struct so we can dynamically allocate space for the
|
|
* name.
|
|
*/
|
|
struct occ_attribute {
|
|
char name[32];
|
|
struct sensor_device_attribute_2 sensor;
|
|
};
|
|
|
|
struct occ {
|
|
struct device *bus_dev;
|
|
|
|
struct occ_response resp;
|
|
struct occ_sensors sensors;
|
|
|
|
int powr_sample_time_us; /* average power sample time */
|
|
u8 poll_cmd_data; /* to perform OCC poll command */
|
|
int (*send_cmd)(struct occ *occ, u8 *cmd);
|
|
|
|
unsigned long last_update;
|
|
struct mutex lock; /* lock OCC access */
|
|
|
|
struct device *hwmon;
|
|
struct occ_attribute *attrs;
|
|
struct attribute_group group;
|
|
const struct attribute_group *groups[2];
|
|
|
|
int error; /* final transfer error after retry */
|
|
int last_error; /* latest transfer error */
|
|
unsigned int error_count; /* number of xfr errors observed */
|
|
unsigned long last_safe; /* time OCC entered "safe" state */
|
|
|
|
/*
|
|
* Store the previous state data for comparison in order to notify
|
|
* sysfs readers of state changes.
|
|
*/
|
|
int prev_error;
|
|
u8 prev_stat;
|
|
u8 prev_ext_stat;
|
|
u8 prev_occs_present;
|
|
};
|
|
|
|
int occ_setup(struct occ *occ, const char *name);
|
|
int occ_setup_sysfs(struct occ *occ);
|
|
void occ_shutdown(struct occ *occ);
|
|
void occ_sysfs_poll_done(struct occ *occ);
|
|
int occ_update_response(struct occ *occ);
|
|
|
|
#endif /* OCC_COMMON_H */
|