aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean Delvare <khali@linux-fr.org>2008-07-14 22:38:29 +0200
committerJean Delvare <khali@mahadeva.delvare>2008-07-14 22:38:29 +0200
commit1b4dff9cd37d430bc76112396e92bb3552f37ccd (patch)
tree30bc7e5816a5d68bb0e2a202e4b54e1d776c2348
parentd4653bf946a5856a17342cd47c47d10b16b1cc22 (diff)
i2c/eeprom: Fall back to SMBus read word transactions
When I2C block reads are not supported by the underlying adapter, use SMBus read word transactions instead of consecutive byte reads. Reasons for this change are: * The consecutive byte read approach is not safe on multi-master buses. * While consecutive byte reads have less overhead if you only count the bytes on the bus, it takes more than twice as many transactions as with SMBus read word transactions, and each transaction has a cost: taking and releasing the adapter mutex, and for polling drivers, waiting for the transaction to complete. This change yields a significant performance boost at HZ=250 with EEPROMs on an Intel 82801 bus (basically twice as fast.) SMBus read word transactions are widely supported so I don't expect compatibility issues. Signed-off-by: Jean Delvare <khali@linux-fr.org>
-rw-r--r--drivers/i2c/chips/eeprom.c39
1 files changed, 19 insertions, 20 deletions
diff --git a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c
index 213a9f98dec..9a81252a721 100644
--- a/drivers/i2c/chips/eeprom.c
+++ b/drivers/i2c/chips/eeprom.c
@@ -78,7 +78,7 @@ static struct i2c_driver eeprom_driver = {
static void eeprom_update_client(struct i2c_client *client, u8 slice)
{
struct eeprom_data *data = i2c_get_clientdata(client);
- int i, j;
+ int i;
mutex_lock(&data->update_lock);
@@ -93,15 +93,12 @@ static void eeprom_update_client(struct i2c_client *client, u8 slice)
!= 32)
goto exit;
} else {
- if (i2c_smbus_write_byte(client, slice << 5)) {
- dev_dbg(&client->dev, "eeprom read start has failed!\n");
- goto exit;
- }
- for (i = slice << 5; i < (slice + 1) << 5; i++) {
- j = i2c_smbus_read_byte(client);
- if (j < 0)
+ for (i = slice << 5; i < (slice + 1) << 5; i += 2) {
+ int word = i2c_smbus_read_word_data(client, i);
+ if (word < 0)
goto exit;
- data->data[i] = (u8) j;
+ data->data[i] = word & 0xff;
+ data->data[i + 1] = word >> 8;
}
}
data->last_updated[slice] = jiffies;
@@ -177,14 +174,15 @@ static int eeprom_detect(struct i2c_adapter *adapter, int address, int kind)
if (!(adapter->class & I2C_CLASS_SPD) && address >= 0x51)
goto exit;
- /* There are three ways we can read the EEPROM data:
+ /* There are four ways we can read the EEPROM data:
(1) I2C block reads (faster, but unsupported by most adapters)
- (2) Consecutive byte reads (100% overhead)
- (3) Regular byte data reads (200% overhead)
- The third method is not implemented by this driver because all
- known adapters support at least the second. */
- if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA
- | I2C_FUNC_SMBUS_BYTE))
+ (2) Word reads (128% overhead)
+ (3) Consecutive byte reads (88% overhead, unsafe)
+ (4) Regular byte data reads (265% overhead)
+ The third and fourth methods are not implemented by this driver
+ because all known adapters support one of the first two. */
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_WORD_DATA)
+ && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK))
goto exit;
if (!(data = kzalloc(sizeof(struct eeprom_data), GFP_KERNEL))) {
@@ -212,13 +210,14 @@ static int eeprom_detect(struct i2c_adapter *adapter, int address, int kind)
/* Detect the Vaio nature of EEPROMs.
We use the "PCG-" or "VGN-" prefix as the signature. */
- if (address == 0x57) {
+ if (address == 0x57
+ && i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
char name[4];
name[0] = i2c_smbus_read_byte_data(new_client, 0x80);
- name[1] = i2c_smbus_read_byte(new_client);
- name[2] = i2c_smbus_read_byte(new_client);
- name[3] = i2c_smbus_read_byte(new_client);
+ name[1] = i2c_smbus_read_byte_data(new_client, 0x81);
+ name[2] = i2c_smbus_read_byte_data(new_client, 0x82);
+ name[3] = i2c_smbus_read_byte_data(new_client, 0x83);
if (!memcmp(name, "PCG-", 4) || !memcmp(name, "VGN-", 4)) {
dev_info(&new_client->dev, "Vaio EEPROM detected, "