Commit 63d4c081 authored by Luben Tuikov's avatar Luben Tuikov Committed by Alex Deucher

drm/amdgpu: Optimize EEPROM RAS table I/O

Split functionality between read and write, which
simplifies the code and exposes areas of
optimization and more or less complexity, and take
advantage of that.

Read and write the table in one go; use a separate
stage to decode or encode the data, as opposed to
on the fly, which keeps the I2C bus busy. Use a
single read/write to read/write the table or at
most two if the number of records we're
reading/writing wraps around.

Check the check-sum of a table in EEPROM on init.

Update the checksum at the same time as when
updating the table header signature, when the
threshold was increased on boot.

Take advantage of arithmetic modulo 256, that is,
use a byte!, to greatly simplify checksum
arithmetic.

Cc: Alexander Deucher <Alexander.Deucher@amd.com>
Cc: Andrey Grodzovsky <Andrey.Grodzovsky@amd.com>
Signed-off-by: default avatarLuben Tuikov <luben.tuikov@amd.com>
Acked-by: default avatarAlexander Deucher <Alexander.Deucher@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 017dad64
...@@ -176,8 +176,8 @@ static int __amdgpu_eeprom_xfer(struct i2c_adapter *i2c_adap, u32 eeprom_addr, ...@@ -176,8 +176,8 @@ static int __amdgpu_eeprom_xfer(struct i2c_adapter *i2c_adap, u32 eeprom_addr,
* *
* Returns the number of bytes read/written; -errno on error. * Returns the number of bytes read/written; -errno on error.
*/ */
int amdgpu_eeprom_xfer(struct i2c_adapter *i2c_adap, u32 eeprom_addr, static int amdgpu_eeprom_xfer(struct i2c_adapter *i2c_adap, u32 eeprom_addr,
u8 *eeprom_buf, u16 buf_size, bool read) u8 *eeprom_buf, u16 buf_size, bool read)
{ {
const struct i2c_adapter_quirks *quirks = i2c_adap->quirks; const struct i2c_adapter_quirks *quirks = i2c_adap->quirks;
u16 limit; u16 limit;
...@@ -221,3 +221,19 @@ int amdgpu_eeprom_xfer(struct i2c_adapter *i2c_adap, u32 eeprom_addr, ...@@ -221,3 +221,19 @@ int amdgpu_eeprom_xfer(struct i2c_adapter *i2c_adap, u32 eeprom_addr,
return res; return res;
} }
} }
int amdgpu_eeprom_read(struct i2c_adapter *i2c_adap,
u32 eeprom_addr, u8 *eeprom_buf,
u16 bytes)
{
return amdgpu_eeprom_xfer(i2c_adap, eeprom_addr, eeprom_buf, bytes,
true);
}
int amdgpu_eeprom_write(struct i2c_adapter *i2c_adap,
u32 eeprom_addr, u8 *eeprom_buf,
u16 bytes)
{
return amdgpu_eeprom_xfer(i2c_adap, eeprom_addr, eeprom_buf, bytes,
false);
}
...@@ -26,23 +26,12 @@ ...@@ -26,23 +26,12 @@
#include <linux/i2c.h> #include <linux/i2c.h>
int amdgpu_eeprom_xfer(struct i2c_adapter *i2c_adap, u32 eeprom_addr, int amdgpu_eeprom_read(struct i2c_adapter *i2c_adap,
u8 *eeprom_buf, u16 bytes, bool read); u32 eeprom_addr, u8 *eeprom_buf,
u16 bytes);
static inline int amdgpu_eeprom_read(struct i2c_adapter *i2c_adap, int amdgpu_eeprom_write(struct i2c_adapter *i2c_adap,
u32 eeprom_addr, u8 *eeprom_buf, u32 eeprom_addr, u8 *eeprom_buf,
u16 bytes) u16 bytes);
{
return amdgpu_eeprom_xfer(i2c_adap, eeprom_addr, eeprom_buf, bytes,
true);
}
static inline int amdgpu_eeprom_write(struct i2c_adapter *i2c_adap,
u32 eeprom_addr, u8 *eeprom_buf,
u16 bytes)
{
return amdgpu_eeprom_xfer(i2c_adap, eeprom_addr, eeprom_buf, bytes,
false);
}
#endif #endif
...@@ -451,7 +451,7 @@ static ssize_t amdgpu_ras_debugfs_eeprom_write(struct file *f, ...@@ -451,7 +451,7 @@ static ssize_t amdgpu_ras_debugfs_eeprom_write(struct file *f,
ret = amdgpu_ras_eeprom_reset_table( ret = amdgpu_ras_eeprom_reset_table(
&(amdgpu_ras_get_context(adev)->eeprom_control)); &(amdgpu_ras_get_context(adev)->eeprom_control));
if (ret > 0) { if (!ret) {
/* Something was written to EEPROM. /* Something was written to EEPROM.
*/ */
amdgpu_ras_get_context(adev)->flags = RAS_DEFAULT_FLAGS; amdgpu_ras_get_context(adev)->flags = RAS_DEFAULT_FLAGS;
...@@ -1821,9 +1821,9 @@ int amdgpu_ras_save_bad_pages(struct amdgpu_device *adev) ...@@ -1821,9 +1821,9 @@ int amdgpu_ras_save_bad_pages(struct amdgpu_device *adev)
save_count = data->count - control->ras_num_recs; save_count = data->count - control->ras_num_recs;
/* only new entries are saved */ /* only new entries are saved */
if (save_count > 0) { if (save_count > 0) {
if (amdgpu_ras_eeprom_write(control, if (amdgpu_ras_eeprom_append(control,
&data->bps[control->ras_num_recs], &data->bps[control->ras_num_recs],
save_count)) { save_count)) {
dev_err(adev->dev, "Failed to save EEPROM table data!"); dev_err(adev->dev, "Failed to save EEPROM table data!");
return -EIO; return -EIO;
} }
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
struct amdgpu_device; struct amdgpu_device;
enum amdgpu_ras_eeprom_err_type{ enum amdgpu_ras_eeprom_err_type {
AMDGPU_RAS_EEPROM_ERR_PLACE_HOLDER, AMDGPU_RAS_EEPROM_ERR_PLACE_HOLDER,
AMDGPU_RAS_EEPROM_ERR_RECOVERABLE, AMDGPU_RAS_EEPROM_ERR_RECOVERABLE,
AMDGPU_RAS_EEPROM_ERR_NON_RECOVERABLE AMDGPU_RAS_EEPROM_ERR_NON_RECOVERABLE
...@@ -51,17 +51,34 @@ struct amdgpu_ras_eeprom_control { ...@@ -51,17 +51,34 @@ struct amdgpu_ras_eeprom_control {
*/ */
u32 i2c_address; u32 i2c_address;
uint32_t next_addr; /* The byte offset off of @i2c_address
* where the table header is found,
* and where the records start--always
* right after the header.
*/
u32 ras_header_offset;
u32 ras_record_offset;
/* Number of records in the table. /* Number of records in the table.
*/ */
unsigned int ras_num_recs; u32 ras_num_recs;
/* First record index to read, 0-based.
* Range is [0, num_recs-1]. This is
* an absolute index, starting right after
* the table header.
*/
u32 ras_fri;
/* Maximum possible number of records
* we could store, i.e. the maximum capacity
* of the table.
*/
u32 ras_max_record_count;
/* Protect table access via this mutex. /* Protect table access via this mutex.
*/ */
struct mutex ras_tbl_mutex; struct mutex ras_tbl_mutex;
u8 tbl_byte_sum;
}; };
/* /*
...@@ -91,6 +108,7 @@ struct eeprom_table_record { ...@@ -91,6 +108,7 @@ struct eeprom_table_record {
int amdgpu_ras_eeprom_init(struct amdgpu_ras_eeprom_control *control, int amdgpu_ras_eeprom_init(struct amdgpu_ras_eeprom_control *control,
bool *exceed_err_limit); bool *exceed_err_limit);
int amdgpu_ras_eeprom_reset_table(struct amdgpu_ras_eeprom_control *control); int amdgpu_ras_eeprom_reset_table(struct amdgpu_ras_eeprom_control *control);
bool amdgpu_ras_eeprom_check_err_threshold(struct amdgpu_device *adev); bool amdgpu_ras_eeprom_check_err_threshold(struct amdgpu_device *adev);
...@@ -98,8 +116,8 @@ bool amdgpu_ras_eeprom_check_err_threshold(struct amdgpu_device *adev); ...@@ -98,8 +116,8 @@ bool amdgpu_ras_eeprom_check_err_threshold(struct amdgpu_device *adev);
int amdgpu_ras_eeprom_read(struct amdgpu_ras_eeprom_control *control, int amdgpu_ras_eeprom_read(struct amdgpu_ras_eeprom_control *control,
struct eeprom_table_record *records, const u32 num); struct eeprom_table_record *records, const u32 num);
int amdgpu_ras_eeprom_write(struct amdgpu_ras_eeprom_control *control, int amdgpu_ras_eeprom_append(struct amdgpu_ras_eeprom_control *control,
struct eeprom_table_record *records, const u32 num); struct eeprom_table_record *records, const u32 num);
inline uint32_t amdgpu_ras_eeprom_max_record_count(void); inline uint32_t amdgpu_ras_eeprom_max_record_count(void);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment