diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2016-10-24 19:37:33 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2016-10-24 19:37:34 +0100 |
commit | fe4c04071f702e008da7db06d0a220b27e1ab3ac (patch) | |
tree | 97c3699d2cd15ec48436d53218178b903389f6e3 /hw/i2c | |
parent | 45b567d645c22fb79f4698a13396718084f7cf72 (diff) | |
parent | cc083d8a25e0a886c3cd4bea0bf57ac4e896fa3f (diff) | |
download | qemu-fe4c04071f702e008da7db06d0a220b27e1ab3ac.zip qemu-fe4c04071f702e008da7db06d0a220b27e1ab3ac.tar.gz qemu-fe4c04071f702e008da7db06d0a220b27e1ab3ac.tar.bz2 |
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20161024' into staging
target-arm queue:
* support variable (runtime-determined) page sizes, for a
nearly-20% speedup of TCG for ARMv7 and v8 CPUs with 4K pages
* ptimer: add tests, support more flexible behaviour around
what happens on the "zero" tick, use ptimer for a9gtimer
* virt: ACPI: Add IORT Structure definition
* i2c: Fix SMBus read transactions to avoid double events
* timer: stm32f2xx_timer: add check for prescaler value
* QOMify musicpal, pxa2xx_gpio, strongarm, pl110
* target-arm: Implement new HLT trap for semihosting
* i2c: Add asserts for second smbus i2c_start_transfer()
# gpg: Signature made Mon 24 Oct 2016 18:24:17 BST
# gpg: using RSA key 0x3C2525ED14360CDE
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>"
# gpg: aka "Peter Maydell <pmaydell@gmail.com>"
# gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>"
# Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE
* remotes/pmaydell/tags/pull-target-arm-20161024: (32 commits)
i2c: Add asserts for second smbus i2c_start_transfer()
target-arm: Implement new HLT trap for semihosting
hw/display: QOM'ify pl110.c
hw/arm: QOM'ify strongarm.c
hw/arm: QOM'ify pxa2xx_gpio.c
hw/arm: QOM'ify musicpal.c
timer: stm32f2xx_timer: add check for prescaler value
i2c: Fix SMBus read transactions to avoid double events
timer: a9gtimer: remove loop to auto-increment comparator
ARM: Virt: ACPI: Build an IORT table with RC and ITS nodes
ACPI: Add IORT Structure definition
tests: Add tests for the ARM MPTimer
arm_mptimer: Convert to use ptimer
tests: ptimer: Replace 10000 with 1
tests: ptimer: Change the copyright comment
tests: ptimer: Add tests for "no counter round down" policy
hw/ptimer: Add "no counter round down" policy
tests: ptimer: Add tests for "no immediate reload" policy
hw/ptimer: Add "no immediate reload" policy
tests: ptimer: Add tests for "no immediate trigger" policy
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/i2c')
-rw-r--r-- | hw/i2c/core.c | 39 | ||||
-rw-r--r-- | hw/i2c/smbus.c | 12 |
2 files changed, 34 insertions, 17 deletions
diff --git a/hw/i2c/core.c b/hw/i2c/core.c index 4afbe0b..abd4c4c 100644 --- a/hw/i2c/core.c +++ b/hw/i2c/core.c @@ -88,7 +88,12 @@ int i2c_bus_busy(I2CBus *bus) return !QLIST_EMPTY(&bus->current_devs); } -/* Returns non-zero if the address is not valid. */ +/* + * Returns non-zero if the address is not valid. If this is called + * again without an intervening i2c_end_transfer(), like in the SMBus + * case where the operation is switched from write to read, this + * function will not rescan the bus and thus cannot fail. + */ /* TODO: Make this handle multiple masters. */ int i2c_start_transfer(I2CBus *bus, uint8_t address, int recv) { @@ -104,15 +109,25 @@ int i2c_start_transfer(I2CBus *bus, uint8_t address, int recv) bus->broadcast = true; } - QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) { - DeviceState *qdev = kid->child; - I2CSlave *candidate = I2C_SLAVE(qdev); - if ((candidate->address == address) || (bus->broadcast)) { - node = g_malloc(sizeof(struct I2CNode)); - node->elt = candidate; - QLIST_INSERT_HEAD(&bus->current_devs, node, next); - if (!bus->broadcast) { - break; + /* + * If there are already devices in the list, that means we are in + * the middle of a transaction and we shouldn't rescan the bus. + * + * This happens with any SMBus transaction, even on a pure I2C + * device. The interface does a transaction start without + * terminating the previous transaction. + */ + if (QLIST_EMPTY(&bus->current_devs)) { + QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) { + DeviceState *qdev = kid->child; + I2CSlave *candidate = I2C_SLAVE(qdev); + if ((candidate->address == address) || (bus->broadcast)) { + node = g_malloc(sizeof(struct I2CNode)); + node->elt = candidate; + QLIST_INSERT_HEAD(&bus->current_devs, node, next); + if (!bus->broadcast) { + break; + } } } } @@ -137,10 +152,6 @@ void i2c_end_transfer(I2CBus *bus) I2CSlaveClass *sc; I2CNode *node, *next; - if (QLIST_EMPTY(&bus->current_devs)) { - return; - } - QLIST_FOREACH_SAFE(node, &bus->current_devs, next, next) { sc = I2C_SLAVE_GET_CLASS(node->elt); if (sc->event) { diff --git a/hw/i2c/smbus.c b/hw/i2c/smbus.c index 3979b3d..5b4dd3e 100644 --- a/hw/i2c/smbus.c +++ b/hw/i2c/smbus.c @@ -248,7 +248,9 @@ int smbus_read_byte(I2CBus *bus, uint8_t addr, uint8_t command) return -1; } i2c_send(bus, command); - i2c_start_transfer(bus, addr, 1); + if (i2c_start_transfer(bus, addr, 1)) { + assert(0); + } data = i2c_recv(bus); i2c_nack(bus); i2c_end_transfer(bus); @@ -273,7 +275,9 @@ int smbus_read_word(I2CBus *bus, uint8_t addr, uint8_t command) return -1; } i2c_send(bus, command); - i2c_start_transfer(bus, addr, 1); + if (i2c_start_transfer(bus, addr, 1)) { + assert(0); + } data = i2c_recv(bus); data |= i2c_recv(bus) << 8; i2c_nack(bus); @@ -302,7 +306,9 @@ int smbus_read_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data) return -1; } i2c_send(bus, command); - i2c_start_transfer(bus, addr, 1); + if (i2c_start_transfer(bus, addr, 1)) { + assert(0); + } len = i2c_recv(bus); if (len > 32) { len = 0; |