[Qemu-devel] [PATCH 1/1] etsec: fix IRQ (un)masking

2018-07-12 Thread Michael Davidsaver
Interrupt conditions occurring while masked are not being
signaled when later unmasked.
The fix is to raise/lower IRQs when IMASK is changed.

To avoid problems like this in future, consolidate
IRQ pin update logic in one function.

Also fix probable typo "IEVENT_TXF | IEVENT_TXF",
and update IRQ pins on reset.

Signed-off-by: Michael Davidsaver 
Reviewed-by: Cédric Le Goater 
---
 hw/net/fsl_etsec/etsec.c | 68 +++-
 hw/net/fsl_etsec/etsec.h |  2 ++
 hw/net/fsl_etsec/registers.h | 10 +++
 hw/net/fsl_etsec/rings.c | 12 +---
 4 files changed, 49 insertions(+), 43 deletions(-)

diff --git a/hw/net/fsl_etsec/etsec.c b/hw/net/fsl_etsec/etsec.c
index 9da1932970..0b66274ce3 100644
--- a/hw/net/fsl_etsec/etsec.c
+++ b/hw/net/fsl_etsec/etsec.c
@@ -49,6 +49,28 @@ static const int debug_etsec;
 }  \
 } while (0)
 
+/* call after any change to IEVENT or IMASK */
+void etsec_update_irq(eTSEC *etsec)
+{
+uint32_t ievent = etsec->regs[IEVENT].value;
+uint32_t imask  = etsec->regs[IMASK].value;
+uint32_t active = ievent & imask;
+
+int tx  = !!(active & IEVENT_TX_MASK);
+int rx  = !!(active & IEVENT_RX_MASK);
+int err = !!(active & IEVENT_ERR_MASK);
+
+DPRINTF("%s IRQ ievent=%"PRIx32" imask=%"PRIx32" %c%c%c",
+__func__, ievent, imask,
+tx  ? 'T' : '_',
+rx  ? 'R' : '_',
+err ? 'E' : '_');
+
+qemu_set_irq(etsec->tx_irq, tx);
+qemu_set_irq(etsec->rx_irq, rx);
+qemu_set_irq(etsec->err_irq, err);
+}
+
 static uint64_t etsec_read(void *opaque, hwaddr addr, unsigned size)
 {
 eTSEC  *etsec = opaque;
@@ -139,31 +161,6 @@ static void write_rbasex(eTSEC  *etsec,
 etsec->regs[RBPTR0 + (reg_index - RBASE0)].value = value & ~0x7;
 }
 
-static void write_ievent(eTSEC  *etsec,
- eTSEC_Register *reg,
- uint32_treg_index,
- uint32_tvalue)
-{
-/* Write 1 to clear */
-reg->value &= ~value;
-
-if (!(reg->value & (IEVENT_TXF | IEVENT_TXF))) {
-qemu_irq_lower(etsec->tx_irq);
-}
-if (!(reg->value & (IEVENT_RXF | IEVENT_RXF))) {
-qemu_irq_lower(etsec->rx_irq);
-}
-
-if (!(reg->value & (IEVENT_MAG | IEVENT_GTSC | IEVENT_GRSC | IEVENT_TXC |
-IEVENT_RXC | IEVENT_BABR | IEVENT_BABT | IEVENT_LC |
-IEVENT_CRL | IEVENT_FGPI | IEVENT_FIR | IEVENT_FIQ |
-IEVENT_DPE | IEVENT_PERR | IEVENT_EBERR | IEVENT_TXE |
-IEVENT_XFUN | IEVENT_BSY | IEVENT_MSRO | IEVENT_MMRD |
-IEVENT_MMRW))) {
-qemu_irq_lower(etsec->err_irq);
-}
-}
-
 static void write_dmactrl(eTSEC  *etsec,
   eTSEC_Register *reg,
   uint32_treg_index,
@@ -178,9 +175,7 @@ static void write_dmactrl(eTSEC  *etsec,
 } else {
 /* Graceful receive stop now */
 etsec->regs[IEVENT].value |= IEVENT_GRSC;
-if (etsec->regs[IMASK].value & IMASK_GRSCEN) {
-qemu_irq_raise(etsec->err_irq);
-}
+etsec_update_irq(etsec);
 }
 }
 
@@ -191,9 +186,7 @@ static void write_dmactrl(eTSEC  *etsec,
 } else {
 /* Graceful transmit stop now */
 etsec->regs[IEVENT].value |= IEVENT_GTSC;
-if (etsec->regs[IMASK].value & IMASK_GTSCEN) {
-qemu_irq_raise(etsec->err_irq);
-}
+etsec_update_irq(etsec);
 }
 }
 
@@ -222,7 +215,16 @@ static void etsec_write(void *opaque,
 
 switch (reg_index) {
 case IEVENT:
-write_ievent(etsec, reg, reg_index, value);
+/* Write 1 to clear */
+reg->value &= ~value;
+
+etsec_update_irq(etsec);
+break;
+
+case IMASK:
+reg->value = value;
+
+etsec_update_irq(etsec);
 break;
 
 case DMACTRL:
@@ -337,6 +339,8 @@ static void etsec_reset(DeviceState *d)
 MII_SR_EXTENDED_STATUS  | MII_SR_100T2_HD_CAPS | MII_SR_100T2_FD_CAPS |
 MII_SR_10T_HD_CAPS  | MII_SR_10T_FD_CAPS   | MII_SR_100X_HD_CAPS  |
 MII_SR_100X_FD_CAPS | MII_SR_100T4_CAPS;
+
+etsec_update_irq(etsec);
 }
 
 static ssize_t etsec_receive(NetClientState *nc,
diff --git a/hw/net/fsl_etsec/etsec.h b/hw/net/fsl_etsec/etsec.h
index 30c828e241..877988572e 100644
--- a/hw/net/fsl_etsec/etsec.h
+++ b/hw/net/fsl_etsec/etsec.h
@@ -163,6 +163,8 @@ DeviceState *etsec_create(hwaddrbase,
   qemu_irq  rx_irq,
   qemu_irq  err_irq);
 
+void etsec_update_irq(eTSEC *etsec);
+
 void etsec_w

Re: [Qemu-devel] [PATCH] etsec: fix IRQ (un)masking

2018-07-07 Thread Michael Davidsaver
On 11/28/2017 05:35 PM, David Gibson wrote:
> On Mon, Nov 27, 2017 at 08:42:13PM -0600, Michael Davidsaver wrote:
>> Interrupt conditions occurring while masked are not being
>> signaled when later unmasked.
>> The fix is to raise/lower IRQs when IMASK is changed.
>>
>> To avoid problems like this in future, consolidate
>> IRQ pin update logic in one function.
>>
>> Also fix probable typo "IEVENT_TXF | IEVENT_TXF",
>> and update IRQ pins on reset.
>>
>> Signed-off-by: Michael Davidsaver 
> 
> Looks sane, but I would like to get an R-b from someone who knows FSL
> better than me before applying.

Any progress on finding a candidate to comment?


>> ---
>>  hw/net/fsl_etsec/etsec.c | 68 
>> +++-
>>  hw/net/fsl_etsec/etsec.h |  2 ++
>>  hw/net/fsl_etsec/registers.h | 10 +++
>>  hw/net/fsl_etsec/rings.c | 12 +---
>>  4 files changed, 49 insertions(+), 43 deletions(-)
>>
>> diff --git a/hw/net/fsl_etsec/etsec.c b/hw/net/fsl_etsec/etsec.c
>> index 9da1932970..0b66274ce3 100644
>> --- a/hw/net/fsl_etsec/etsec.c
>> +++ b/hw/net/fsl_etsec/etsec.c
>> @@ -49,6 +49,28 @@ static const int debug_etsec;
>>  }  \
>>  } while (0)
>>  
>> +/* call after any change to IEVENT or IMASK */
>> +void etsec_update_irq(eTSEC *etsec)
>> +{
>> +uint32_t ievent = etsec->regs[IEVENT].value;
>> +uint32_t imask  = etsec->regs[IMASK].value;
>> +uint32_t active = ievent & imask;
>> +
>> +int tx  = !!(active & IEVENT_TX_MASK);
>> +int rx  = !!(active & IEVENT_RX_MASK);
>> +int err = !!(active & IEVENT_ERR_MASK);
>> +
>> +DPRINTF("%s IRQ ievent=%"PRIx32" imask=%"PRIx32" %c%c%c\n",
>> +__func__, ievent, imask,
>> +tx  ? 'T' : '_',
>> +rx  ? 'R' : '_',
>> +err ? 'E' : '_');
>> +
>> +qemu_set_irq(etsec->tx_irq, tx);
>> +qemu_set_irq(etsec->rx_irq, rx);
>> +qemu_set_irq(etsec->err_irq, err);
>> +}
>> +
>>  static uint64_t etsec_read(void *opaque, hwaddr addr, unsigned size)
>>  {
>>  eTSEC  *etsec = opaque;
>> @@ -139,31 +161,6 @@ static void write_rbasex(eTSEC  *etsec,
>>  etsec->regs[RBPTR0 + (reg_index - RBASE0)].value = value & ~0x7;
>>  }
>>  
>> -static void write_ievent(eTSEC  *etsec,
>> - eTSEC_Register *reg,
>> - uint32_treg_index,
>> - uint32_tvalue)
>> -{
>> -/* Write 1 to clear */
>> -reg->value &= ~value;
>> -
>> -if (!(reg->value & (IEVENT_TXF | IEVENT_TXF))) {
>> -qemu_irq_lower(etsec->tx_irq);
>> -}
>> -if (!(reg->value & (IEVENT_RXF | IEVENT_RXF))) {
>> -qemu_irq_lower(etsec->rx_irq);
>> -}
>> -
>> -if (!(reg->value & (IEVENT_MAG | IEVENT_GTSC | IEVENT_GRSC | IEVENT_TXC 
>> |
>> -IEVENT_RXC | IEVENT_BABR | IEVENT_BABT | IEVENT_LC |
>> -IEVENT_CRL | IEVENT_FGPI | IEVENT_FIR | IEVENT_FIQ |
>> -IEVENT_DPE | IEVENT_PERR | IEVENT_EBERR | 
>> IEVENT_TXE |
>> -IEVENT_XFUN | IEVENT_BSY | IEVENT_MSRO | 
>> IEVENT_MMRD |
>> -IEVENT_MMRW))) {
>> -qemu_irq_lower(etsec->err_irq);
>> -}
>> -}
>> -
>>  static void write_dmactrl(eTSEC  *etsec,
>>eTSEC_Register *reg,
>>uint32_treg_index,
>> @@ -178,9 +175,7 @@ static void write_dmactrl(eTSEC  *etsec,
>>  } else {
>>  /* Graceful receive stop now */
>>  etsec->regs[IEVENT].value |= IEVENT_GRSC;
>> -if (etsec->regs[IMASK].value & IMASK_GRSCEN) {
>> -qemu_irq_raise(etsec->err_irq);
>> -}
>> +etsec_update_irq(etsec);
>>  }
>>  }
>>  
>> @@ -191,9 +186,7 @@ static void write_dmactrl(eTSEC  *etsec,
>>  } else {
>>  /* Graceful transmit stop now */
>>  etsec->regs[IEVENT].value |= IEVENT_GTSC;
>> -if (etsec->regs[IMASK].value & IMASK_GTSCEN) {
>> -qemu_irq_raise(etsec->err_irq);
>> -}
>> 

Re: [Qemu-devel] [PATCH 03/14] timer: ds1338 persist 12-hour mode selection

2018-07-07 Thread Michael Davidsaver
On 07/05/2018 09:35 PM, Michael Davidsaver wrote:
> Also, I though I had test coverage of this bug.  That's actually how I
> noticed it to begin with.  But it seems my later change to allow for a
> slow test runner also stopped testing readback of the 12/24 hour mode bit.
> It just silently uses whichever it reads.  I'll be re-issuing an updated
> version which restores this check.  Then you will be able to easily
> see the effect of reverting 'timer: ds1338 persist 12-hour mode selection'.

I've posted revised versions of two of the three test patches #6 and #7
(which I've hopefully posted correctly...).  #6 again tests for this issue.
So you can demonstrate the problem by either applying 1,2,4-6, or just 1 and 6
to see that the issue is present in the original implementation.

The test failure should be:

> test_rtc_set: assertion failed (mode_expect == mode_actual): (1 == 0)

Which shows that a write with 12 hour mode is read back as 24 hour mode.

Similarly, omitting patch #5 will cause the tests added in #7 to fail.



signature.asc
Description: OpenPGP digital signature


[Qemu-devel] [PATCH v2 07/14] tests: ds-rtc test wday offset

2018-07-07 Thread Michael Davidsaver
Signed-off-by: Michael Davidsaver 
---
 tests/ds-rtc-common.h   | 10 +++---
 tests/ds-rtc-current-test.c |  9 -
 tests/ds-rtc-set-test.c |  6 --
 3 files changed, 19 insertions(+), 6 deletions(-)

diff --git a/tests/ds-rtc-common.h b/tests/ds-rtc-common.h
index 5bc7ab32a6..782ea60453 100644
--- a/tests/ds-rtc-common.h
+++ b/tests/ds-rtc-common.h
@@ -20,7 +20,7 @@ static uint8_t addr;
 static bool use_century;
 
 /* input buffer must have at least 7 elements */
-static inline time_t rtc_parse(const uint8_t *buf, int *mmode)
+static inline time_t rtc_parse(const uint8_t *buf, unsigned *wday, int *mmode)
 {
 struct tm parts;
 
@@ -51,10 +51,14 @@ static inline time_t rtc_parse(const uint8_t *buf, int 
*mmode)
 parts.tm_year += 100u;
 }
 
+if (wday) {
+*wday = parts.tm_wday;
+}
+
 return mktimegm();
 }
 
-static time_t rtc_gettime(int *mmode)
+static time_t rtc_gettime(unsigned *wday, int *mmode)
 {
 uint8_t buf[7];
 
@@ -64,7 +68,7 @@ static time_t rtc_gettime(int *mmode)
 /* read back current time registers */
 i2c_recv(i2c, addr, buf, 7);
 
-return rtc_parse(buf, mmode);
+return rtc_parse(buf, wday, mmode);
 }
 
 #endif /* DSRTCCOMMON_H */
diff --git a/tests/ds-rtc-current-test.c b/tests/ds-rtc-current-test.c
index 3c15482a9d..08d8411671 100644
--- a/tests/ds-rtc-current-test.c
+++ b/tests/ds-rtc-current-test.c
@@ -20,17 +20,24 @@
 static
 void test_rtc_current(void)
 {
+struct tm tm_actual;
 time_t expected, actual;
 /* relax test to limit false positives when host may be overloaded.
  * Allow larger delta when running "-m quick"
  */
 time_t max_delta = g_test_slow() ? 1 : 30;
 
+unsigned wday_expect;
+
 actual = time(NULL);
 /* new second may start here */
-expected = rtc_gettime(NULL);
+expected = rtc_gettime(_expect, NULL);
+
+gmtime_r(, _actual);
+
 g_assert_cmpuint(expected, <=, actual + max_delta);
 g_assert_cmpuint(expected, >=, actual);
+g_assert_cmpuint(wday_expect, ==, tm_actual.tm_wday);
 }
 
 int main(int argc, char *argv[])
diff --git a/tests/ds-rtc-set-test.c b/tests/ds-rtc-set-test.c
index 3a742e897f..1004470931 100644
--- a/tests/ds-rtc-set-test.c
+++ b/tests/ds-rtc-set-test.c
@@ -124,17 +124,19 @@ void test_rtc_set(const void *raw)
 
 const uint8_t *testtime = raw;
 time_t expected, actual;
+unsigned wday_expect, wday_actual;
 int mode_expect, mode_actual;
 
 /* skip address pointer and parse remainder */
-expected = rtc_parse([1], _expect);
+expected = rtc_parse([1], _expect, _expect);
 
 i2c_send(i2c, addr, testtime, 8);
 /* host may start new second here */
-actual = rtc_gettime(_actual);
+actual = rtc_gettime(_actual, _actual);
 
 g_assert_cmpuint(expected, <=, actual);
 g_assert_cmpuint(expected + max_delta, >=, actual);
+g_assert_cmpuint(wday_expect, ==, wday_actual);
 g_assert_cmpint(mode_expect, ==, mode_actual);
 }
 
-- 
2.11.0




[Qemu-devel] [PATCH v2 06/14] tests: ds-rtc test 12 hour mode

2018-07-07 Thread Michael Davidsaver
Signed-off-by: Michael Davidsaver 
---
 tests/ds-rtc-common.h   |  9 ---
 tests/ds-rtc-current-test.c |  2 +-
 tests/ds-rtc-set-test.c | 58 +++--
 3 files changed, 63 insertions(+), 6 deletions(-)

diff --git a/tests/ds-rtc-common.h b/tests/ds-rtc-common.h
index c8e6c2bc5b..5bc7ab32a6 100644
--- a/tests/ds-rtc-common.h
+++ b/tests/ds-rtc-common.h
@@ -20,12 +20,15 @@ static uint8_t addr;
 static bool use_century;
 
 /* input buffer must have at least 7 elements */
-static inline time_t rtc_parse(const uint8_t *buf)
+static inline time_t rtc_parse(const uint8_t *buf, int *mmode)
 {
 struct tm parts;
 
 parts.tm_sec = from_bcd(buf[0]);
 parts.tm_min = from_bcd(buf[1]);
+if (mmode) {
+*mmode = !!(buf[2] & 0x40);
+}
 if (buf[2] & 0x40) {
 /* 12 hour */
 /* HOUR register is 1-12. */
@@ -51,7 +54,7 @@ static inline time_t rtc_parse(const uint8_t *buf)
 return mktimegm();
 }
 
-static time_t rtc_gettime(void)
+static time_t rtc_gettime(int *mmode)
 {
 uint8_t buf[7];
 
@@ -61,7 +64,7 @@ static time_t rtc_gettime(void)
 /* read back current time registers */
 i2c_recv(i2c, addr, buf, 7);
 
-return rtc_parse(buf);
+return rtc_parse(buf, mmode);
 }
 
 #endif /* DSRTCCOMMON_H */
diff --git a/tests/ds-rtc-current-test.c b/tests/ds-rtc-current-test.c
index 6acbbed9a6..3c15482a9d 100644
--- a/tests/ds-rtc-current-test.c
+++ b/tests/ds-rtc-current-test.c
@@ -28,7 +28,7 @@ void test_rtc_current(void)
 
 actual = time(NULL);
 /* new second may start here */
-expected = rtc_gettime();
+expected = rtc_gettime(NULL);
 g_assert_cmpuint(expected, <=, actual + max_delta);
 g_assert_cmpuint(expected, >=, actual);
 }
diff --git a/tests/ds-rtc-set-test.c b/tests/ds-rtc-set-test.c
index 35e1a36281..3a742e897f 100644
--- a/tests/ds-rtc-set-test.c
+++ b/tests/ds-rtc-set-test.c
@@ -29,6 +29,18 @@ static uint8_t test_time_24_12am[8] = {
 0x17,
 };
 
+static uint8_t test_time_12_12am[8] = {
+0, /* address */
+/* Wed, 22 Nov 2017 00:30:53 + */
+0x53,
+0x30,
+0x52, /* 12 AM in 12 hour mode */
+0x03, /* monday is our day 1 */
+0x22,
+0x11 | 0x80,
+0x17,
+};
+
 static uint8_t test_time_24_6am[8] = {
 0, /* address */
 /* Wed, 22 Nov 2017 06:30:53 + */
@@ -41,6 +53,18 @@ static uint8_t test_time_24_6am[8] = {
 0x17,
 };
 
+static uint8_t test_time_12_6am[8] = {
+0, /* address */
+/* Wed, 22 Nov 2017 06:30:53 + */
+0x53,
+0x30,
+0x46, /* 6 AM in 12 hour mode */
+0x03, /* monday is our day 1 */
+0x22,
+0x11 | 0x80,
+0x17,
+};
+
 static uint8_t test_time_24_12pm[8] = {
 0, /* address */
 /* Wed, 22 Nov 2017 12:30:53 + */
@@ -53,6 +77,18 @@ static uint8_t test_time_24_12pm[8] = {
 0x17,
 };
 
+static uint8_t test_time_12_12pm[8] = {
+0, /* address */
+/* Wed, 22 Nov 2017 12:30:53 + */
+0x53,
+0x30,
+0x72, /* 12 PM in 24 hour mode */
+0x03, /* monday is our day 1 */
+0x22,
+0x11 | 0x80,
+0x17,
+};
+
 static uint8_t test_time_24_6pm[8] = {
 0, /* address */
 /* Wed, 22 Nov 2017 18:30:53 + */
@@ -65,6 +101,18 @@ static uint8_t test_time_24_6pm[8] = {
 0x17,
 };
 
+static uint8_t test_time_12_6pm[8] = {
+0, /* address */
+/* Wed, 22 Nov 2017 18:30:53 + */
+0x53,
+0x30,
+0x66, /* 6 PM in 12 hour mode */
+0x03, /* monday is our day 1 */
+0x22,
+0x11 | 0x80,
+0x17,
+};
+
 /* write in and read back known time */
 static
 void test_rtc_set(const void *raw)
@@ -76,16 +124,18 @@ void test_rtc_set(const void *raw)
 
 const uint8_t *testtime = raw;
 time_t expected, actual;
+int mode_expect, mode_actual;
 
 /* skip address pointer and parse remainder */
-expected = rtc_parse([1]);
+expected = rtc_parse([1], _expect);
 
 i2c_send(i2c, addr, testtime, 8);
 /* host may start new second here */
-actual = rtc_gettime();
+actual = rtc_gettime(_actual);
 
 g_assert_cmpuint(expected, <=, actual);
 g_assert_cmpuint(expected + max_delta, >=, actual);
+g_assert_cmpint(mode_expect, ==, mode_actual);
 }
 
 int main(int argc, char *argv[])
@@ -108,6 +158,10 @@ int main(int argc, char *argv[])
 qtest_add_data_func("/ds-rtc-i2c/set24_6am", test_time_24_6am, 
test_rtc_set);
 qtest_add_data_func("/ds-rtc-i2c/set24_12pm", test_time_24_12pm, 
test_rtc_set);
 qtest_add_data_func("/ds-rtc-i2c/set24_6pm", test_time_24_6pm, 
test_rtc_set);
+qtest_add_data_func("/ds-rtc-i2c/set12_12am", test_time_12_12am, 
test_rtc_set);
+qtest_add_data_func("/ds-rtc-i2c/set12_6am", test_time_12_6am, 
test_rtc_set);
+qtest_add_data_func("/ds-rtc-i2c/set12_12pm", test_time_12_12pm, 
test_rtc_set);
+qtest_add_data_func("/ds-rtc-i2c/set12_6pm", test_time_12_6pm, 
test_rtc_set);
 
 ret = g_test_run();
 
-- 
2.11.0




Re: [Qemu-devel] [PATCH 03/14] timer: ds1338 persist 12-hour mode selection

2018-07-05 Thread Michael Davidsaver
On 07/05/2018 08:39 PM, David Gibson wrote:
> On Thu, Jul 05, 2018 at 11:19:50AM -0700, Michael Davidsaver wrote:
> 11;rgb://> Need to save HOUR[HOUR12] bit to keep
>> track of guest selection of 12-hour mode.
>> Write through current time registers to
>> achieve this.  Will be overwritten
>> by the next read/latch.
>>
>> This was only being done in two of three
>> arms of this conditional block.
>>
>> Signed-off-by: Michael Davidsaver 
> 
> This looks dubious to me, or at least the explanation of it does.  The
> other branch of the conditional is covering different registers in the
> device, which are part of the RTC component, rather than the NVRAM
> area.  I wouldn't necessarily expect them to persist data as a rule
> the way the rest of the block does, even if this specific bit does
> need to be preserved.

The fact that the above capture_current_time() included the line

> if (s->nvram[2] & HOURS_12) {

was enough to convince me that the original author intended to persist
the 12/24 hour mode in this way.  There are certainly other ways to
accomplish this, but they would involved adding to the vmstate,
which I've tried to avoid in this iteration.


Also, I though I had test coverage of this bug.  That's actually how I
noticed it to begin with.  But it seems my later change to allow for a
slow test runner also stopped testing readback of the 12/24 hour mode bit.
It just silently uses whichever it reads.  I'll be re-issuing an updated
version which restores this check.  Then you will be able to easily
see the effect of reverting 'timer: ds1338 persist 12-hour mode selection'.



>> ---
>>  hw/timer/ds1338.c | 4 +---
>>  1 file changed, 1 insertion(+), 3 deletions(-)
>>
>> diff --git a/hw/timer/ds1338.c b/hw/timer/ds1338.c
>> index 7298c5af43..b56db5852e 100644
>> --- a/hw/timer/ds1338.c
>> +++ b/hw/timer/ds1338.c
>> @@ -220,10 +220,8 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
>> value unchanged. */
>>  data = (data & ~CTRL_OSF) | (data & s->nvram[s->ptr] & CTRL_OSF);
>>  
>> -s->nvram[s->ptr] = data;
>> -} else {
>> -s->nvram[s->ptr] = data;
>>  }
>> +s->nvram[s->ptr] = data;
>>  inc_regptr(s);
>>  return 0;
>>  }
> 




signature.asc
Description: OpenPGP digital signature


[Qemu-devel] [PATCH 14/14] tests: drop ds1338-test

2018-07-05 Thread Michael Davidsaver
redundant to ds-rtc-*-test.c

Signed-off-by: Michael Davidsaver 
---
 tests/Makefile.include |  2 --
 tests/ds1338-test.c| 75 --
 2 files changed, 77 deletions(-)
 delete mode 100644 tests/ds1338-test.c

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 6ce5a9ff4d..8cf438260b 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -377,7 +377,6 @@ check-qtest-sparc64-y += tests/boot-serial-test$(EXESUF)
 
 check-qtest-arm-y = tests/tmp105-test$(EXESUF)
 check-qtest-arm-y += tests/pca9552-test$(EXESUF)
-check-qtest-arm-y += tests/ds1338-test$(EXESUF)
 check-qtest-arm-y += tests/ds-rtc-current-test$(EXESUF)
 check-qtest-arm-y += tests/ds-rtc-set-test$(EXESUF)
 check-qtest-arm-y += tests/m25p80-test$(EXESUF)
@@ -788,7 +787,6 @@ tests/bios-tables-test$(EXESUF): tests/bios-tables-test.o \
 tests/pxe-test$(EXESUF): tests/pxe-test.o tests/boot-sector.o $(libqos-obj-y)
 tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y)
 tests/pca9552-test$(EXESUF): tests/pca9552-test.o $(libqos-omap-obj-y)
-tests/ds1338-test$(EXESUF): tests/ds1338-test.o $(libqos-imx-obj-y)
 tests/ds-rtc-current-test$(EXESUF): tests/ds-rtc-current-test.o 
$(libqos-imx-obj-y)
 tests/ds-rtc-set-test$(EXESUF): tests/ds-rtc-set-test.o $(libqos-imx-obj-y)
 tests/m25p80-test$(EXESUF): tests/m25p80-test.o
diff --git a/tests/ds1338-test.c b/tests/ds1338-test.c
deleted file mode 100644
index 742dad9113..00
--- a/tests/ds1338-test.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * QTest testcase for the DS1338 RTC
- *
- * Copyright (c) 2013 Jean-Christophe Dubois
- *
- *  This program is free software; you can redistribute it and/or modify it
- *  under the terms of the GNU General Public License as published by the
- *  Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful, but WITHOUT
- *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- *  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- *  for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest.h"
-#include "libqos/i2c.h"
-
-#define IMX25_I2C_0_BASE 0x43F8
-
-#define DS1338_ADDR 0x68
-
-static I2CAdapter *i2c;
-static uint8_t addr;
-
-static inline uint8_t bcd2bin(uint8_t x)
-{
-return ((x) & 0x0f) + ((x) >> 4) * 10;
-}
-
-static void send_and_receive(void)
-{
-uint8_t cmd[1];
-uint8_t resp[7];
-time_t now = time(NULL);
-struct tm *tm_ptr = gmtime();
-
-/* reset the index in the RTC memory */
-cmd[0] = 0;
-i2c_send(i2c, addr, cmd, 1);
-
-/* retrieve the date */
-i2c_recv(i2c, addr, resp, 7);
-
-/* check retrieved time againt local time */
-g_assert_cmpuint(bcd2bin(resp[4]), == , tm_ptr->tm_mday);
-g_assert_cmpuint(bcd2bin(resp[5]), == , 1 + tm_ptr->tm_mon);
-g_assert_cmpuint(2000 + bcd2bin(resp[6]), == , 1900 + tm_ptr->tm_year);
-}
-
-int main(int argc, char **argv)
-{
-QTestState *s = NULL;
-int ret;
-
-g_test_init(, , NULL);
-
-s = qtest_start("-display none -machine imx25-pdk");
-i2c = imx_i2c_create(s, IMX25_I2C_0_BASE);
-addr = DS1338_ADDR;
-
-qtest_add_func("/ds1338/tx-rx", send_and_receive);
-
-ret = g_test_run();
-
-qtest_quit(s);
-g_free(i2c);
-
-return ret;
-}
-- 
2.11.0




[Qemu-devel] [PATCH 13/14] timer: ds-rtc model ds1375

2018-07-05 Thread Michael Davidsaver
differences from ds1338

* Has alarms (not modeled)
* different control register (not modeled)
* smaller address space (0x20 vs. 0x40)

Signed-off-by: Michael Davidsaver 
Reviewed-by: Peter Maydell 
---
 hw/timer/ds-rtc.c | 30 --
 1 file changed, 28 insertions(+), 2 deletions(-)

diff --git a/hw/timer/ds-rtc.c b/hw/timer/ds-rtc.c
index 9abac38628..3a8ad1a00f 100644
--- a/hw/timer/ds-rtc.c
+++ b/hw/timer/ds-rtc.c
@@ -1,8 +1,9 @@
 /*
- * MAXIM DS1338 I2C RTC+NVRAM
+ * MAXIM/Dallas DS1338 and DS1375 I2C RTC+NVRAM
  *
+ * Copyright (c) 2018 Michael Davidsaver
  * Copyright (c) 2009 CodeSourcery.
- * Written by Paul Brook
+ * Written by Paul Brook, Michael Davidsaver
  *
  * This code is licensed under the GNU GPL v2.
  *
@@ -41,6 +42,7 @@
 #define R_YEAR  (0x6)
 
 #define R_DS1338_CTRL (0x7)
+#define R_DS1375_CTRL (0xe)
 
 /* use 12 hour mode when set */
 FIELD(HOUR, SET12, 6, 1)
@@ -300,10 +302,34 @@ static const TypeInfo ds1338_info = {
 .class_init= ds1338_class_init,
 };
 
+static void ds1375_control_write(DSRTCState *s, uint8_t data)
+{
+/* just store it, we don't model any features */
+s->nvram[R_DS1375_CTRL] = data;
+}
+
+static void ds1375_class_init(ObjectClass *klass, void *data)
+{
+DSRTCClass *k = DSRTC_CLASS(klass);
+
+k->has_century = true;
+k->addr_size = 0x20;
+k->ctrl_offset = R_DS1375_CTRL;
+k->ctrl_write = ds1375_control_write;
+}
+
+static const TypeInfo ds1375_info = {
+.name  = "ds1375",
+.parent= TYPE_DSRTC,
+.class_size= sizeof(DSRTCClass),
+.class_init= ds1375_class_init,
+};
+
 static void dsrtc_register_types(void)
 {
 type_register_static(_info);
 type_register_static(_info);
+type_register_static(_info);
 }
 
 type_init(dsrtc_register_types)
-- 
2.11.0




[Qemu-devel] [PATCH 09/14] timer: rename file ds1338.c -> ds-rtc.c

2018-07-05 Thread Michael Davidsaver
Signed-off-by: Michael Davidsaver 
Reviewed-by: Peter Maydell 
---
 default-configs/arm-softmmu.mak | 2 +-
 hw/timer/Makefile.objs  | 2 +-
 hw/timer/{ds1338.c => ds-rtc.c} | 0
 3 files changed, 2 insertions(+), 2 deletions(-)
 rename hw/timer/{ds1338.c => ds-rtc.c} (100%)

diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index 834d45cfaf..84f42b821b 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -34,7 +34,7 @@ CONFIG_SMC91C111=y
 CONFIG_ALLWINNER_EMAC=y
 CONFIG_IMX_FEC=y
 CONFIG_FTGMAC100=y
-CONFIG_DS1338=y
+CONFIG_DSRTC=y
 CONFIG_PFLASH_CFI01=y
 CONFIG_PFLASH_CFI02=y
 CONFIG_MICRODRIVE=y
diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs
index e16b2b913c..b3d3b80232 100644
--- a/hw/timer/Makefile.objs
+++ b/hw/timer/Makefile.objs
@@ -3,7 +3,7 @@ common-obj-$(CONFIG_ARM_MPTIMER) += arm_mptimer.o
 common-obj-$(CONFIG_ARM_V7M) += armv7m_systick.o
 common-obj-$(CONFIG_A9_GTIMER) += a9gtimer.o
 common-obj-$(CONFIG_CADENCE) += cadence_ttc.o
-common-obj-$(CONFIG_DS1338) += ds1338.o
+common-obj-$(CONFIG_DSRTC) += ds-rtc.o
 common-obj-$(CONFIG_HPET) += hpet.o
 common-obj-$(CONFIG_I8254) += i8254_common.o i8254.o
 common-obj-$(CONFIG_M41T80) += m41t80.o
diff --git a/hw/timer/ds1338.c b/hw/timer/ds-rtc.c
similarity index 100%
rename from hw/timer/ds1338.c
rename to hw/timer/ds-rtc.c
-- 
2.11.0




[Qemu-devel] [PATCH 06/14] tests: ds-rtc test 12 hour mode

2018-07-05 Thread Michael Davidsaver
Signed-off-by: Michael Davidsaver 
---
 tests/ds-rtc-set-test.c | 52 +
 1 file changed, 52 insertions(+)

diff --git a/tests/ds-rtc-set-test.c b/tests/ds-rtc-set-test.c
index 35e1a36281..c48406ee2c 100644
--- a/tests/ds-rtc-set-test.c
+++ b/tests/ds-rtc-set-test.c
@@ -29,6 +29,18 @@ static uint8_t test_time_24_12am[8] = {
 0x17,
 };
 
+static uint8_t test_time_12_12am[8] = {
+0, /* address */
+/* Wed, 22 Nov 2017 00:30:53 + */
+0x53,
+0x30,
+0x52, /* 12 AM in 12 hour mode */
+0x03, /* monday is our day 1 */
+0x22,
+0x11 | 0x80,
+0x17,
+};
+
 static uint8_t test_time_24_6am[8] = {
 0, /* address */
 /* Wed, 22 Nov 2017 06:30:53 + */
@@ -41,6 +53,18 @@ static uint8_t test_time_24_6am[8] = {
 0x17,
 };
 
+static uint8_t test_time_12_6am[8] = {
+0, /* address */
+/* Wed, 22 Nov 2017 06:30:53 + */
+0x53,
+0x30,
+0x46, /* 6 AM in 12 hour mode */
+0x03, /* monday is our day 1 */
+0x22,
+0x11 | 0x80,
+0x17,
+};
+
 static uint8_t test_time_24_12pm[8] = {
 0, /* address */
 /* Wed, 22 Nov 2017 12:30:53 + */
@@ -53,6 +77,18 @@ static uint8_t test_time_24_12pm[8] = {
 0x17,
 };
 
+static uint8_t test_time_12_12pm[8] = {
+0, /* address */
+/* Wed, 22 Nov 2017 12:30:53 + */
+0x53,
+0x30,
+0x72, /* 12 PM in 24 hour mode */
+0x03, /* monday is our day 1 */
+0x22,
+0x11 | 0x80,
+0x17,
+};
+
 static uint8_t test_time_24_6pm[8] = {
 0, /* address */
 /* Wed, 22 Nov 2017 18:30:53 + */
@@ -65,6 +101,18 @@ static uint8_t test_time_24_6pm[8] = {
 0x17,
 };
 
+static uint8_t test_time_12_6pm[8] = {
+0, /* address */
+/* Wed, 22 Nov 2017 18:30:53 + */
+0x53,
+0x30,
+0x66, /* 6 PM in 12 hour mode */
+0x03, /* monday is our day 1 */
+0x22,
+0x11 | 0x80,
+0x17,
+};
+
 /* write in and read back known time */
 static
 void test_rtc_set(const void *raw)
@@ -108,6 +156,10 @@ int main(int argc, char *argv[])
 qtest_add_data_func("/ds-rtc-i2c/set24_6am", test_time_24_6am, 
test_rtc_set);
 qtest_add_data_func("/ds-rtc-i2c/set24_12pm", test_time_24_12pm, 
test_rtc_set);
 qtest_add_data_func("/ds-rtc-i2c/set24_6pm", test_time_24_6pm, 
test_rtc_set);
+qtest_add_data_func("/ds-rtc-i2c/set12_12am", test_time_12_12am, 
test_rtc_set);
+qtest_add_data_func("/ds-rtc-i2c/set12_6am", test_time_12_6am, 
test_rtc_set);
+qtest_add_data_func("/ds-rtc-i2c/set12_12pm", test_time_12_12pm, 
test_rtc_set);
+qtest_add_data_func("/ds-rtc-i2c/set12_6pm", test_time_12_6pm, 
test_rtc_set);
 
 ret = g_test_run();
 
-- 
2.11.0




[Qemu-devel] [PATCH 12/14] timer: ds-rtc handle CENTURY bit

2018-07-05 Thread Michael Davidsaver
Signed-off-by: Michael Davidsaver 
Reviewed-by: Peter Maydell 
---
 hw/timer/ds-rtc.c | 8 +++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/hw/timer/ds-rtc.c b/hw/timer/ds-rtc.c
index 6d3a8b5586..9abac38628 100644
--- a/hw/timer/ds-rtc.c
+++ b/hw/timer/ds-rtc.c
@@ -70,6 +70,7 @@ typedef struct DSRTCState {
 typedef struct DSRTCClass {
 I2CSlaveClass parent_obj;
 
+bool has_century;
 /* actual address space size must be <= NVRAM_SIZE */
 unsigned addr_size;
 unsigned ctrl_offset;
@@ -93,6 +94,7 @@ static const VMStateDescription vmstate_dsrtc = {
 
 static void capture_current_time(DSRTCState *s)
 {
+DSRTCClass *k = DSRTC_GET_CLASS(s);
 /* Capture the current time into the secondary registers
  * which will be actually read by the data transfer operation.
  */
@@ -125,7 +127,10 @@ static void capture_current_time(DSRTCState *s)
 }
 s->nvram[R_DATE] = to_bcd(now.tm_mday);
 s->nvram[R_MONTH] = to_bcd(now.tm_mon + 1);
-s->nvram[R_YEAR] = to_bcd(now.tm_year - 100);
+s->nvram[R_YEAR] = to_bcd(now.tm_year % 100u);
+
+ARRAY_FIELD_DP32(s->nvram, MONTH, CENTURY,
+ k->has_century && now.tm_year >= 100)
 }
 
 static void inc_regptr(DSRTCState *s)
@@ -282,6 +287,7 @@ static void ds1338_class_init(ObjectClass *klass, void 
*data)
 {
 DSRTCClass *k = DSRTC_CLASS(klass);
 
+k->has_century = false;
 k->addr_size = 0x40;
 k->ctrl_offset = R_DS1338_CTRL;
 k->ctrl_write = ds1338_control_write;
-- 
2.11.0




[Qemu-devel] [PATCH 10/14] timer: ds1338 remove vestige of un-modeled OSF

2018-07-05 Thread Michael Davidsaver
Oscillator stop has never been modeled, so the
Oscillator Stop Flag can never be set.

Signed-off-by: Michael Davidsaver 
---
 hw/timer/ds-rtc.c | 14 +-
 1 file changed, 5 insertions(+), 9 deletions(-)

diff --git a/hw/timer/ds-rtc.c b/hw/timer/ds-rtc.c
index 3c5781d53c..126566ce1f 100644
--- a/hw/timer/ds-rtc.c
+++ b/hw/timer/ds-rtc.c
@@ -21,8 +21,6 @@
  */
 #define NVRAM_SIZE 64
 
-#define CTRL_OSF   0x20
-
 #define TYPE_DSRTC "ds1338"
 #define DSRTC(obj) OBJECT_CHECK(DSRTCState, (obj), TYPE_DSRTC)
 
@@ -216,13 +214,11 @@ static int dsrtc_send(I2CSlave *i2c, uint8_t data)
 if (s->ptr == R_CTRL) {
 /* Control register. */
 
-/* Ensure bits 2, 3 and 6 will read back as zero. */
-data &= 0xB3;
-
-/* Attempting to write the OSF flag to logic 1 leaves the
-   value unchanged. */
-data = (data & ~CTRL_OSF) | (data & s->nvram[s->ptr] & CTRL_OSF);
-
+/* Allow guest to set no-op controls for clock out pin and
+ * rate select.  Ignore write 1 to clear OSF.  We don't model
+ * oscillator stop, so it is never set.
+ */
+data = data & 0x93;
 }
 s->nvram[s->ptr] = data;
 if (s->ptr <= R_YEAR) {
-- 
2.11.0




[Qemu-devel] [PATCH 01/14] tests: more thorough tests of ds1338

2018-07-05 Thread Michael Davidsaver
Test current time and set+get round trip.

Separate current time test from set/get tests
to avoid test needing to impose order, or to
have a magic handshaketo reset RTC to current time.

Signed-off-by: Michael Davidsaver 
---
 tests/Makefile.include  |   4 ++
 tests/ds-rtc-common.h   |  67 +
 tests/ds-rtc-current-test.c |  59 ++
 tests/ds-rtc-set-test.c | 117 
 4 files changed, 247 insertions(+)
 create mode 100644 tests/ds-rtc-common.h
 create mode 100644 tests/ds-rtc-current-test.c
 create mode 100644 tests/ds-rtc-set-test.c

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 8859e88ffb..6ce5a9ff4d 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -378,6 +378,8 @@ check-qtest-sparc64-y += tests/boot-serial-test$(EXESUF)
 check-qtest-arm-y = tests/tmp105-test$(EXESUF)
 check-qtest-arm-y += tests/pca9552-test$(EXESUF)
 check-qtest-arm-y += tests/ds1338-test$(EXESUF)
+check-qtest-arm-y += tests/ds-rtc-current-test$(EXESUF)
+check-qtest-arm-y += tests/ds-rtc-set-test$(EXESUF)
 check-qtest-arm-y += tests/m25p80-test$(EXESUF)
 gcov-files-arm-y += hw/misc/tmp105.c
 check-qtest-arm-y += tests/virtio-blk-test$(EXESUF)
@@ -787,6 +789,8 @@ tests/pxe-test$(EXESUF): tests/pxe-test.o 
tests/boot-sector.o $(libqos-obj-y)
 tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y)
 tests/pca9552-test$(EXESUF): tests/pca9552-test.o $(libqos-omap-obj-y)
 tests/ds1338-test$(EXESUF): tests/ds1338-test.o $(libqos-imx-obj-y)
+tests/ds-rtc-current-test$(EXESUF): tests/ds-rtc-current-test.o 
$(libqos-imx-obj-y)
+tests/ds-rtc-set-test$(EXESUF): tests/ds-rtc-set-test.o $(libqos-imx-obj-y)
 tests/m25p80-test$(EXESUF): tests/m25p80-test.o
 tests/i440fx-test$(EXESUF): tests/i440fx-test.o $(libqos-pc-obj-y)
 tests/q35-test$(EXESUF): tests/q35-test.o $(libqos-pc-obj-y)
diff --git a/tests/ds-rtc-common.h b/tests/ds-rtc-common.h
new file mode 100644
index 00..c8e6c2bc5b
--- /dev/null
+++ b/tests/ds-rtc-common.h
@@ -0,0 +1,67 @@
+/* Common code for testing of Dallas/Maxim I2C bus RTC devices
+ *
+ * Copyright (c) 2018 Michael Davidsaver
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the LICENSE file in the top-level directory.
+ */
+#ifndef DSRTCCOMMON_H
+#define DSRTCCOMMON_H
+
+#include "qemu/osdep.h"
+#include "qemu/cutils.h"
+#include "libqos/i2c.h"
+
+#define IMX25_I2C_0_BASE 0x43F8
+#define DS1338_ADDR 0x68
+
+static I2CAdapter *i2c;
+static uint8_t addr;
+static bool use_century;
+
+/* input buffer must have at least 7 elements */
+static inline time_t rtc_parse(const uint8_t *buf)
+{
+struct tm parts;
+
+parts.tm_sec = from_bcd(buf[0]);
+parts.tm_min = from_bcd(buf[1]);
+if (buf[2] & 0x40) {
+/* 12 hour */
+/* HOUR register is 1-12. */
+parts.tm_hour = from_bcd(buf[2] & 0x1f);
+g_assert_cmpuint(parts.tm_hour, >=, 1);
+g_assert_cmpuint(parts.tm_hour, <=, 12);
+parts.tm_hour %= 12u; /* wrap 12 -> 0 */
+if (buf[2] & 0x20) {
+parts.tm_hour += 12u;
+}
+} else {
+/* 24 hour */
+parts.tm_hour = from_bcd(buf[2] & 0x3f);
+}
+parts.tm_wday = from_bcd(buf[3]);
+parts.tm_mday = from_bcd(buf[4]);
+parts.tm_mon =  from_bcd((buf[5] & 0x1f) - 1u);
+parts.tm_year = from_bcd(buf[6]);
+if (!use_century || (buf[5] & 0x80)) {
+parts.tm_year += 100u;
+}
+
+return mktimegm();
+}
+
+static time_t rtc_gettime(void)
+{
+uint8_t buf[7];
+
+/* zero address pointer */
+buf[0] = 0;
+i2c_send(i2c, addr, buf, 1);
+/* read back current time registers */
+i2c_recv(i2c, addr, buf, 7);
+
+return rtc_parse(buf);
+}
+
+#endif /* DSRTCCOMMON_H */
diff --git a/tests/ds-rtc-current-test.c b/tests/ds-rtc-current-test.c
new file mode 100644
index 00..6acbbed9a6
--- /dev/null
+++ b/tests/ds-rtc-current-test.c
@@ -0,0 +1,59 @@
+/* Testing of Dallas/Maxim I2C bus RTC devices
+ *
+ * Copyright (c) 2018 Michael Davidsaver
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the LICENSE file in the top-level directory.
+ */
+#include 
+
+#include "qemu/osdep.h"
+#include "qemu/bcd.h"
+#include "qemu/cutils.h"
+#include "libqtest.h"
+#include "libqos/libqos.h"
+#include "libqos/i2c.h"
+
+#include "ds-rtc-common.h"
+
+/* read back and compare with current system time */
+static
+void test_rtc_current(void)
+{
+time_t expected, actual;
+/* relax test to limit false positives when host may be overloaded.
+ * Allow larger delta when running "-m quick"
+ */
+time_t max_delta = g_test_slow() ? 1 : 30;
+
+actual = time(NULL);
+/* new second may start here */
+expected = rtc_gettime();
+g_assert_cmpuint(exp

[Qemu-devel] [PATCH 05/14] timer: ds1338 change write handling and fix wday_offset handling

2018-07-05 Thread Michael Davidsaver
instead of a read-modify-write, do direct translation
of device registers to struct tm members.

This new ds1338_update() is the reverse of
the existing capture_current_time().

Simplifies later handling of CENTURY bit in
similar Dallas RTC chips.

Correctly handle different real weekday in
guest and host timezones.
Allow guest to use any day as start of week
(day 1).  eg. Monday instead of Sunday.

Signed-off-by: Michael Davidsaver 
---
 hw/timer/ds1338.c | 95 ---
 1 file changed, 48 insertions(+), 47 deletions(-)

diff --git a/hw/timer/ds1338.c b/hw/timer/ds1338.c
index 637a0f4246..0134ffd72a 100644
--- a/hw/timer/ds1338.c
+++ b/hw/timer/ds1338.c
@@ -110,7 +110,10 @@ static void capture_current_time(DS1338State *s)
 /* 24 hour mode. */
 s->nvram[R_HOUR] = to_bcd(now.tm_hour);
 }
-s->nvram[R_WDAY] = (now.tm_wday + s->wday_offset) % 7 + 1;
+s->nvram[R_WDAY] = (now.tm_wday + s->wday_offset) % 7;
+if (s->nvram[R_WDAY] == 0) {
+s->nvram[R_WDAY] = 7;
+}
 s->nvram[R_DATE] = to_bcd(now.tm_mday);
 s->nvram[R_MONTH] = to_bcd(now.tm_mon + 1);
 s->nvram[R_YEAR] = to_bcd(now.tm_year - 100);
@@ -161,6 +164,46 @@ static int ds1338_recv(I2CSlave *i2c)
 return res;
 }
 
+/* call after guest writes to current time registers
+ * to re-compute our offset from host time.
+ */
+static void ds1338_update(DS1338State *s)
+{
+
+struct tm now = {};
+
+/* TODO: Implement CH (stop) bit?  */
+now.tm_sec = from_bcd(s->nvram[R_SEC] & 0x7f);
+now.tm_min = from_bcd(s->nvram[R_MIN] & 0x7f);
+if (ARRAY_FIELD_EX32(s->nvram, HOUR, SET12)) {
+/* 12 hour (1-12) */
+/* read and wrap 1-12 -> 0-11 */
+now.tm_hour = from_bcd(ARRAY_FIELD_EX32(s->nvram, HOUR, HOUR12)) % 12u;
+if (ARRAY_FIELD_EX32(s->nvram, HOUR, AMPM)) {
+now.tm_hour += 12;
+}
+
+} else {
+now.tm_hour = from_bcd(ARRAY_FIELD_EX32(s->nvram, HOUR, HOUR24));
+}
+now.tm_wday = from_bcd(s->nvram[R_WDAY]) - 1u;
+now.tm_mday = from_bcd(s->nvram[R_DATE] & 0x3f);
+now.tm_mon = from_bcd(s->nvram[R_MONTH] & 0x1f) - 1;
+now.tm_year = from_bcd(s->nvram[R_YEAR]) + 100;
+s->offset = qemu_timedate_diff();
+
+{
+/* Round trip to get real wday_offset based on time delta and
+ * ref. timezone.
+ * Race if midnight (in ref. timezone) happens here.
+ */
+int user_wday = now.tm_wday;
+qemu_get_timedate(, s->offset);
+
+s->wday_offset = (user_wday - now.tm_wday) % 7 + 1;
+}
+}
+
 static int ds1338_send(I2CSlave *i2c, uint8_t data)
 {
 DS1338State *s = DS1338(i2c);
@@ -170,52 +213,7 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
 s->addr_byte = false;
 return 0;
 }
-if (s->ptr < 7) {
-/* Time register. */
-struct tm now;
-qemu_get_timedate(, s->offset);
-switch(s->ptr) {
-case R_SEC:
-/* TODO: Implement CH (stop) bit.  */
-now.tm_sec = from_bcd(data & 0x7f);
-break;
-case R_MIN:
-now.tm_min = from_bcd(data & 0x7f);
-break;
-case R_HOUR:
-if (FIELD_EX32(data, HOUR, SET12)) {
-/* 12 hour (1-12) */
-/* read and wrap 1-12 -> 0-11 */
-now.tm_hour = from_bcd(FIELD_EX32(data, HOUR, HOUR12)) % 12u;
-if (FIELD_EX32(data, HOUR, AMPM)) {
-now.tm_hour += 12;
-}
-
-} else {
-now.tm_hour = from_bcd(FIELD_EX32(data, HOUR, HOUR24));
-}
-break;
-case R_WDAY:
-{
-/* The day field is supposed to contain a value in
-   the range 1-7. Otherwise behavior is undefined.
- */
-int user_wday = (data & 7) - 1;
-s->wday_offset = (user_wday - now.tm_wday + 7) % 7;
-}
-break;
-case R_DATE:
-now.tm_mday = from_bcd(data & 0x3f);
-break;
-case R_MONTH:
-now.tm_mon = from_bcd(data & 0x1f) - 1;
-break;
-case R_YEAR:
-now.tm_year = from_bcd(data) + 100;
-break;
-}
-s->offset = qemu_timedate_diff();
-} else if (s->ptr == R_CTRL) {
+if (s->ptr == R_CTRL) {
 /* Control register. */
 
 /* Ensure bits 2, 3 and 6 will read back as zero. */
@@ -227,6 +225,9 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
 
 }
 s->nvram[s->ptr] = data;
+if (s->ptr <= R_YEAR) {
+ds1338_update(s);
+}
 inc_regptr(s);
 return 0;
 }
-- 
2.11.0




[Qemu-devel] [PATCH 08/14] timer: rename ds1338 -> dsrtc

2018-07-05 Thread Michael Davidsaver
Prepare to generalize with a more generic
name.

Keep device name and vmstate name "ds1338"
for compatibility.

Signed-off-by: Michael Davidsaver 
Reviewed-by: Peter Maydell 
---
 hw/timer/ds1338.c | 72 +++
 1 file changed, 36 insertions(+), 36 deletions(-)

diff --git a/hw/timer/ds1338.c b/hw/timer/ds1338.c
index 0134ffd72a..3c5781d53c 100644
--- a/hw/timer/ds1338.c
+++ b/hw/timer/ds1338.c
@@ -23,8 +23,8 @@
 
 #define CTRL_OSF   0x20
 
-#define TYPE_DS1338 "ds1338"
-#define DS1338(obj) OBJECT_CHECK(DS1338State, (obj), TYPE_DS1338)
+#define TYPE_DSRTC "ds1338"
+#define DSRTC(obj) OBJECT_CHECK(DSRTCState, (obj), TYPE_DSRTC)
 
 /* values stored in BCD */
 /* 00-59 */
@@ -57,7 +57,7 @@ FIELD(MONTH, CENTURY, 7, 1)
 
 FIELD(CTRL, OSF, 5, 1)
 
-typedef struct DS1338State {
+typedef struct DSRTCState {
 I2CSlave parent_obj;
 
 int64_t offset;
@@ -65,24 +65,24 @@ typedef struct DS1338State {
 uint8_t nvram[NVRAM_SIZE];
 int32_t ptr;
 bool addr_byte;
-} DS1338State;
+} DSRTCState;
 
-static const VMStateDescription vmstate_ds1338 = {
+static const VMStateDescription vmstate_dsrtc = {
 .name = "ds1338",
 .version_id = 2,
 .minimum_version_id = 1,
 .fields = (VMStateField[]) {
-VMSTATE_I2C_SLAVE(parent_obj, DS1338State),
-VMSTATE_INT64(offset, DS1338State),
-VMSTATE_UINT8_V(wday_offset, DS1338State, 2),
-VMSTATE_UINT8_ARRAY(nvram, DS1338State, NVRAM_SIZE),
-VMSTATE_INT32(ptr, DS1338State),
-VMSTATE_BOOL(addr_byte, DS1338State),
+VMSTATE_I2C_SLAVE(parent_obj, DSRTCState),
+VMSTATE_INT64(offset, DSRTCState),
+VMSTATE_UINT8_V(wday_offset, DSRTCState, 2),
+VMSTATE_UINT8_ARRAY(nvram, DSRTCState, NVRAM_SIZE),
+VMSTATE_INT32(ptr, DSRTCState),
+VMSTATE_BOOL(addr_byte, DSRTCState),
 VMSTATE_END_OF_LIST()
 }
 };
 
-static void capture_current_time(DS1338State *s)
+static void capture_current_time(DSRTCState *s)
 {
 /* Capture the current time into the secondary registers
  * which will be actually read by the data transfer operation.
@@ -119,7 +119,7 @@ static void capture_current_time(DS1338State *s)
 s->nvram[R_YEAR] = to_bcd(now.tm_year - 100);
 }
 
-static void inc_regptr(DS1338State *s)
+static void inc_regptr(DSRTCState *s)
 {
 /* The register pointer wraps around after 0x3F; wraparound
  * causes the current time/date to be retransferred into
@@ -131,9 +131,9 @@ static void inc_regptr(DS1338State *s)
 }
 }
 
-static int ds1338_event(I2CSlave *i2c, enum i2c_event event)
+static int dsrtc_event(I2CSlave *i2c, enum i2c_event event)
 {
-DS1338State *s = DS1338(i2c);
+DSRTCState *s = DSRTC(i2c);
 
 switch (event) {
 case I2C_START_RECV:
@@ -154,9 +154,9 @@ static int ds1338_event(I2CSlave *i2c, enum i2c_event event)
 return 0;
 }
 
-static int ds1338_recv(I2CSlave *i2c)
+static int dsrtc_recv(I2CSlave *i2c)
 {
-DS1338State *s = DS1338(i2c);
+DSRTCState *s = DSRTC(i2c);
 uint8_t res;
 
 res  = s->nvram[s->ptr];
@@ -167,7 +167,7 @@ static int ds1338_recv(I2CSlave *i2c)
 /* call after guest writes to current time registers
  * to re-compute our offset from host time.
  */
-static void ds1338_update(DS1338State *s)
+static void dsrtc_update(DSRTCState *s)
 {
 
 struct tm now = {};
@@ -204,9 +204,9 @@ static void ds1338_update(DS1338State *s)
 }
 }
 
-static int ds1338_send(I2CSlave *i2c, uint8_t data)
+static int dsrtc_send(I2CSlave *i2c, uint8_t data)
 {
-DS1338State *s = DS1338(i2c);
+DSRTCState *s = DSRTC(i2c);
 
 if (s->addr_byte) {
 s->ptr = data & (NVRAM_SIZE - 1);
@@ -226,15 +226,15 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
 }
 s->nvram[s->ptr] = data;
 if (s->ptr <= R_YEAR) {
-ds1338_update(s);
+dsrtc_update(s);
 }
 inc_regptr(s);
 return 0;
 }
 
-static void ds1338_reset(DeviceState *dev)
+static void dsrtc_reset(DeviceState *dev)
 {
-DS1338State *s = DS1338(dev);
+DSRTCState *s = DSRTC(dev);
 
 /* The clock is running and synchronized with the host */
 s->offset = 0;
@@ -244,28 +244,28 @@ static void ds1338_reset(DeviceState *dev)
 s->addr_byte = false;
 }
 
-static void ds1338_class_init(ObjectClass *klass, void *data)
+static void dsrtc_class_init(ObjectClass *klass, void *data)
 {
 DeviceClass *dc = DEVICE_CLASS(klass);
 I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
 
-k->event = ds1338_event;
-k->recv = ds1338_recv;
-k->send = ds1338_send;
-dc->reset = ds1338_reset;
-dc->vmsd = _ds1338;
+k->event = dsrtc_event;
+k->recv = dsrtc_recv;
+k->send = dsrtc_send;
+dc->reset = dsrtc_reset;
+dc->vmsd = _dsrtc;
 }
 
-static const TypeInfo ds1338_info = {
-.name  = TYPE_DS1338,
+static const TypeInfo dsrtc_in

[Qemu-devel] [PATCH 04/14] timer: ds1338 clarify HOUR handling

2018-07-05 Thread Michael Davidsaver
Simplify and comment the translation between
registers and struct tm.

Signed-off-by: Michael Davidsaver 
---
 hw/timer/ds1338.c | 17 +++--
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/hw/timer/ds1338.c b/hw/timer/ds1338.c
index b56db5852e..637a0f4246 100644
--- a/hw/timer/ds1338.c
+++ b/hw/timer/ds1338.c
@@ -89,9 +89,13 @@ static void capture_current_time(DS1338State *s)
  */
 struct tm now;
 qemu_get_timedate(, s->offset);
+
 s->nvram[R_SEC] = to_bcd(now.tm_sec);
 s->nvram[R_MIN] = to_bcd(now.tm_min);
 if (ARRAY_FIELD_EX32(s->nvram, HOUR, SET12)) {
+/* 12 hour mode.
+ * map 0-23 to 1-12 am/pm
+ */
 int tmp = now.tm_hour;
 if (tmp % 12 == 0) {
 tmp += 12;
@@ -101,7 +105,9 @@ static void capture_current_time(DS1338State *s)
 } else {
 s->nvram[R_HOUR] = R_HOUR_SET12_MASK | R_HOUR_AMPM_MASK | 
to_bcd(tmp - 12);
 }
+
 } else {
+/* 24 hour mode. */
 s->nvram[R_HOUR] = to_bcd(now.tm_hour);
 }
 s->nvram[R_WDAY] = (now.tm_wday + s->wday_offset) % 7 + 1;
@@ -178,14 +184,13 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
 break;
 case R_HOUR:
 if (FIELD_EX32(data, HOUR, SET12)) {
-int tmp = from_bcd(FIELD_EX32(data, HOUR, HOUR12));
+/* 12 hour (1-12) */
+/* read and wrap 1-12 -> 0-11 */
+now.tm_hour = from_bcd(FIELD_EX32(data, HOUR, HOUR12)) % 12u;
 if (FIELD_EX32(data, HOUR, AMPM)) {
-tmp += 12;
+now.tm_hour += 12;
 }
-if (tmp % 12 == 0) {
-tmp -= 12;
-}
-now.tm_hour = tmp;
+
 } else {
 now.tm_hour = from_bcd(FIELD_EX32(data, HOUR, HOUR24));
 }
-- 
2.11.0




[Qemu-devel] [PATCH 00/14] Generalize Dallas/Maxim I2C RTC devices v3

2018-07-05 Thread Michael Davidsaver
This series generalizes the ds1338 model to also support the ds1375.
As previously, only the time of day registers are modeled.  This
series (v3) is a minor iteration on the previous v2.

No changes were made to the unittests.

Summary of changes by patch name in response to comments by Peter Maydell.

= timer: ds1338 use registerfields.h

Changed as requested to be more direct translation.

= timer: ds1338 persist 12-hour mode selection

On 04/12/2018 11:03 AM, Peter Maydell wrote:
> The code change here looks like a reasonable no-behaviour-change
> simplification of the code, but it doesn't match up with
> the description in the commit message ?

While it isn't clear from the diff, the condtional
involved has 3 arms, only two of these were updating
's->nvram[]'.  The arm handling control register
writes is the one which didn't.  So attempts to set
the 12 hour mode bit were ignored, and subsequent
reads always returned 24 hour time.

So this is a behaviour change, and a minor bug fix.

= timer: ds1338 clarify HOUR handling
= timer: ds1338 fix wday_offset handling

These two are combined as requested.

= timer: generalize ds1338

The change to CTRL register handling is split out
as a seperate patch "timer: ds1338 remove vestige of un-modeled OSF"

= timer: ds-rtc handle CENTURY bit

Changed as suggested.



Michael Davidsaver (14):
  tests: more thorough tests of ds1338
  timer: ds1338 use registerfields.h
  timer: ds1338 persist 12-hour mode selection
  timer: ds1338 clarify HOUR handling
  timer: ds1338 change write handling and fix wday_offset handling
  tests: ds-rtc test 12 hour mode
  tests: ds-rtc test wday offset
  timer: rename ds1338 -> dsrtc
  timer: rename file ds1338.c -> ds-rtc.c
  timer: ds1338 remove vestige of un-modeled OSF
  timer: generalize ds1338
  timer: ds-rtc handle CENTURY bit
  timer: ds-rtc model ds1375
  tests: drop ds1338-test

 default-configs/arm-softmmu.mak |   2 +-
 hw/timer/Makefile.objs  |   2 +-
 hw/timer/ds-rtc.c   | 335 
 hw/timer/ds1338.c   | 239 
 tests/Makefile.include  |   6 +-
 tests/ds-rtc-common.h   |  71 +
 tests/ds-rtc-current-test.c |  66 
 tests/ds-rtc-set-test.c | 171 
 tests/ds1338-test.c |  75 -
 9 files changed, 649 insertions(+), 318 deletions(-)
 create mode 100644 hw/timer/ds-rtc.c
 delete mode 100644 hw/timer/ds1338.c
 create mode 100644 tests/ds-rtc-common.h
 create mode 100644 tests/ds-rtc-current-test.c
 create mode 100644 tests/ds-rtc-set-test.c
 delete mode 100644 tests/ds1338-test.c

-- 
2.11.0




[Qemu-devel] [PATCH 03/14] timer: ds1338 persist 12-hour mode selection

2018-07-05 Thread Michael Davidsaver
Need to save HOUR[HOUR12] bit to keep
track of guest selection of 12-hour mode.
Write through current time registers to
achieve this.  Will be overwritten
by the next read/latch.

This was only being done in two of three
arms of this conditional block.

Signed-off-by: Michael Davidsaver 
---
 hw/timer/ds1338.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/hw/timer/ds1338.c b/hw/timer/ds1338.c
index 7298c5af43..b56db5852e 100644
--- a/hw/timer/ds1338.c
+++ b/hw/timer/ds1338.c
@@ -220,10 +220,8 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
value unchanged. */
 data = (data & ~CTRL_OSF) | (data & s->nvram[s->ptr] & CTRL_OSF);
 
-s->nvram[s->ptr] = data;
-} else {
-s->nvram[s->ptr] = data;
 }
+s->nvram[s->ptr] = data;
 inc_regptr(s);
 return 0;
 }
-- 
2.11.0




[Qemu-devel] [PATCH 07/14] tests: ds-rtc test wday offset

2018-07-05 Thread Michael Davidsaver
Signed-off-by: Michael Davidsaver 
---
 tests/ds-rtc-common.h   | 10 +++---
 tests/ds-rtc-current-test.c |  9 -
 tests/ds-rtc-set-test.c |  6 --
 3 files changed, 19 insertions(+), 6 deletions(-)

diff --git a/tests/ds-rtc-common.h b/tests/ds-rtc-common.h
index c8e6c2bc5b..633131c55f 100644
--- a/tests/ds-rtc-common.h
+++ b/tests/ds-rtc-common.h
@@ -20,7 +20,7 @@ static uint8_t addr;
 static bool use_century;
 
 /* input buffer must have at least 7 elements */
-static inline time_t rtc_parse(const uint8_t *buf)
+static inline time_t rtc_parse(const uint8_t *buf, unsigned *wday)
 {
 struct tm parts;
 
@@ -48,10 +48,14 @@ static inline time_t rtc_parse(const uint8_t *buf)
 parts.tm_year += 100u;
 }
 
+if (wday) {
+*wday = parts.tm_wday;
+}
+
 return mktimegm();
 }
 
-static time_t rtc_gettime(void)
+static time_t rtc_gettime(unsigned *wday)
 {
 uint8_t buf[7];
 
@@ -61,7 +65,7 @@ static time_t rtc_gettime(void)
 /* read back current time registers */
 i2c_recv(i2c, addr, buf, 7);
 
-return rtc_parse(buf);
+return rtc_parse(buf, wday);
 }
 
 #endif /* DSRTCCOMMON_H */
diff --git a/tests/ds-rtc-current-test.c b/tests/ds-rtc-current-test.c
index 6acbbed9a6..7dc3202261 100644
--- a/tests/ds-rtc-current-test.c
+++ b/tests/ds-rtc-current-test.c
@@ -20,17 +20,24 @@
 static
 void test_rtc_current(void)
 {
+struct tm tm_actual;
 time_t expected, actual;
 /* relax test to limit false positives when host may be overloaded.
  * Allow larger delta when running "-m quick"
  */
 time_t max_delta = g_test_slow() ? 1 : 30;
 
+unsigned wday_expect;
+
 actual = time(NULL);
 /* new second may start here */
-expected = rtc_gettime();
+expected = rtc_gettime(_expect);
+
+gmtime_r(, _actual);
+
 g_assert_cmpuint(expected, <=, actual + max_delta);
 g_assert_cmpuint(expected, >=, actual);
+g_assert_cmpuint(wday_expect, ==, tm_actual.tm_wday);
 }
 
 int main(int argc, char *argv[])
diff --git a/tests/ds-rtc-set-test.c b/tests/ds-rtc-set-test.c
index c48406ee2c..12aeb2580a 100644
--- a/tests/ds-rtc-set-test.c
+++ b/tests/ds-rtc-set-test.c
@@ -124,16 +124,18 @@ void test_rtc_set(const void *raw)
 
 const uint8_t *testtime = raw;
 time_t expected, actual;
+unsigned wday_expect, wday_actual;
 
 /* skip address pointer and parse remainder */
-expected = rtc_parse([1]);
+expected = rtc_parse([1], _expect);
 
 i2c_send(i2c, addr, testtime, 8);
 /* host may start new second here */
-actual = rtc_gettime();
+actual = rtc_gettime(_actual);
 
 g_assert_cmpuint(expected, <=, actual);
 g_assert_cmpuint(expected + max_delta, >=, actual);
+g_assert_cmpuint(wday_expect, ==, wday_actual);
 }
 
 int main(int argc, char *argv[])
-- 
2.11.0




[Qemu-devel] [PATCH 02/14] timer: ds1338 use registerfields.h

2018-07-05 Thread Michael Davidsaver
Use names for registers and bits except
for R_CTRL which will be dealt with later,
and isn't modeled anyway.

Signed-off-by: Michael Davidsaver 
Reviewed-by: Peter Maydell 
---
 hw/timer/ds1338.c | 80 +--
 1 file changed, 54 insertions(+), 26 deletions(-)

diff --git a/hw/timer/ds1338.c b/hw/timer/ds1338.c
index 3849b74a68..7298c5af43 100644
--- a/hw/timer/ds1338.c
+++ b/hw/timer/ds1338.c
@@ -13,6 +13,7 @@
 #include "qemu/osdep.h"
 #include "qemu-common.h"
 #include "hw/i2c/i2c.h"
+#include "hw/registerfields.h"
 #include "qemu/bcd.h"
 
 /* Size of NVRAM including both the user-accessible area and the
@@ -20,15 +21,42 @@
  */
 #define NVRAM_SIZE 64
 
-/* Flags definitions */
-#define SECONDS_CH 0x80
-#define HOURS_12   0x40
-#define HOURS_PM   0x20
 #define CTRL_OSF   0x20
 
 #define TYPE_DS1338 "ds1338"
 #define DS1338(obj) OBJECT_CHECK(DS1338State, (obj), TYPE_DS1338)
 
+/* values stored in BCD */
+/* 00-59 */
+#define R_SEC   (0x0)
+/* 00-59 */
+#define R_MIN   (0x1)
+#define R_HOUR  (0x2)
+/* 1-7 */
+#define R_WDAY  (0x3)
+/* 0-31 */
+#define R_DATE  (0x4)
+#define R_MONTH (0x5)
+/* 0-99 */
+#define R_YEAR  (0x6)
+
+#define R_CTRL  (0x7)
+
+/* use 12 hour mode when set */
+FIELD(HOUR, SET12, 6, 1)
+/* 00-23 */
+FIELD(HOUR, HOUR24, 0, 6)
+/* PM when set */
+FIELD(HOUR, AMPM, 5, 1)
+/* 1-12 (not 0-11!) */
+FIELD(HOUR, HOUR12, 0, 5)
+
+/* 1-12 */
+FIELD(MONTH, MONTH, 0, 5)
+FIELD(MONTH, CENTURY, 7, 1)
+
+FIELD(CTRL, OSF, 5, 1)
+
 typedef struct DS1338State {
 I2CSlave parent_obj;
 
@@ -61,25 +89,25 @@ static void capture_current_time(DS1338State *s)
  */
 struct tm now;
 qemu_get_timedate(, s->offset);
-s->nvram[0] = to_bcd(now.tm_sec);
-s->nvram[1] = to_bcd(now.tm_min);
-if (s->nvram[2] & HOURS_12) {
+s->nvram[R_SEC] = to_bcd(now.tm_sec);
+s->nvram[R_MIN] = to_bcd(now.tm_min);
+if (ARRAY_FIELD_EX32(s->nvram, HOUR, SET12)) {
 int tmp = now.tm_hour;
 if (tmp % 12 == 0) {
 tmp += 12;
 }
 if (tmp <= 12) {
-s->nvram[2] = HOURS_12 | to_bcd(tmp);
+s->nvram[R_HOUR] = R_HOUR_SET12_MASK | to_bcd(tmp);
 } else {
-s->nvram[2] = HOURS_12 | HOURS_PM | to_bcd(tmp - 12);
+s->nvram[R_HOUR] = R_HOUR_SET12_MASK | R_HOUR_AMPM_MASK | 
to_bcd(tmp - 12);
 }
 } else {
-s->nvram[2] = to_bcd(now.tm_hour);
+s->nvram[R_HOUR] = to_bcd(now.tm_hour);
 }
-s->nvram[3] = (now.tm_wday + s->wday_offset) % 7 + 1;
-s->nvram[4] = to_bcd(now.tm_mday);
-s->nvram[5] = to_bcd(now.tm_mon + 1);
-s->nvram[6] = to_bcd(now.tm_year - 100);
+s->nvram[R_WDAY] = (now.tm_wday + s->wday_offset) % 7 + 1;
+s->nvram[R_DATE] = to_bcd(now.tm_mday);
+s->nvram[R_MONTH] = to_bcd(now.tm_mon + 1);
+s->nvram[R_YEAR] = to_bcd(now.tm_year - 100);
 }
 
 static void inc_regptr(DS1338State *s)
@@ -141,17 +169,17 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
 struct tm now;
 qemu_get_timedate(, s->offset);
 switch(s->ptr) {
-case 0:
+case R_SEC:
 /* TODO: Implement CH (stop) bit.  */
 now.tm_sec = from_bcd(data & 0x7f);
 break;
-case 1:
+case R_MIN:
 now.tm_min = from_bcd(data & 0x7f);
 break;
-case 2:
-if (data & HOURS_12) {
-int tmp = from_bcd(data & (HOURS_PM - 1));
-if (data & HOURS_PM) {
+case R_HOUR:
+if (FIELD_EX32(data, HOUR, SET12)) {
+int tmp = from_bcd(FIELD_EX32(data, HOUR, HOUR12));
+if (FIELD_EX32(data, HOUR, AMPM)) {
 tmp += 12;
 }
 if (tmp % 12 == 0) {
@@ -159,10 +187,10 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
 }
 now.tm_hour = tmp;
 } else {
-now.tm_hour = from_bcd(data & (HOURS_12 - 1));
+now.tm_hour = from_bcd(FIELD_EX32(data, HOUR, HOUR24));
 }
 break;
-case 3:
+case R_WDAY:
 {
 /* The day field is supposed to contain a value in
the range 1-7. Otherwise behavior is undefined.
@@ -171,18 +199,18 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
 s->wday_offset = (user_wday - now.tm_wday + 7) % 7;
 }
 break;
-case 4:
+case R_DATE:
 now.tm_mday = from_bcd(data & 0x3f);
 break;
-case 5:
+case R_MONTH:
 now.tm_mon = from_bcd(data & 0x1f) - 1;
 break;
-case 6:
+case R_YEAR:
 now.tm_year = from_bcd(data) + 100;
 break;
  

Re: [Qemu-devel] [Qemu-ppc] [PATCH] ppc: move at24c to its own CONFIG_ symbol

2018-05-23 Thread Michael Davidsaver
On 05/22/2018 10:30 PM, Thomas Huth wrote:
> On 22.05.2018 21:17, Paolo Bonzini wrote:
>> AT24c EEPROM is currently gated by CONFIG_I2C, and as such it is
>> being included in all emulators that use I2C, even if they do not
>> really need it.  Separate it and, since it was added for the e500
>> machines, add it to qemu-system-ppc and qemu-system-ppc64.
>> ---
>>  default-configs/ppc-softmmu.mak | 1 +
>>  hw/nvram/Makefile.objs  | 2 +-
>>  2 files changed, 2 insertions(+), 1 deletion(-)
>>
>> diff --git a/default-configs/ppc-softmmu.mak 
>> b/default-configs/ppc-softmmu.mak
>> index 4d7be45ac5..c57e568121 100644
>> --- a/default-configs/ppc-softmmu.mak
>> +++ b/default-configs/ppc-softmmu.mak
>> @@ -26,6 +26,7 @@ CONFIG_USB_EHCI_SYSBUS=y
>>  CONFIG_SM501=y
>>  CONFIG_IDE_SII3112=y
>>  CONFIG_I2C=y
>> +CONFIG_AT24C=y
>>  
>>  # For Macs
>>  CONFIG_MAC=y
>> diff --git a/hw/nvram/Makefile.objs b/hw/nvram/Makefile.objs
>> index a912d25391..b318e53a43 100644
>> --- a/hw/nvram/Makefile.objs
>> +++ b/hw/nvram/Makefile.objs
>> @@ -1,6 +1,6 @@
>>  common-obj-$(CONFIG_DS1225Y) += ds1225y.o
>>  common-obj-y += eeprom93xx.o
>> -common-obj-$(CONFIG_I2C) += eeprom_at24c.o
>> +common-obj-$(CONFIG_AT24C) += eeprom_at24c.o
>>  common-obj-y += fw_cfg.o
>>  common-obj-y += chrp_nvram.o
>>  common-obj-$(CONFIG_MAC_NVRAM) += mac_nvram.o
> 
> Since this is a device that can only be added by the user (no board is
> using it automatically, as far as I can see),

The board which prompted me to add this device is still out there and
I'm still intent on pursuing getting it into QEMU.  It's clearly going
to be some time before this can happen as there are RTC and e500
patches that would need to get in first, and my time to spend on this
has been non-existent in recent months.

https://github.com/mdavidsaver/qemu/commits/vme

> it could be useful for
> other machines, too, I guess? Anyway, it's a good idea to have a
> separate config switch available for it, and we can add it to other
> machines again later if somebody feels that it is necessary, so (once
> you add your SoB):
> 
> Reviewed-by: Thomas Huth 
> 




Re: [Qemu-devel] [PATCH 01/14] tests: more thorough tests of ds1338

2018-03-26 Thread Michael Davidsaver
On 03/26/2018 02:18 AM, Paolo Bonzini wrote:
> On 24/03/2018 20:24, Michael Davidsaver wrote:
>> Test current time and set+get round trip.
>> Separate current time test from set/get
>> tests to avoid test order issues.
> 
> What are these issues?  You can start a different QEMU for each test.

Quite right, and this is now what I do.  The previous iteration was
clever about avoiding this for ... no particular reason.



[Qemu-devel] [PATCH 11/14] timer: generalize ds1338

2018-03-24 Thread Michael Davidsaver
Add class level handling for address space size
and control register.

Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 hw/timer/ds-rtc.c | 63 ---
 1 file changed, 46 insertions(+), 17 deletions(-)

diff --git a/hw/timer/ds-rtc.c b/hw/timer/ds-rtc.c
index 28f788dd8e..2df1bce3f8 100644
--- a/hw/timer/ds-rtc.c
+++ b/hw/timer/ds-rtc.c
@@ -21,10 +21,10 @@
  */
 #define NVRAM_SIZE 64
 
-#define CTRL_OSF   0x20
-
-#define TYPE_DSRTC "ds1338"
+#define TYPE_DSRTC "dsrtc"
 #define DSRTC(obj) OBJECT_CHECK(DSRTCState, (obj), TYPE_DSRTC)
+#define DSRTC_CLASS(klass) OBJECT_CLASS_CHECK(DSRTCClass, (klass), TYPE_DSRTC)
+#define DSRTC_GET_CLASS(obj) OBJECT_GET_CLASS(DSRTCClass, (obj), TYPE_DSRTC)
 
 /* values stored in BCD */
 /* 00-59 */
@@ -40,7 +40,7 @@
 /* 0-99 */
 #define R_YEAR  (0x6)
 
-#define R_CTRL  (0x7)
+#define R_DS1338_CTRL (0x7)
 
 /* use 12 hour mode when set */
 FIELD(HOUR, SET12, 6, 1)
@@ -67,6 +67,15 @@ typedef struct DSRTCState {
 bool addr_byte;
 } DSRTCState;
 
+typedef struct DSRTCClass {
+I2CSlaveClass parent_obj;
+
+/* actual address space size must be <= NVRAM_SIZE */
+unsigned addr_size;
+unsigned ctrl_offset;
+void (*ctrl_write)(DSRTCState *s, uint8_t);
+} DSRTCClass;
+
 static const VMStateDescription vmstate_dsrtc = {
 .name = "ds1338",
 .version_id = 2,
@@ -119,11 +128,12 @@ static void capture_current_time(DSRTCState *s)
 
 static void inc_regptr(DSRTCState *s)
 {
-/* The register pointer wraps around after 0x3F; wraparound
+DSRTCClass *k = DSRTC_GET_CLASS(s);
+/* The register pointer wraps around after k->addr_size-1; wraparound
  * causes the current time/date to be retransferred into
  * the secondary registers.
  */
-s->ptr = (s->ptr + 1) & (NVRAM_SIZE - 1);
+s->ptr = (s->ptr + 1) % k->addr_size;
 if (!s->ptr) {
 capture_current_time(s);
 }
@@ -206,22 +216,15 @@ static void dsrtc_update(DSRTCState *s)
 static int dsrtc_send(I2CSlave *i2c, uint8_t data)
 {
 DSRTCState *s = DSRTC(i2c);
+DSRTCClass *k = DSRTC_GET_CLASS(s);
 
 if (s->addr_byte) {
-s->ptr = data & (NVRAM_SIZE - 1);
+s->ptr = data % k->addr_size;
 s->addr_byte = false;
 return 0;
 }
-if (s->ptr == R_CTRL) {
-/* Control register. */
-
-/* Ensure bits 2, 3 and 6 will read back as zero. */
-data &= 0xB3;
-
-/* Attempting to write the OSF flag to logic 1 leaves the
-   value unchanged. */
-data = (data & ~CTRL_OSF) | (data & s->nvram[s->ptr] & CTRL_OSF);
-
+if (s->ptr == k->ctrl_offset) {
+(k->ctrl_write)(s, data);
 }
 s->nvram[s->ptr] = data;
 if (s->ptr <= R_YEAR) {
@@ -256,15 +259,41 @@ static void dsrtc_class_init(ObjectClass *klass, void 
*data)
 }
 
 static const TypeInfo dsrtc_info = {
+.abstract  = true,
 .name  = TYPE_DSRTC,
 .parent= TYPE_I2C_SLAVE,
 .instance_size = sizeof(DSRTCState),
 .class_init= dsrtc_class_init,
 };
 
+static void ds1338_control_write(DSRTCState *s, uint8_t data)
+{
+/* Control register. */
+
+/* allow guest to set no-op controls for clock out pin */
+s->nvram[R_DS1338_CTRL] = data & 0x93;
+}
+
+static void ds1338_class_init(ObjectClass *klass, void *data)
+{
+DSRTCClass *k = DSRTC_CLASS(klass);
+
+k->addr_size = 0x40;
+k->ctrl_offset = R_DS1338_CTRL;
+k->ctrl_write = ds1338_control_write;
+}
+
+static const TypeInfo ds1338_info = {
+.name  = "ds1338",
+.parent= TYPE_DSRTC,
+.class_size= sizeof(DSRTCClass),
+.class_init= ds1338_class_init,
+};
+
 static void dsrtc_register_types(void)
 {
 type_register_static(_info);
+type_register_static(_info);
 }
 
 type_init(dsrtc_register_types)
-- 
2.11.0




[Qemu-devel] [PATCH 03/14] timer: ds1338 persist 12-hour mode selection

2018-03-24 Thread Michael Davidsaver
Need to save HOUR[HOUR12] bit to keep
track of guest selection of 12-hour mode.
Write through current time registers to
achieve this.  Will be overwritten
by the next read/latch.

Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 hw/timer/ds1338.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/hw/timer/ds1338.c b/hw/timer/ds1338.c
index b5630e214a..72a4692d60 100644
--- a/hw/timer/ds1338.c
+++ b/hw/timer/ds1338.c
@@ -224,10 +224,8 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
value unchanged. */
 data = (data & ~CTRL_OSF) | (data & s->nvram[s->ptr] & CTRL_OSF);
 
-s->nvram[s->ptr] = data;
-} else {
-s->nvram[s->ptr] = data;
 }
+s->nvram[s->ptr] = data;
 inc_regptr(s);
 return 0;
 }
-- 
2.11.0




[Qemu-devel] [PATCH 13/14] timer: ds-rtc model ds1375

2018-03-24 Thread Michael Davidsaver
differences from ds1338

* Has alarms (not modeled)
* different control register (not modeled)
* smaller address space (0x20 vs. 0x40)

Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 hw/timer/ds-rtc.c | 30 --
 1 file changed, 28 insertions(+), 2 deletions(-)

diff --git a/hw/timer/ds-rtc.c b/hw/timer/ds-rtc.c
index 5a4df1b115..e5da36cae8 100644
--- a/hw/timer/ds-rtc.c
+++ b/hw/timer/ds-rtc.c
@@ -1,8 +1,9 @@
 /*
- * MAXIM DSRTC I2C RTC+NVRAM
+ * MAXIM/Dallas DS1338 and DS1375 I2C RTC+NVRAM
  *
+ * Copyright (c) 2018 Michael Davidsaver
  * Copyright (c) 2009 CodeSourcery.
- * Written by Paul Brook
+ * Written by Paul Brook, Michael Davidsaver
  *
  * This code is licensed under the GNU GPL v2.
  *
@@ -41,6 +42,7 @@
 #define R_YEAR  (0x6)
 
 #define R_DS1338_CTRL (0x7)
+#define R_DS1375_CTRL (0xe)
 
 /* use 12 hour mode when set */
 FIELD(HOUR, SET12, 6, 1)
@@ -296,10 +298,34 @@ static const TypeInfo ds1338_info = {
 .class_init= ds1338_class_init,
 };
 
+static void ds1375_control_write(DSRTCState *s, uint8_t data)
+{
+/* just store it, we don't model any features */
+s->nvram[R_DS1375_CTRL] = data;
+}
+
+static void ds1375_class_init(ObjectClass *klass, void *data)
+{
+DSRTCClass *k = DSRTC_CLASS(klass);
+
+k->has_century = true;
+k->addr_size = 0x20;
+k->ctrl_offset = R_DS1375_CTRL;
+k->ctrl_write = ds1375_control_write;
+}
+
+static const TypeInfo ds1375_info = {
+.name  = "ds1375",
+.parent= TYPE_DSRTC,
+.class_size= sizeof(DSRTCClass),
+.class_init= ds1375_class_init,
+};
+
 static void dsrtc_register_types(void)
 {
 type_register_static(_info);
 type_register_static(_info);
+type_register_static(_info);
 }
 
 type_init(dsrtc_register_types)
-- 
2.11.0




[Qemu-devel] [PATCH 07/14] timer: ds1338 fix wday_offset handling

2018-03-24 Thread Michael Davidsaver
Correctly handle different real weekday in
guest and host timezones.
Allow guest to use any day as start of week
(day 1).  eg. Monday instead of Sunday.

Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 hw/timer/ds1338.c | 24 
 1 file changed, 16 insertions(+), 8 deletions(-)

diff --git a/hw/timer/ds1338.c b/hw/timer/ds1338.c
index 071c031563..a969b5c8ba 100644
--- a/hw/timer/ds1338.c
+++ b/hw/timer/ds1338.c
@@ -108,7 +108,10 @@ static void capture_current_time(DS1338State *s)
 } else {
 ARRAY_FIELD_DP32(s->nvram, HOUR, HOUR24, to_bcd(now.tm_hour));
 }
-s->nvram[R_WDAY] = (now.tm_wday + s->wday_offset) % 7 + 1;
+s->nvram[R_WDAY] = (now.tm_wday + s->wday_offset) % 7;
+if (s->nvram[R_WDAY] == 0) {
+s->nvram[R_WDAY] = 7;
+}
 s->nvram[R_DATE] = to_bcd(now.tm_mday);
 s->nvram[R_MONTH] = to_bcd(now.tm_mon + 1);
 s->nvram[R_YEAR] = to_bcd(now.tm_year - 100);
@@ -182,17 +185,22 @@ static void ds1338_update(DS1338State *s)
 } else {
 now.tm_hour = from_bcd(ARRAY_FIELD_EX32(s->nvram, HOUR, HOUR24));
 }
-{
-/* The day field is supposed to contain a value in
-   the range 1-7. Otherwise behavior is undefined.
- */
-int user_wday = (s->nvram[R_WDAY] & 7) - 1;
-s->wday_offset = (user_wday - now.tm_wday + 7) % 7;
-}
+now.tm_wday = from_bcd(s->nvram[R_WDAY]) - 1u;
 now.tm_mday = from_bcd(s->nvram[R_DATE] & 0x3f);
 now.tm_mon = from_bcd(s->nvram[R_MONTH] & 0x1f) - 1;
 now.tm_year = from_bcd(s->nvram[R_YEAR]) + 100;
 s->offset = qemu_timedate_diff();
+
+{
+/* Round trip to get real wday_offset based on time delta and
+ * ref. timezone.
+ * Race if midnight (in ref. timezone) happens here.
+ */
+int user_wday = now.tm_wday;
+qemu_get_timedate(, s->offset);
+
+s->wday_offset = (user_wday - now.tm_wday) % 7 + 1;
+}
 }
 
 static int ds1338_send(I2CSlave *i2c, uint8_t data)
-- 
2.11.0




[Qemu-devel] [PATCH 01/14] tests: more thorough tests of ds1338

2018-03-24 Thread Michael Davidsaver
Test current time and set+get round trip.
Separate current time test from set/get
tests to avoid test order issues.

Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 tests/Makefile.include  |   4 ++
 tests/ds-rtc-common.h   |  67 +
 tests/ds-rtc-current-test.c |  59 ++
 tests/ds-rtc-set-test.c | 117 
 4 files changed, 247 insertions(+)
 create mode 100644 tests/ds-rtc-common.h
 create mode 100644 tests/ds-rtc-current-test.c
 create mode 100644 tests/ds-rtc-set-test.c

diff --git a/tests/Makefile.include b/tests/Makefile.include
index eb218a9539..d256095c88 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -372,6 +372,8 @@ check-qtest-sparc64-y += tests/boot-serial-test$(EXESUF)
 
 check-qtest-arm-y = tests/tmp105-test$(EXESUF)
 check-qtest-arm-y += tests/ds1338-test$(EXESUF)
+check-qtest-arm-y += tests/ds-rtc-current-test$(EXESUF)
+check-qtest-arm-y += tests/ds-rtc-set-test$(EXESUF)
 check-qtest-arm-y += tests/m25p80-test$(EXESUF)
 gcov-files-arm-y += hw/misc/tmp105.c
 check-qtest-arm-y += tests/virtio-blk-test$(EXESUF)
@@ -771,6 +773,8 @@ tests/bios-tables-test$(EXESUF): tests/bios-tables-test.o \
 tests/pxe-test$(EXESUF): tests/pxe-test.o tests/boot-sector.o $(libqos-obj-y)
 tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y)
 tests/ds1338-test$(EXESUF): tests/ds1338-test.o $(libqos-imx-obj-y)
+tests/ds-rtc-current-test$(EXESUF): tests/ds-rtc-current-test.o 
$(libqos-imx-obj-y)
+tests/ds-rtc-set-test$(EXESUF): tests/ds-rtc-set-test.o $(libqos-imx-obj-y)
 tests/m25p80-test$(EXESUF): tests/m25p80-test.o
 tests/i440fx-test$(EXESUF): tests/i440fx-test.o $(libqos-pc-obj-y)
 tests/q35-test$(EXESUF): tests/q35-test.o $(libqos-pc-obj-y)
diff --git a/tests/ds-rtc-common.h b/tests/ds-rtc-common.h
new file mode 100644
index 00..c8e6c2bc5b
--- /dev/null
+++ b/tests/ds-rtc-common.h
@@ -0,0 +1,67 @@
+/* Common code for testing of Dallas/Maxim I2C bus RTC devices
+ *
+ * Copyright (c) 2018 Michael Davidsaver
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the LICENSE file in the top-level directory.
+ */
+#ifndef DSRTCCOMMON_H
+#define DSRTCCOMMON_H
+
+#include "qemu/osdep.h"
+#include "qemu/cutils.h"
+#include "libqos/i2c.h"
+
+#define IMX25_I2C_0_BASE 0x43F8
+#define DS1338_ADDR 0x68
+
+static I2CAdapter *i2c;
+static uint8_t addr;
+static bool use_century;
+
+/* input buffer must have at least 7 elements */
+static inline time_t rtc_parse(const uint8_t *buf)
+{
+struct tm parts;
+
+parts.tm_sec = from_bcd(buf[0]);
+parts.tm_min = from_bcd(buf[1]);
+if (buf[2] & 0x40) {
+/* 12 hour */
+/* HOUR register is 1-12. */
+parts.tm_hour = from_bcd(buf[2] & 0x1f);
+g_assert_cmpuint(parts.tm_hour, >=, 1);
+g_assert_cmpuint(parts.tm_hour, <=, 12);
+parts.tm_hour %= 12u; /* wrap 12 -> 0 */
+if (buf[2] & 0x20) {
+parts.tm_hour += 12u;
+}
+} else {
+/* 24 hour */
+parts.tm_hour = from_bcd(buf[2] & 0x3f);
+}
+parts.tm_wday = from_bcd(buf[3]);
+parts.tm_mday = from_bcd(buf[4]);
+parts.tm_mon =  from_bcd((buf[5] & 0x1f) - 1u);
+parts.tm_year = from_bcd(buf[6]);
+if (!use_century || (buf[5] & 0x80)) {
+parts.tm_year += 100u;
+}
+
+return mktimegm();
+}
+
+static time_t rtc_gettime(void)
+{
+uint8_t buf[7];
+
+/* zero address pointer */
+buf[0] = 0;
+i2c_send(i2c, addr, buf, 1);
+/* read back current time registers */
+i2c_recv(i2c, addr, buf, 7);
+
+return rtc_parse(buf);
+}
+
+#endif /* DSRTCCOMMON_H */
diff --git a/tests/ds-rtc-current-test.c b/tests/ds-rtc-current-test.c
new file mode 100644
index 00..6acbbed9a6
--- /dev/null
+++ b/tests/ds-rtc-current-test.c
@@ -0,0 +1,59 @@
+/* Testing of Dallas/Maxim I2C bus RTC devices
+ *
+ * Copyright (c) 2018 Michael Davidsaver
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the LICENSE file in the top-level directory.
+ */
+#include 
+
+#include "qemu/osdep.h"
+#include "qemu/bcd.h"
+#include "qemu/cutils.h"
+#include "libqtest.h"
+#include "libqos/libqos.h"
+#include "libqos/i2c.h"
+
+#include "ds-rtc-common.h"
+
+/* read back and compare with current system time */
+static
+void test_rtc_current(void)
+{
+time_t expected, actual;
+/* relax test to limit false positives when host may be overloaded.
+ * Allow larger delta when running "-m quick"
+ */
+time_t max_delta = g_test_slow() ? 1 : 30;
+
+actual = time(NULL);
+/* new second may start here */
+expected = rtc_gettime();
+g_assert_cmpuint(expected, <=, actual + max_delta);
+g_assert_cmpuint(expected, >=, actual);
+}
+
+int main(in

Re: [Qemu-devel] [PATCH 2/5] tests: more thorough test of ds1338

2018-03-24 Thread Michael Davidsaver
> On 02/20/2018 09:44 AM, Michael Davidsaver wrote:
>> On 02/18/2018 11:39 PM, Thomas Huth wrote:
...
>> That magic (together with patch 1/5) is IMHO a little bit ugly. I've hit
>> the same problem with the m48t59 test recently, and I solved it by
>> moving the qtest_start() and qtest_end() calls from the main() function
>> into the single tests instead, so that each test starts with a clean state:
>>
>> https://git.qemu.org/?p=qemu.git;a=commitdiff;h=9c29830c90d82f27f
>>
>> Could you maybe try whether that approach works for your test cases
>> here, too? Then you could do this without the "0xff" hack here...
> 
> Your right, this looks clearer.  I'll try this approach.

I ultimately decided not to go with this approach as test failures
didn't call qtest_quit(), and the process under test is left running
after gtester exits.

Instead I split the current time test off into a second executable.
This avoids all of the magic.


FYI.  I also looked at using g_test_add(), keeping the QTestState* in a
Fixture struct, and using setup and teardown functions to call
qtest_start()/qtest_quit().  This works, but seemed to me like too much
effort in this case.



[Qemu-devel] [PATCH 10/14] timer: rename file ds1338.c -> ds-rtc.c

2018-03-24 Thread Michael Davidsaver
Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 default-configs/arm-softmmu.mak | 2 +-
 hw/timer/Makefile.objs  | 2 +-
 hw/timer/{ds1338.c => ds-rtc.c} | 0
 3 files changed, 2 insertions(+), 2 deletions(-)
 rename hw/timer/{ds1338.c => ds-rtc.c} (100%)

diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index dd29e741c2..0afffa2a8a 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -33,7 +33,7 @@ CONFIG_SMC91C111=y
 CONFIG_ALLWINNER_EMAC=y
 CONFIG_IMX_FEC=y
 CONFIG_FTGMAC100=y
-CONFIG_DS1338=y
+CONFIG_DSRTC=y
 CONFIG_PFLASH_CFI01=y
 CONFIG_PFLASH_CFI02=y
 CONFIG_MICRODRIVE=y
diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs
index 8b27a4b7ef..d4c59df1d1 100644
--- a/hw/timer/Makefile.objs
+++ b/hw/timer/Makefile.objs
@@ -3,7 +3,7 @@ common-obj-$(CONFIG_ARM_MPTIMER) += arm_mptimer.o
 common-obj-$(CONFIG_ARM_V7M) += armv7m_systick.o
 common-obj-$(CONFIG_A9_GTIMER) += a9gtimer.o
 common-obj-$(CONFIG_CADENCE) += cadence_ttc.o
-common-obj-$(CONFIG_DS1338) += ds1338.o
+common-obj-$(CONFIG_DSRTC) += ds-rtc.o
 common-obj-$(CONFIG_HPET) += hpet.o
 common-obj-$(CONFIG_I8254) += i8254_common.o i8254.o
 common-obj-$(CONFIG_M48T59) += m48t59.o
diff --git a/hw/timer/ds1338.c b/hw/timer/ds-rtc.c
similarity index 100%
rename from hw/timer/ds1338.c
rename to hw/timer/ds-rtc.c
-- 
2.11.0




[Qemu-devel] [PATCH 04/14] timer: ds1338 clarify HOUR handling

2018-03-24 Thread Michael Davidsaver
Simplify and comment the translation between
registers and struct tm.

Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 hw/timer/ds1338.c | 35 +--
 1 file changed, 17 insertions(+), 18 deletions(-)

diff --git a/hw/timer/ds1338.c b/hw/timer/ds1338.c
index 72a4692d60..9bcda26e51 100644
--- a/hw/timer/ds1338.c
+++ b/hw/timer/ds1338.c
@@ -88,23 +88,23 @@ static void capture_current_time(DS1338State *s)
  * which will be actually read by the data transfer operation.
  */
 struct tm now;
+bool mode12 = ARRAY_FIELD_EX32(s->nvram, HOUR, SET12);
 qemu_get_timedate(, s->offset);
+
 s->nvram[R_SEC] = to_bcd(now.tm_sec);
 s->nvram[R_MIN] = to_bcd(now.tm_min);
-if (ARRAY_FIELD_EX32(s->nvram, HOUR, SET12)) {
-int tmp = now.tm_hour;
-if (tmp % 12 == 0) {
-tmp += 12;
-}
-s->nvram[R_HOUR] = 0;
+s->nvram[R_HOUR] = 0;
+if (mode12) {
+/* map 0-23 to 1-12 am/pm */
 ARRAY_FIELD_DP32(s->nvram, HOUR, SET12, 1);
-if (tmp <= 12) {
-ARRAY_FIELD_DP32(s->nvram, HOUR, AMPM, 0);
-ARRAY_FIELD_DP32(s->nvram, HOUR, HOUR12, to_bcd(tmp));
-} else {
-ARRAY_FIELD_DP32(s->nvram, HOUR, AMPM, 1);
-ARRAY_FIELD_DP32(s->nvram, HOUR, HOUR12, to_bcd(tmp - 12));
+ARRAY_FIELD_DP32(s->nvram, HOUR, AMPM, now.tm_hour >= 12u);
+now.tm_hour %= 12u; /* wrap 0-23 to 0-11 */
+if (now.tm_hour == 0u) {
+/* midnight/noon stored as 12 */
+now.tm_hour = 12u;
 }
+ARRAY_FIELD_DP32(s->nvram, HOUR, HOUR12, to_bcd(now.tm_hour));
+
 } else {
 ARRAY_FIELD_DP32(s->nvram, HOUR, HOUR24, to_bcd(now.tm_hour));
 }
@@ -182,14 +182,13 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
 break;
 case R_HOUR:
 if (FIELD_EX32(data, HOUR, SET12)) {
-int tmp = from_bcd(FIELD_EX32(data, HOUR, HOUR12));
+/* 12 hour (1-12) */
+/* read and wrap 1-12 -> 0-11 */
+now.tm_hour = from_bcd(FIELD_EX32(data, HOUR, HOUR12)) % 12u;
 if (FIELD_EX32(data, HOUR, AMPM)) {
-tmp += 12;
+now.tm_hour += 12;
 }
-if (tmp % 12 == 0) {
-tmp -= 12;
-}
-now.tm_hour = tmp;
+
 } else {
 now.tm_hour = from_bcd(FIELD_EX32(data, HOUR, HOUR24));
 }
-- 
2.11.0




[Qemu-devel] [PATCH 09/14] timer: rename ds1338 -> dsrtc

2018-03-24 Thread Michael Davidsaver
Prepare to generalize with a more generic
name.

Keep device name and vmstate name "ds1338"
for compatibility.

Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 hw/timer/ds1338.c | 74 +++
 1 file changed, 37 insertions(+), 37 deletions(-)

diff --git a/hw/timer/ds1338.c b/hw/timer/ds1338.c
index a969b5c8ba..28f788dd8e 100644
--- a/hw/timer/ds1338.c
+++ b/hw/timer/ds1338.c
@@ -1,5 +1,5 @@
 /*
- * MAXIM DS1338 I2C RTC+NVRAM
+ * MAXIM DSRTC I2C RTC+NVRAM
  *
  * Copyright (c) 2009 CodeSourcery.
  * Written by Paul Brook
@@ -23,8 +23,8 @@
 
 #define CTRL_OSF   0x20
 
-#define TYPE_DS1338 "ds1338"
-#define DS1338(obj) OBJECT_CHECK(DS1338State, (obj), TYPE_DS1338)
+#define TYPE_DSRTC "ds1338"
+#define DSRTC(obj) OBJECT_CHECK(DSRTCState, (obj), TYPE_DSRTC)
 
 /* values stored in BCD */
 /* 00-59 */
@@ -57,7 +57,7 @@ FIELD(MONTH, CENTURY, 7, 1)
 
 FIELD(CTRL, OSF, 5, 1)
 
-typedef struct DS1338State {
+typedef struct DSRTCState {
 I2CSlave parent_obj;
 
 int64_t offset;
@@ -65,24 +65,24 @@ typedef struct DS1338State {
 uint8_t nvram[NVRAM_SIZE];
 int32_t ptr;
 bool addr_byte;
-} DS1338State;
+} DSRTCState;
 
-static const VMStateDescription vmstate_ds1338 = {
+static const VMStateDescription vmstate_dsrtc = {
 .name = "ds1338",
 .version_id = 2,
 .minimum_version_id = 1,
 .fields = (VMStateField[]) {
-VMSTATE_I2C_SLAVE(parent_obj, DS1338State),
-VMSTATE_INT64(offset, DS1338State),
-VMSTATE_UINT8_V(wday_offset, DS1338State, 2),
-VMSTATE_UINT8_ARRAY(nvram, DS1338State, NVRAM_SIZE),
-VMSTATE_INT32(ptr, DS1338State),
-VMSTATE_BOOL(addr_byte, DS1338State),
+VMSTATE_I2C_SLAVE(parent_obj, DSRTCState),
+VMSTATE_INT64(offset, DSRTCState),
+VMSTATE_UINT8_V(wday_offset, DSRTCState, 2),
+VMSTATE_UINT8_ARRAY(nvram, DSRTCState, NVRAM_SIZE),
+VMSTATE_INT32(ptr, DSRTCState),
+VMSTATE_BOOL(addr_byte, DSRTCState),
 VMSTATE_END_OF_LIST()
 }
 };
 
-static void capture_current_time(DS1338State *s)
+static void capture_current_time(DSRTCState *s)
 {
 /* Capture the current time into the secondary registers
  * which will be actually read by the data transfer operation.
@@ -117,7 +117,7 @@ static void capture_current_time(DS1338State *s)
 s->nvram[R_YEAR] = to_bcd(now.tm_year - 100);
 }
 
-static void inc_regptr(DS1338State *s)
+static void inc_regptr(DSRTCState *s)
 {
 /* The register pointer wraps around after 0x3F; wraparound
  * causes the current time/date to be retransferred into
@@ -129,9 +129,9 @@ static void inc_regptr(DS1338State *s)
 }
 }
 
-static int ds1338_event(I2CSlave *i2c, enum i2c_event event)
+static int dsrtc_event(I2CSlave *i2c, enum i2c_event event)
 {
-DS1338State *s = DS1338(i2c);
+DSRTCState *s = DSRTC(i2c);
 
 switch (event) {
 case I2C_START_RECV:
@@ -152,9 +152,9 @@ static int ds1338_event(I2CSlave *i2c, enum i2c_event event)
 return 0;
 }
 
-static int ds1338_recv(I2CSlave *i2c)
+static int dsrtc_recv(I2CSlave *i2c)
 {
-DS1338State *s = DS1338(i2c);
+DSRTCState *s = DSRTC(i2c);
 uint8_t res;
 
 res  = s->nvram[s->ptr];
@@ -165,7 +165,7 @@ static int ds1338_recv(I2CSlave *i2c)
 /* call after guest writes to current time registers
  * to re-compute our offset from host time.
  */
-static void ds1338_update(DS1338State *s)
+static void dsrtc_update(DSRTCState *s)
 {
 
 struct tm now;
@@ -203,9 +203,9 @@ static void ds1338_update(DS1338State *s)
 }
 }
 
-static int ds1338_send(I2CSlave *i2c, uint8_t data)
+static int dsrtc_send(I2CSlave *i2c, uint8_t data)
 {
-DS1338State *s = DS1338(i2c);
+DSRTCState *s = DSRTC(i2c);
 
 if (s->addr_byte) {
 s->ptr = data & (NVRAM_SIZE - 1);
@@ -225,15 +225,15 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
 }
 s->nvram[s->ptr] = data;
 if (s->ptr <= R_YEAR) {
-ds1338_update(s);
+dsrtc_update(s);
 }
 inc_regptr(s);
 return 0;
 }
 
-static void ds1338_reset(DeviceState *dev)
+static void dsrtc_reset(DeviceState *dev)
 {
-DS1338State *s = DS1338(dev);
+DSRTCState *s = DSRTC(dev);
 
 /* The clock is running and synchronized with the host */
 s->offset = 0;
@@ -243,28 +243,28 @@ static void ds1338_reset(DeviceState *dev)
 s->addr_byte = false;
 }
 
-static void ds1338_class_init(ObjectClass *klass, void *data)
+static void dsrtc_class_init(ObjectClass *klass, void *data)
 {
 DeviceClass *dc = DEVICE_CLASS(klass);
 I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
 
-k->event = ds1338_event;
-k->recv = ds1338_recv;
-k->send = ds1338_send;
-dc->reset = ds1338_reset;
-dc->vmsd = _ds1338;
+k->event = dsrtc_event;
+k->recv = dsrtc_recv;
+k->send = dsrtc_send;
+dc->reset = dsrt

[Qemu-devel] [PATCH 02/14] timer: ds1338 use registerfields.h

2018-03-24 Thread Michael Davidsaver
Use names for registers and bits except
for R_CTRL which will be dealt with later,
and isn't modeled anyway.

Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 hw/timer/ds1338.c | 84 ++-
 1 file changed, 58 insertions(+), 26 deletions(-)

diff --git a/hw/timer/ds1338.c b/hw/timer/ds1338.c
index 3849b74a68..b5630e214a 100644
--- a/hw/timer/ds1338.c
+++ b/hw/timer/ds1338.c
@@ -13,6 +13,7 @@
 #include "qemu/osdep.h"
 #include "qemu-common.h"
 #include "hw/i2c/i2c.h"
+#include "hw/registerfields.h"
 #include "qemu/bcd.h"
 
 /* Size of NVRAM including both the user-accessible area and the
@@ -20,15 +21,42 @@
  */
 #define NVRAM_SIZE 64
 
-/* Flags definitions */
-#define SECONDS_CH 0x80
-#define HOURS_12   0x40
-#define HOURS_PM   0x20
 #define CTRL_OSF   0x20
 
 #define TYPE_DS1338 "ds1338"
 #define DS1338(obj) OBJECT_CHECK(DS1338State, (obj), TYPE_DS1338)
 
+/* values stored in BCD */
+/* 00-59 */
+#define R_SEC   (0x0)
+/* 00-59 */
+#define R_MIN   (0x1)
+#define R_HOUR  (0x2)
+/* 1-7 */
+#define R_WDAY  (0x3)
+/* 0-31 */
+#define R_DATE  (0x4)
+#define R_MONTH (0x5)
+/* 0-99 */
+#define R_YEAR  (0x6)
+
+#define R_CTRL  (0x7)
+
+/* use 12 hour mode when set */
+FIELD(HOUR, SET12, 6, 1)
+/* 00-23 */
+FIELD(HOUR, HOUR24, 0, 6)
+/* PM when set */
+FIELD(HOUR, AMPM, 5, 1)
+/* 1-12 (not 0-11!) */
+FIELD(HOUR, HOUR12, 0, 5)
+
+/* 1-12 */
+FIELD(MONTH, MONTH, 0, 5)
+FIELD(MONTH, CENTURY, 7, 1)
+
+FIELD(CTRL, OSF, 5, 1)
+
 typedef struct DS1338State {
 I2CSlave parent_obj;
 
@@ -61,25 +89,29 @@ static void capture_current_time(DS1338State *s)
  */
 struct tm now;
 qemu_get_timedate(, s->offset);
-s->nvram[0] = to_bcd(now.tm_sec);
-s->nvram[1] = to_bcd(now.tm_min);
-if (s->nvram[2] & HOURS_12) {
+s->nvram[R_SEC] = to_bcd(now.tm_sec);
+s->nvram[R_MIN] = to_bcd(now.tm_min);
+if (ARRAY_FIELD_EX32(s->nvram, HOUR, SET12)) {
 int tmp = now.tm_hour;
 if (tmp % 12 == 0) {
 tmp += 12;
 }
+s->nvram[R_HOUR] = 0;
+ARRAY_FIELD_DP32(s->nvram, HOUR, SET12, 1);
 if (tmp <= 12) {
-s->nvram[2] = HOURS_12 | to_bcd(tmp);
+ARRAY_FIELD_DP32(s->nvram, HOUR, AMPM, 0);
+ARRAY_FIELD_DP32(s->nvram, HOUR, HOUR12, to_bcd(tmp));
 } else {
-s->nvram[2] = HOURS_12 | HOURS_PM | to_bcd(tmp - 12);
+ARRAY_FIELD_DP32(s->nvram, HOUR, AMPM, 1);
+ARRAY_FIELD_DP32(s->nvram, HOUR, HOUR12, to_bcd(tmp - 12));
 }
 } else {
-s->nvram[2] = to_bcd(now.tm_hour);
+ARRAY_FIELD_DP32(s->nvram, HOUR, HOUR24, to_bcd(now.tm_hour));
 }
-s->nvram[3] = (now.tm_wday + s->wday_offset) % 7 + 1;
-s->nvram[4] = to_bcd(now.tm_mday);
-s->nvram[5] = to_bcd(now.tm_mon + 1);
-s->nvram[6] = to_bcd(now.tm_year - 100);
+s->nvram[R_WDAY] = (now.tm_wday + s->wday_offset) % 7 + 1;
+s->nvram[R_DATE] = to_bcd(now.tm_mday);
+s->nvram[R_MONTH] = to_bcd(now.tm_mon + 1);
+s->nvram[R_YEAR] = to_bcd(now.tm_year - 100);
 }
 
 static void inc_regptr(DS1338State *s)
@@ -141,17 +173,17 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
 struct tm now;
 qemu_get_timedate(, s->offset);
 switch(s->ptr) {
-case 0:
+case R_SEC:
 /* TODO: Implement CH (stop) bit.  */
 now.tm_sec = from_bcd(data & 0x7f);
 break;
-case 1:
+case R_MIN:
 now.tm_min = from_bcd(data & 0x7f);
 break;
-case 2:
-if (data & HOURS_12) {
-int tmp = from_bcd(data & (HOURS_PM - 1));
-if (data & HOURS_PM) {
+case R_HOUR:
+if (FIELD_EX32(data, HOUR, SET12)) {
+int tmp = from_bcd(FIELD_EX32(data, HOUR, HOUR12));
+if (FIELD_EX32(data, HOUR, AMPM)) {
 tmp += 12;
 }
 if (tmp % 12 == 0) {
@@ -159,10 +191,10 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
 }
 now.tm_hour = tmp;
 } else {
-now.tm_hour = from_bcd(data & (HOURS_12 - 1));
+now.tm_hour = from_bcd(FIELD_EX32(data, HOUR, HOUR24));
 }
 break;
-case 3:
+case R_WDAY:
 {
 /* The day field is supposed to contain a value in
the range 1-7. Otherwise behavior is undefined.
@@ -171,18 +203,18 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
 s->wday_offset = (user_wday - now.tm_wday + 7) % 7;
 }
 break;
-case 4:
+case R_DATE:
 now.tm_mday = from_bcd(data & 0x3f);
 break;
-   

[Qemu-devel] [PATCH 06/14] tests: ds-rtc test 12 hour mode

2018-03-24 Thread Michael Davidsaver
Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 tests/ds-rtc-set-test.c | 52 +
 1 file changed, 52 insertions(+)

diff --git a/tests/ds-rtc-set-test.c b/tests/ds-rtc-set-test.c
index 35e1a36281..c48406ee2c 100644
--- a/tests/ds-rtc-set-test.c
+++ b/tests/ds-rtc-set-test.c
@@ -29,6 +29,18 @@ static uint8_t test_time_24_12am[8] = {
 0x17,
 };
 
+static uint8_t test_time_12_12am[8] = {
+0, /* address */
+/* Wed, 22 Nov 2017 00:30:53 + */
+0x53,
+0x30,
+0x52, /* 12 AM in 12 hour mode */
+0x03, /* monday is our day 1 */
+0x22,
+0x11 | 0x80,
+0x17,
+};
+
 static uint8_t test_time_24_6am[8] = {
 0, /* address */
 /* Wed, 22 Nov 2017 06:30:53 + */
@@ -41,6 +53,18 @@ static uint8_t test_time_24_6am[8] = {
 0x17,
 };
 
+static uint8_t test_time_12_6am[8] = {
+0, /* address */
+/* Wed, 22 Nov 2017 06:30:53 + */
+0x53,
+0x30,
+0x46, /* 6 AM in 12 hour mode */
+0x03, /* monday is our day 1 */
+0x22,
+0x11 | 0x80,
+0x17,
+};
+
 static uint8_t test_time_24_12pm[8] = {
 0, /* address */
 /* Wed, 22 Nov 2017 12:30:53 + */
@@ -53,6 +77,18 @@ static uint8_t test_time_24_12pm[8] = {
 0x17,
 };
 
+static uint8_t test_time_12_12pm[8] = {
+0, /* address */
+/* Wed, 22 Nov 2017 12:30:53 + */
+0x53,
+0x30,
+0x72, /* 12 PM in 24 hour mode */
+0x03, /* monday is our day 1 */
+0x22,
+0x11 | 0x80,
+0x17,
+};
+
 static uint8_t test_time_24_6pm[8] = {
 0, /* address */
 /* Wed, 22 Nov 2017 18:30:53 + */
@@ -65,6 +101,18 @@ static uint8_t test_time_24_6pm[8] = {
 0x17,
 };
 
+static uint8_t test_time_12_6pm[8] = {
+0, /* address */
+/* Wed, 22 Nov 2017 18:30:53 + */
+0x53,
+0x30,
+0x66, /* 6 PM in 12 hour mode */
+0x03, /* monday is our day 1 */
+0x22,
+0x11 | 0x80,
+0x17,
+};
+
 /* write in and read back known time */
 static
 void test_rtc_set(const void *raw)
@@ -108,6 +156,10 @@ int main(int argc, char *argv[])
 qtest_add_data_func("/ds-rtc-i2c/set24_6am", test_time_24_6am, 
test_rtc_set);
 qtest_add_data_func("/ds-rtc-i2c/set24_12pm", test_time_24_12pm, 
test_rtc_set);
 qtest_add_data_func("/ds-rtc-i2c/set24_6pm", test_time_24_6pm, 
test_rtc_set);
+qtest_add_data_func("/ds-rtc-i2c/set12_12am", test_time_12_12am, 
test_rtc_set);
+qtest_add_data_func("/ds-rtc-i2c/set12_6am", test_time_12_6am, 
test_rtc_set);
+qtest_add_data_func("/ds-rtc-i2c/set12_12pm", test_time_12_12pm, 
test_rtc_set);
+qtest_add_data_func("/ds-rtc-i2c/set12_6pm", test_time_12_6pm, 
test_rtc_set);
 
 ret = g_test_run();
 
-- 
2.11.0




[Qemu-devel] [PATCH 08/14] tests: ds-rtc test wday offset

2018-03-24 Thread Michael Davidsaver
Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 tests/ds-rtc-common.h   | 10 +++---
 tests/ds-rtc-current-test.c |  9 -
 tests/ds-rtc-set-test.c |  6 --
 3 files changed, 19 insertions(+), 6 deletions(-)

diff --git a/tests/ds-rtc-common.h b/tests/ds-rtc-common.h
index c8e6c2bc5b..633131c55f 100644
--- a/tests/ds-rtc-common.h
+++ b/tests/ds-rtc-common.h
@@ -20,7 +20,7 @@ static uint8_t addr;
 static bool use_century;
 
 /* input buffer must have at least 7 elements */
-static inline time_t rtc_parse(const uint8_t *buf)
+static inline time_t rtc_parse(const uint8_t *buf, unsigned *wday)
 {
 struct tm parts;
 
@@ -48,10 +48,14 @@ static inline time_t rtc_parse(const uint8_t *buf)
 parts.tm_year += 100u;
 }
 
+if (wday) {
+*wday = parts.tm_wday;
+}
+
 return mktimegm();
 }
 
-static time_t rtc_gettime(void)
+static time_t rtc_gettime(unsigned *wday)
 {
 uint8_t buf[7];
 
@@ -61,7 +65,7 @@ static time_t rtc_gettime(void)
 /* read back current time registers */
 i2c_recv(i2c, addr, buf, 7);
 
-return rtc_parse(buf);
+return rtc_parse(buf, wday);
 }
 
 #endif /* DSRTCCOMMON_H */
diff --git a/tests/ds-rtc-current-test.c b/tests/ds-rtc-current-test.c
index 6acbbed9a6..7dc3202261 100644
--- a/tests/ds-rtc-current-test.c
+++ b/tests/ds-rtc-current-test.c
@@ -20,17 +20,24 @@
 static
 void test_rtc_current(void)
 {
+struct tm tm_actual;
 time_t expected, actual;
 /* relax test to limit false positives when host may be overloaded.
  * Allow larger delta when running "-m quick"
  */
 time_t max_delta = g_test_slow() ? 1 : 30;
 
+unsigned wday_expect;
+
 actual = time(NULL);
 /* new second may start here */
-expected = rtc_gettime();
+expected = rtc_gettime(_expect);
+
+gmtime_r(, _actual);
+
 g_assert_cmpuint(expected, <=, actual + max_delta);
 g_assert_cmpuint(expected, >=, actual);
+g_assert_cmpuint(wday_expect, ==, tm_actual.tm_wday);
 }
 
 int main(int argc, char *argv[])
diff --git a/tests/ds-rtc-set-test.c b/tests/ds-rtc-set-test.c
index c48406ee2c..12aeb2580a 100644
--- a/tests/ds-rtc-set-test.c
+++ b/tests/ds-rtc-set-test.c
@@ -124,16 +124,18 @@ void test_rtc_set(const void *raw)
 
 const uint8_t *testtime = raw;
 time_t expected, actual;
+unsigned wday_expect, wday_actual;
 
 /* skip address pointer and parse remainder */
-expected = rtc_parse([1]);
+expected = rtc_parse([1], _expect);
 
 i2c_send(i2c, addr, testtime, 8);
 /* host may start new second here */
-actual = rtc_gettime();
+actual = rtc_gettime(_actual);
 
 g_assert_cmpuint(expected, <=, actual);
 g_assert_cmpuint(expected + max_delta, >=, actual);
+g_assert_cmpuint(wday_expect, ==, wday_actual);
 }
 
 int main(int argc, char *argv[])
-- 
2.11.0




[Qemu-devel] [PATCH 12/14] timer: ds-rtc handle CENTURY bit

2018-03-24 Thread Michael Davidsaver
Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 hw/timer/ds-rtc.c | 22 ++
 1 file changed, 14 insertions(+), 8 deletions(-)

diff --git a/hw/timer/ds-rtc.c b/hw/timer/ds-rtc.c
index 2df1bce3f8..5a4df1b115 100644
--- a/hw/timer/ds-rtc.c
+++ b/hw/timer/ds-rtc.c
@@ -70,6 +70,7 @@ typedef struct DSRTCState {
 typedef struct DSRTCClass {
 I2CSlaveClass parent_obj;
 
+bool has_century;
 /* actual address space size must be <= NVRAM_SIZE */
 unsigned addr_size;
 unsigned ctrl_offset;
@@ -91,7 +92,7 @@ static const VMStateDescription vmstate_dsrtc = {
 }
 };
 
-static void capture_current_time(DSRTCState *s)
+static void capture_current_time(DSRTCState *s, DSRTCClass *k)
 {
 /* Capture the current time into the secondary registers
  * which will be actually read by the data transfer operation.
@@ -123,25 +124,28 @@ static void capture_current_time(DSRTCState *s)
 }
 s->nvram[R_DATE] = to_bcd(now.tm_mday);
 s->nvram[R_MONTH] = to_bcd(now.tm_mon + 1);
-s->nvram[R_YEAR] = to_bcd(now.tm_year - 100);
+s->nvram[R_YEAR] = to_bcd(now.tm_year % 100u);
+
+ARRAY_FIELD_DP32(s->nvram, MONTH, CENTURY,
+ k->has_century && now.tm_year >= 100)
 }
 
-static void inc_regptr(DSRTCState *s)
+static void inc_regptr(DSRTCState *s, DSRTCClass *k)
 {
-DSRTCClass *k = DSRTC_GET_CLASS(s);
 /* The register pointer wraps around after k->addr_size-1; wraparound
  * causes the current time/date to be retransferred into
  * the secondary registers.
  */
 s->ptr = (s->ptr + 1) % k->addr_size;
 if (!s->ptr) {
-capture_current_time(s);
+capture_current_time(s, k);
 }
 }
 
 static int dsrtc_event(I2CSlave *i2c, enum i2c_event event)
 {
 DSRTCState *s = DSRTC(i2c);
+DSRTCClass *k = DSRTC_GET_CLASS(s);
 
 switch (event) {
 case I2C_START_RECV:
@@ -150,7 +154,7 @@ static int dsrtc_event(I2CSlave *i2c, enum i2c_event event)
  * START_SEND, because the guest can't get at that data
  * without going through a START_RECV which would overwrite it.
  */
-capture_current_time(s);
+capture_current_time(s, k);
 break;
 case I2C_START_SEND:
 s->addr_byte = true;
@@ -165,10 +169,11 @@ static int dsrtc_event(I2CSlave *i2c, enum i2c_event 
event)
 static int dsrtc_recv(I2CSlave *i2c)
 {
 DSRTCState *s = DSRTC(i2c);
+DSRTCClass *k = DSRTC_GET_CLASS(s);
 uint8_t res;
 
 res  = s->nvram[s->ptr];
-inc_regptr(s);
+inc_regptr(s, k);
 return res;
 }
 
@@ -230,7 +235,7 @@ static int dsrtc_send(I2CSlave *i2c, uint8_t data)
 if (s->ptr <= R_YEAR) {
 dsrtc_update(s);
 }
-inc_regptr(s);
+inc_regptr(s, k);
 return 0;
 }
 
@@ -278,6 +283,7 @@ static void ds1338_class_init(ObjectClass *klass, void 
*data)
 {
 DSRTCClass *k = DSRTC_CLASS(klass);
 
+k->has_century = false;
 k->addr_size = 0x40;
 k->ctrl_offset = R_DS1338_CTRL;
 k->ctrl_write = ds1338_control_write;
-- 
2.11.0




[Qemu-devel] [PATCH 05/14] timer: ds1338 change write handling

2018-03-24 Thread Michael Davidsaver
instead of a read-modify-write, do direct translation
of device registers to struct tm members.

This new ds1338_update() is the reverse of
the existing capture_current_time().

Simplifies later handling of CENTURY bit in
similar Dallas RTC chips.

Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 hw/timer/ds1338.c | 86 ++-
 1 file changed, 40 insertions(+), 46 deletions(-)

diff --git a/hw/timer/ds1338.c b/hw/timer/ds1338.c
index 9bcda26e51..071c031563 100644
--- a/hw/timer/ds1338.c
+++ b/hw/timer/ds1338.c
@@ -159,6 +159,42 @@ static int ds1338_recv(I2CSlave *i2c)
 return res;
 }
 
+/* call after guest writes to current time registers
+ * to re-compute our offset from host time.
+ */
+static void ds1338_update(DS1338State *s)
+{
+
+struct tm now;
+memset(, 0, sizeof(now));
+
+/* TODO: Implement CH (stop) bit?  */
+now.tm_sec = from_bcd(s->nvram[R_SEC] & 0x7f);
+now.tm_min = from_bcd(s->nvram[R_MIN] & 0x7f);
+if (ARRAY_FIELD_EX32(s->nvram, HOUR, SET12)) {
+/* 12 hour (1-12) */
+/* read and wrap 1-12 -> 0-11 */
+now.tm_hour = from_bcd(ARRAY_FIELD_EX32(s->nvram, HOUR, HOUR12)) % 12u;
+if (ARRAY_FIELD_EX32(s->nvram, HOUR, AMPM)) {
+now.tm_hour += 12;
+}
+
+} else {
+now.tm_hour = from_bcd(ARRAY_FIELD_EX32(s->nvram, HOUR, HOUR24));
+}
+{
+/* The day field is supposed to contain a value in
+   the range 1-7. Otherwise behavior is undefined.
+ */
+int user_wday = (s->nvram[R_WDAY] & 7) - 1;
+s->wday_offset = (user_wday - now.tm_wday + 7) % 7;
+}
+now.tm_mday = from_bcd(s->nvram[R_DATE] & 0x3f);
+now.tm_mon = from_bcd(s->nvram[R_MONTH] & 0x1f) - 1;
+now.tm_year = from_bcd(s->nvram[R_YEAR]) + 100;
+s->offset = qemu_timedate_diff();
+}
+
 static int ds1338_send(I2CSlave *i2c, uint8_t data)
 {
 DS1338State *s = DS1338(i2c);
@@ -168,52 +204,7 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
 s->addr_byte = false;
 return 0;
 }
-if (s->ptr < 7) {
-/* Time register. */
-struct tm now;
-qemu_get_timedate(, s->offset);
-switch(s->ptr) {
-case R_SEC:
-/* TODO: Implement CH (stop) bit.  */
-now.tm_sec = from_bcd(data & 0x7f);
-break;
-case R_MIN:
-now.tm_min = from_bcd(data & 0x7f);
-break;
-case R_HOUR:
-if (FIELD_EX32(data, HOUR, SET12)) {
-/* 12 hour (1-12) */
-/* read and wrap 1-12 -> 0-11 */
-now.tm_hour = from_bcd(FIELD_EX32(data, HOUR, HOUR12)) % 12u;
-if (FIELD_EX32(data, HOUR, AMPM)) {
-now.tm_hour += 12;
-}
-
-} else {
-now.tm_hour = from_bcd(FIELD_EX32(data, HOUR, HOUR24));
-}
-break;
-case R_WDAY:
-{
-/* The day field is supposed to contain a value in
-   the range 1-7. Otherwise behavior is undefined.
- */
-int user_wday = (data & 7) - 1;
-s->wday_offset = (user_wday - now.tm_wday + 7) % 7;
-}
-break;
-case R_DATE:
-now.tm_mday = from_bcd(data & 0x3f);
-break;
-case R_MONTH:
-now.tm_mon = from_bcd(data & 0x1f) - 1;
-break;
-case R_YEAR:
-now.tm_year = from_bcd(data) + 100;
-break;
-}
-s->offset = qemu_timedate_diff();
-} else if (s->ptr == R_CTRL) {
+if (s->ptr == R_CTRL) {
 /* Control register. */
 
 /* Ensure bits 2, 3 and 6 will read back as zero. */
@@ -225,6 +216,9 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
 
 }
 s->nvram[s->ptr] = data;
+if (s->ptr <= R_YEAR) {
+ds1338_update(s);
+}
 inc_regptr(s);
 return 0;
 }
-- 
2.11.0




[Qemu-devel] [PATCH 14/14] tests: drop ds1338-test

2018-03-24 Thread Michael Davidsaver
redundant to ds-rtc-*-test.c

Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 tests/Makefile.include |  2 --
 tests/ds1338-test.c| 75 --
 2 files changed, 77 deletions(-)
 delete mode 100644 tests/ds1338-test.c

diff --git a/tests/Makefile.include b/tests/Makefile.include
index d256095c88..04a99ea6fb 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -371,7 +371,6 @@ check-qtest-sparc64-y += tests/prom-env-test$(EXESUF)
 check-qtest-sparc64-y += tests/boot-serial-test$(EXESUF)
 
 check-qtest-arm-y = tests/tmp105-test$(EXESUF)
-check-qtest-arm-y += tests/ds1338-test$(EXESUF)
 check-qtest-arm-y += tests/ds-rtc-current-test$(EXESUF)
 check-qtest-arm-y += tests/ds-rtc-set-test$(EXESUF)
 check-qtest-arm-y += tests/m25p80-test$(EXESUF)
@@ -772,7 +771,6 @@ tests/bios-tables-test$(EXESUF): tests/bios-tables-test.o \
tests/boot-sector.o tests/acpi-utils.o $(libqos-obj-y)
 tests/pxe-test$(EXESUF): tests/pxe-test.o tests/boot-sector.o $(libqos-obj-y)
 tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y)
-tests/ds1338-test$(EXESUF): tests/ds1338-test.o $(libqos-imx-obj-y)
 tests/ds-rtc-current-test$(EXESUF): tests/ds-rtc-current-test.o 
$(libqos-imx-obj-y)
 tests/ds-rtc-set-test$(EXESUF): tests/ds-rtc-set-test.o $(libqos-imx-obj-y)
 tests/m25p80-test$(EXESUF): tests/m25p80-test.o
diff --git a/tests/ds1338-test.c b/tests/ds1338-test.c
deleted file mode 100644
index 742dad9113..00
--- a/tests/ds1338-test.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * QTest testcase for the DS1338 RTC
- *
- * Copyright (c) 2013 Jean-Christophe Dubois
- *
- *  This program is free software; you can redistribute it and/or modify it
- *  under the terms of the GNU General Public License as published by the
- *  Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful, but WITHOUT
- *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- *  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- *  for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest.h"
-#include "libqos/i2c.h"
-
-#define IMX25_I2C_0_BASE 0x43F8
-
-#define DS1338_ADDR 0x68
-
-static I2CAdapter *i2c;
-static uint8_t addr;
-
-static inline uint8_t bcd2bin(uint8_t x)
-{
-return ((x) & 0x0f) + ((x) >> 4) * 10;
-}
-
-static void send_and_receive(void)
-{
-uint8_t cmd[1];
-uint8_t resp[7];
-time_t now = time(NULL);
-struct tm *tm_ptr = gmtime();
-
-/* reset the index in the RTC memory */
-cmd[0] = 0;
-i2c_send(i2c, addr, cmd, 1);
-
-/* retrieve the date */
-i2c_recv(i2c, addr, resp, 7);
-
-/* check retrieved time againt local time */
-g_assert_cmpuint(bcd2bin(resp[4]), == , tm_ptr->tm_mday);
-g_assert_cmpuint(bcd2bin(resp[5]), == , 1 + tm_ptr->tm_mon);
-g_assert_cmpuint(2000 + bcd2bin(resp[6]), == , 1900 + tm_ptr->tm_year);
-}
-
-int main(int argc, char **argv)
-{
-QTestState *s = NULL;
-int ret;
-
-g_test_init(, , NULL);
-
-s = qtest_start("-display none -machine imx25-pdk");
-i2c = imx_i2c_create(s, IMX25_I2C_0_BASE);
-addr = DS1338_ADDR;
-
-qtest_add_func("/ds1338/tx-rx", send_and_receive);
-
-ret = g_test_run();
-
-qtest_quit(s);
-g_free(i2c);
-
-return ret;
-}
-- 
2.11.0




[Qemu-devel] [PATCH 00/14] Generalize Dallas/Maxim I2C RTC devices v2

2018-03-24 Thread Michael Davidsaver
This series generalizes the ds1338 model to also support the ds1375.
As previously, only the time of day registers are modeled.  This
series is largely a do-over wrt. my previous series.  This time I
started with incremental changes from the existing ds1338 model, and only
add support for the ds1375 (which I care about).

I've added a more thorough test of the time of day function, covering
reading and setting in both 12 and 24 hour mode.  This corrects two
(practically inconsequential) bugs with the handling of 12 hour mode,
and day of the week.

In an attempt to address concerns about false positive test failures
in CI builds, instead of comparing the parts of 'struct tm' seperately
I've changed the logic of the tests to compare the difference between
the expected and actual time in seconds.  The threshold is 30 seconds
when run with 'gtester -m quick', and 1 second otherwise.

Comparision of day of the week is still exact, so there is a chance of
a false positive if the test is running across midnight UTC.

Michael Davidsaver (14):
  tests: more thorough tests of ds1338
  timer: ds1338 use registerfields.h
  timer: ds1338 persist 12-hour mode selection
  timer: ds1338 clarify HOUR handling
  timer: ds1338 change write handling
  tests: ds-rtc test 12 hour mode
  timer: ds1338 fix wday_offset handling
  tests: ds-rtc test wday offset
  timer: rename ds1338 -> dsrtc
  timer: rename file ds1338.c -> ds-rtc.c
  timer: generalize ds1338
  timer: ds-rtc handle CENTURY bit
  timer: ds-rtc model ds1375
  tests: drop ds1338-test

 default-configs/arm-softmmu.mak |   2 +-
 hw/timer/Makefile.objs  |   2 +-
 hw/timer/ds-rtc.c   | 331 
 hw/timer/ds1338.c   | 239 -
 tests/Makefile.include  |   6 +-
 tests/ds-rtc-common.h   |  71 +
 tests/ds-rtc-current-test.c |  66 
 tests/ds-rtc-set-test.c | 171 +
 tests/ds1338-test.c |  75 -
 9 files changed, 645 insertions(+), 318 deletions(-)
 create mode 100644 hw/timer/ds-rtc.c
 delete mode 100644 hw/timer/ds1338.c
 create mode 100644 tests/ds-rtc-common.h
 create mode 100644 tests/ds-rtc-current-test.c
 create mode 100644 tests/ds-rtc-set-test.c
 delete mode 100644 tests/ds1338-test.c

-- 
2.11.0




Re: [Qemu-devel] [PATCH 2/5] tests: more thorough test of ds1338

2018-02-20 Thread Michael Davidsaver
On 02/18/2018 11:39 PM, Thomas Huth wrote:
> On 19.02.2018 05:03, Michael Davidsaver wrote:
>> Test current time and set+get round trip.
>>
>> The set+get test is repeated 4 times.  These cases are
>> spread across a single day in an attempt to trigger some potential
>> issues regardless of the timezone of the machine running the tests.
>>
>> Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
>> ---
>>  tests/Makefile.include  |   2 +
>>  tests/ds-rtc-i2c-test.c | 193 
>> 
>>  2 files changed, 195 insertions(+)
>>  create mode 100644 tests/ds-rtc-i2c-test.c
> [...]
>>  tests/q35-test$(EXESUF): tests/q35-test.o $(libqos-pc-obj-y)
>> diff --git a/tests/ds-rtc-i2c-test.c b/tests/ds-rtc-i2c-test.c
>> new file mode 100644
>> index 00..464eb08558
>> --- /dev/null
>> +++ b/tests/ds-rtc-i2c-test.c
>> @@ -0,0 +1,193 @@
>> +/* Testing of Dallas/Maxim I2C bus RTC devices
>> + *
>> + * Copyright (c) 2017 Michael Davidsaver
>> + *
>> + * This work is licensed under the terms of the GNU GPL, version 2.  See
>> + * the LICENSE file in the top-level directory.
>> + */
>> +#include 
>> +
>> +#include "qemu/osdep.h"
>> +#include "qemu/bcd.h"
>> +#include "qemu/cutils.h"
>> +#include "qemu/timer.h"
>> +#include "libqtest.h"
>> +#include "libqos/libqos.h"
>> +#include "libqos/i2c.h"
>> +
>> +#define IMX25_I2C_0_BASE 0x43F8
>> +#define DS1338_ADDR 0x68
>> +
>> +static I2CAdapter *i2c;
>> +static uint8_t addr;
>> +static bool use_century;
>> +
>> +static
>> +time_t rtc_gettime(void)
>> +{
>> +struct tm parts;
>> +uint8_t buf[7];
>> +
>> +buf[0] = 0;
>> +i2c_send(i2c, addr, buf, 1);
>> +i2c_recv(i2c, addr, buf, 7);
>> +
>> +parts.tm_sec = from_bcd(buf[0]);
>> +parts.tm_min = from_bcd(buf[1]);
>> +if (buf[2] & 0x40) {
>> +/* 12 hour */
>> +/* HOUR register is 1-12. */
>> +parts.tm_hour = from_bcd(buf[2] & 0x1f);
>> +g_assert_cmpuint(parts.tm_hour, >=, 1);
>> +g_assert_cmpuint(parts.tm_hour, <=, 12);
>> +parts.tm_hour %= 12u; /* wrap 12 -> 0 */
>> +if (buf[2] & 0x20) {
>> +parts.tm_hour += 12u;
>> +}
>> +} else {
>> +/* 24 hour */
>> +parts.tm_hour = from_bcd(buf[2] & 0x3f);
>> +}
>> +parts.tm_wday = from_bcd(buf[3]);
>> +parts.tm_mday = from_bcd(buf[4]);
>> +parts.tm_mon =  from_bcd((buf[5] & 0x1f) - 1u);
>> +parts.tm_year = from_bcd(buf[6]);
>> +if (!use_century || (buf[5] & 0x80)) {
>> +parts.tm_year += 100u;
>> +}
>> +
>> +return mktimegm();
>> +}
>> +
>> +/* read back and compare with current system time */
>> +static
>> +void test_rtc_current(void)
>> +{
>> +uint8_t buf;
>> +time_t expected, actual;
>> +
>> +/* magic address to zero RTC time offset
>> + * as tests may be run in any order
>> + */
>> +buf = 0xff;
>> +i2c_send(i2c, addr, , 1);
> 
> That magic (together with patch 1/5) is IMHO a little bit ugly. I've hit
> the same problem with the m48t59 test recently, and I solved it by
> moving the qtest_start() and qtest_end() calls from the main() function
> into the single tests instead, so that each test starts with a clean state:
> 
> https://git.qemu.org/?p=qemu.git;a=commitdiff;h=9c29830c90d82f27f
> 
> Could you maybe try whether that approach works for your test cases
> here, too? Then you could do this without the "0xff" hack here...

Your right, this looks clearer.  I'll try this approach.

>> +
>> +actual = time(NULL);
>> +/* new second may start here */
>> +expected = rtc_gettime();
>> +g_assert_cmpuint(expected, <=, actual + 1);
>> +g_assert_cmpuint(expected, >=, actual);
>> +}
>> +
>> +
>> +static uint8_t test_time_24_12am[8] = {
>> +0, /* address */
>> +/* Wed, 22 Nov 2017 00:30:53 + */
>> +0x53,
>> +0x30,
>> +0x00, /* 12 AM in 24 hour mode */
>> +0x03, /* monday is our day 1 */
>> +0x22,
>> +0x11 | 0x80,
>> +0x17,
>> +};
>> +
>> +static uint8_t test_time_24_6am[8] = {
>> +0, /* address */
>> +/* Wed, 22 Nov 2017 06:30:53 + */
>>

[Qemu-devel] [PATCH 3/5] timer: generalize Dallas/Maxim RTC i2c devices

2018-02-18 Thread Michael Davidsaver
Support for: ds1307, ds1337, ds1338, ds1339,
ds1340, ds1375, ds1388, and ds3231.

Tested with ds1338 and ds1375.

The existing ds1338 model has two bugs
with almost no practical impact.

1. Trying to set time in 12-hour mode works,
but the 12 hour mode bit isn't stored.
So time always reads in 24 hour mode.

2. wday_offset is always stored for the
local time zone.  When the RTC is set
and rtc_utc=1 and the local timezone
has a different day than UTC, then
wday_offset will be off by one.

Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 default-configs/arm-softmmu.mak |   2 +-
 hw/timer/Makefile.objs  |   2 +-
 hw/timer/ds-rtc-i2c.c   | 466 
 hw/timer/ds1338.c   | 248 -
 4 files changed, 468 insertions(+), 250 deletions(-)
 create mode 100644 hw/timer/ds-rtc-i2c.c
 delete mode 100644 hw/timer/ds1338.c

diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index ca34cf4462..510a92c9a8 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -31,7 +31,7 @@ CONFIG_SMC91C111=y
 CONFIG_ALLWINNER_EMAC=y
 CONFIG_IMX_FEC=y
 CONFIG_FTGMAC100=y
-CONFIG_DS1338=y
+CONFIG_DSRTCI2C=y
 CONFIG_PFLASH_CFI01=y
 CONFIG_PFLASH_CFI02=y
 CONFIG_MICRODRIVE=y
diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs
index 8c19eac3b6..290015ebec 100644
--- a/hw/timer/Makefile.objs
+++ b/hw/timer/Makefile.objs
@@ -3,7 +3,7 @@ common-obj-$(CONFIG_ARM_MPTIMER) += arm_mptimer.o
 common-obj-$(CONFIG_ARM_V7M) += armv7m_systick.o
 common-obj-$(CONFIG_A9_GTIMER) += a9gtimer.o
 common-obj-$(CONFIG_CADENCE) += cadence_ttc.o
-common-obj-$(CONFIG_DS1338) += ds1338.o
+common-obj-$(CONFIG_DSRTCI2C) += ds-rtc-i2c.o
 common-obj-$(CONFIG_HPET) += hpet.o
 common-obj-$(CONFIG_I8254) += i8254_common.o i8254.o
 common-obj-$(CONFIG_M48T59) += m48t59.o
diff --git a/hw/timer/ds-rtc-i2c.c b/hw/timer/ds-rtc-i2c.c
new file mode 100644
index 00..ebe53bbec7
--- /dev/null
+++ b/hw/timer/ds-rtc-i2c.c
@@ -0,0 +1,466 @@
+/* Emulation of various Dallas/Maxim RTCs accessed via I2C bus
+ *
+ * Copyright (c) 2017 Michael Davidsaver
+ * Copyright (c) 2009 CodeSourcery
+ *
+ * Authors: Michael Davidsaver
+ *  Paul Brook
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the LICENSE file in the top-level directory.
+ *
+ * Models real time read/set and NVRAM.
+ * Does not model alarms, or control/status registers.
+ *
+ * Generalized register map is:
+ *   [Current time]
+ *   [Alarm settings] (optional)
+ *   [Control/Status] (optional)
+ *   [Non-volatile memory] (optional)
+ *
+ * The current time registers are almost always the same,
+ * with the exception being that some have a CENTURY bit
+ * in the month register.
+ */
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qemu/timer.h"
+#include "qemu/bcd.h"
+#include "hw/hw.h"
+#include "hw/registerfields.h"
+#include "hw/i2c/i2c.h"
+#include "sysemu/qtest.h"
+#include "qemu/error-report.h"
+
+/* #define DEBUG_DSRTC */
+
+#ifdef DEBUG_DSRTC
+#define DPRINTK(FMT, ...) info_report(TYPE_DSRTC " : " FMT, ## __VA_ARGS__)
+#else
+#define DPRINTK(FMT, ...) do {} while (0)
+#endif
+
+#define LOG(MSK, FMT, ...) qemu_log_mask(MSK, TYPE_DSRTC " : " FMT "\n", \
+## __VA_ARGS__)
+
+#define DSRTC_REGSIZE (0x40)
+
+/* values stored in BCD */
+/* 00-59 */
+#define R_SEC   (0x0)
+/* 00-59 */
+#define R_MIN   (0x1)
+#define R_HOUR  (0x2)
+/* 1-7 */
+#define R_WDAY  (0x3)
+/* 0-31 */
+#define R_DATE  (0x4)
+#define R_MONTH (0x5)
+/* 0-99 */
+#define R_YEAR  (0x6)
+
+/* use 12 hour mode when set */
+FIELD(HOUR, SET12, 6, 1)
+/* 00-23 */
+FIELD(HOUR, HOUR24, 0, 6)
+FIELD(HOUR, AMPM, 5, 1)
+/* 1-12 (not 0-11!) */
+FIELD(HOUR, HOUR12, 0, 5)
+
+/* 1-12 */
+FIELD(MONTH, MONTH, 0, 5)
+FIELD(MONTH, CENTURY, 7, 1)
+
+typedef struct DSRTCInfo {
+/* if bit 7 of the Month register is set after Y2K */
+bool has_century;
+/* address of first non-volatile memory cell.
+ * nv_start >= reg_end means no NV memory.
+ */
+uint8_t nv_start;
+/* total size of register range.  When address counter rolls over. */
+uint8_t reg_size;
+} DSRTCInfo;
+
+typedef struct DSRTCState {
+I2CSlave parent_obj;
+
+const DSRTCInfo *info;
+
+qemu_irq alarm_irq;
+
+/* register address counter */
+uint8_t addr;
+/* when writing, whether the address has been sent */
+bool addrd;
+
+int64_t time_offset;
+int8_t wday_offset;
+
+uint8_t regs[DSRTC_REGSIZE];
+} DSRTCState;
+
+typedef struct DSRTCClass {
+I2CSlaveClass parent_class;
+
+const DSRTCInfo *info;
+} DSRTCClass;
+
+#define TYPE_DSRTC "ds-rtc-i2c"
+#define DSRTC(obj) OBJECT_CHECK(DSRTCState, (obj), TYPE_DSRTC)
+#define DSRTC_GET_CLASS(obj) \
+OBJECT_

[Qemu-devel] [PATCH 5/5] tests: drop ds1338-test

2018-02-18 Thread Michael Davidsaver
Now redundant to ds-rtc-i2c-test.

Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 tests/Makefile.include |  2 --
 tests/ds1338-test.c| 75 --
 2 files changed, 77 deletions(-)
 delete mode 100644 tests/ds1338-test.c

diff --git a/tests/Makefile.include b/tests/Makefile.include
index f5dcd274e0..8b1e486e32 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -359,7 +359,6 @@ check-qtest-sparc64-y += tests/prom-env-test$(EXESUF)
 check-qtest-sparc64-y += tests/boot-serial-test$(EXESUF)
 
 check-qtest-arm-y = tests/tmp105-test$(EXESUF)
-check-qtest-arm-y += tests/ds1338-test$(EXESUF)
 check-qtest-arm-y += tests/ds-rtc-i2c-test$(EXESUF)
 check-qtest-arm-y += tests/m25p80-test$(EXESUF)
 gcov-files-arm-y += hw/misc/tmp105.c
@@ -764,7 +763,6 @@ tests/bios-tables-test$(EXESUF): tests/bios-tables-test.o \
tests/boot-sector.o tests/acpi-utils.o $(libqos-obj-y)
 tests/pxe-test$(EXESUF): tests/pxe-test.o tests/boot-sector.o $(libqos-obj-y)
 tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y)
-tests/ds1338-test$(EXESUF): tests/ds1338-test.o $(libqos-imx-obj-y)
 tests/ds-rtc-i2c-test$(EXESUF): tests/ds-rtc-i2c-test.o $(libqos-imx-obj-y)
 tests/m25p80-test$(EXESUF): tests/m25p80-test.o
 tests/i440fx-test$(EXESUF): tests/i440fx-test.o $(libqos-pc-obj-y)
diff --git a/tests/ds1338-test.c b/tests/ds1338-test.c
deleted file mode 100644
index 742dad9113..00
--- a/tests/ds1338-test.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * QTest testcase for the DS1338 RTC
- *
- * Copyright (c) 2013 Jean-Christophe Dubois
- *
- *  This program is free software; you can redistribute it and/or modify it
- *  under the terms of the GNU General Public License as published by the
- *  Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful, but WITHOUT
- *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- *  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- *  for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "libqtest.h"
-#include "libqos/i2c.h"
-
-#define IMX25_I2C_0_BASE 0x43F8
-
-#define DS1338_ADDR 0x68
-
-static I2CAdapter *i2c;
-static uint8_t addr;
-
-static inline uint8_t bcd2bin(uint8_t x)
-{
-return ((x) & 0x0f) + ((x) >> 4) * 10;
-}
-
-static void send_and_receive(void)
-{
-uint8_t cmd[1];
-uint8_t resp[7];
-time_t now = time(NULL);
-struct tm *tm_ptr = gmtime();
-
-/* reset the index in the RTC memory */
-cmd[0] = 0;
-i2c_send(i2c, addr, cmd, 1);
-
-/* retrieve the date */
-i2c_recv(i2c, addr, resp, 7);
-
-/* check retrieved time againt local time */
-g_assert_cmpuint(bcd2bin(resp[4]), == , tm_ptr->tm_mday);
-g_assert_cmpuint(bcd2bin(resp[5]), == , 1 + tm_ptr->tm_mon);
-g_assert_cmpuint(2000 + bcd2bin(resp[6]), == , 1900 + tm_ptr->tm_year);
-}
-
-int main(int argc, char **argv)
-{
-QTestState *s = NULL;
-int ret;
-
-g_test_init(, , NULL);
-
-s = qtest_start("-display none -machine imx25-pdk");
-i2c = imx_i2c_create(s, IMX25_I2C_0_BASE);
-addr = DS1338_ADDR;
-
-qtest_add_func("/ds1338/tx-rx", send_and_receive);
-
-ret = g_test_run();
-
-qtest_quit(s);
-g_free(i2c);
-
-return ret;
-}
-- 
2.11.0




[Qemu-devel] [PATCH 1/5] timer: ds1338 add magic reset for test code

2018-02-18 Thread Michael Davidsaver
When running w/ QTest, allow the tester
to reliably zero time offsets.
Allows tests to read the current time,
and set time, independent of test order.

Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 hw/timer/ds1338.c | 9 +
 1 file changed, 9 insertions(+)

diff --git a/hw/timer/ds1338.c b/hw/timer/ds1338.c
index 3849b74a68..41c2d7dac6 100644
--- a/hw/timer/ds1338.c
+++ b/hw/timer/ds1338.c
@@ -14,6 +14,7 @@
 #include "qemu-common.h"
 #include "hw/i2c/i2c.h"
 #include "qemu/bcd.h"
+#include "sysemu/qtest.h"
 
 /* Size of NVRAM including both the user-accessible area and the
  * secondary register area.
@@ -132,6 +133,14 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
 DS1338State *s = DS1338(i2c);
 
 if (s->addr_byte) {
+if (data == 0xff && qtest_enabled()) {
+/* magic, out of bounds, address to allow test code
+ * to reset offset
+ */
+s->offset = 0;
+s->wday_offset = 0;
+return 0;
+}
 s->ptr = data & (NVRAM_SIZE - 1);
 s->addr_byte = false;
 return 0;
-- 
2.11.0




[Qemu-devel] [PATCH 2/5] tests: more thorough test of ds1338

2018-02-18 Thread Michael Davidsaver
Test current time and set+get round trip.

The set+get test is repeated 4 times.  These cases are
spread across a single day in an attempt to trigger some potential
issues regardless of the timezone of the machine running the tests.

Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 tests/Makefile.include  |   2 +
 tests/ds-rtc-i2c-test.c | 193 
 2 files changed, 195 insertions(+)
 create mode 100644 tests/ds-rtc-i2c-test.c

diff --git a/tests/Makefile.include b/tests/Makefile.include
index a1bcbffe12..f5dcd274e0 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -360,6 +360,7 @@ check-qtest-sparc64-y += tests/boot-serial-test$(EXESUF)
 
 check-qtest-arm-y = tests/tmp105-test$(EXESUF)
 check-qtest-arm-y += tests/ds1338-test$(EXESUF)
+check-qtest-arm-y += tests/ds-rtc-i2c-test$(EXESUF)
 check-qtest-arm-y += tests/m25p80-test$(EXESUF)
 gcov-files-arm-y += hw/misc/tmp105.c
 check-qtest-arm-y += tests/virtio-blk-test$(EXESUF)
@@ -764,6 +765,7 @@ tests/bios-tables-test$(EXESUF): tests/bios-tables-test.o \
 tests/pxe-test$(EXESUF): tests/pxe-test.o tests/boot-sector.o $(libqos-obj-y)
 tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y)
 tests/ds1338-test$(EXESUF): tests/ds1338-test.o $(libqos-imx-obj-y)
+tests/ds-rtc-i2c-test$(EXESUF): tests/ds-rtc-i2c-test.o $(libqos-imx-obj-y)
 tests/m25p80-test$(EXESUF): tests/m25p80-test.o
 tests/i440fx-test$(EXESUF): tests/i440fx-test.o $(libqos-pc-obj-y)
 tests/q35-test$(EXESUF): tests/q35-test.o $(libqos-pc-obj-y)
diff --git a/tests/ds-rtc-i2c-test.c b/tests/ds-rtc-i2c-test.c
new file mode 100644
index 00..464eb08558
--- /dev/null
+++ b/tests/ds-rtc-i2c-test.c
@@ -0,0 +1,193 @@
+/* Testing of Dallas/Maxim I2C bus RTC devices
+ *
+ * Copyright (c) 2017 Michael Davidsaver
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the LICENSE file in the top-level directory.
+ */
+#include 
+
+#include "qemu/osdep.h"
+#include "qemu/bcd.h"
+#include "qemu/cutils.h"
+#include "qemu/timer.h"
+#include "libqtest.h"
+#include "libqos/libqos.h"
+#include "libqos/i2c.h"
+
+#define IMX25_I2C_0_BASE 0x43F8
+#define DS1338_ADDR 0x68
+
+static I2CAdapter *i2c;
+static uint8_t addr;
+static bool use_century;
+
+static
+time_t rtc_gettime(void)
+{
+struct tm parts;
+uint8_t buf[7];
+
+buf[0] = 0;
+i2c_send(i2c, addr, buf, 1);
+i2c_recv(i2c, addr, buf, 7);
+
+parts.tm_sec = from_bcd(buf[0]);
+parts.tm_min = from_bcd(buf[1]);
+if (buf[2] & 0x40) {
+/* 12 hour */
+/* HOUR register is 1-12. */
+parts.tm_hour = from_bcd(buf[2] & 0x1f);
+g_assert_cmpuint(parts.tm_hour, >=, 1);
+g_assert_cmpuint(parts.tm_hour, <=, 12);
+parts.tm_hour %= 12u; /* wrap 12 -> 0 */
+if (buf[2] & 0x20) {
+parts.tm_hour += 12u;
+}
+} else {
+/* 24 hour */
+parts.tm_hour = from_bcd(buf[2] & 0x3f);
+}
+parts.tm_wday = from_bcd(buf[3]);
+parts.tm_mday = from_bcd(buf[4]);
+parts.tm_mon =  from_bcd((buf[5] & 0x1f) - 1u);
+parts.tm_year = from_bcd(buf[6]);
+if (!use_century || (buf[5] & 0x80)) {
+parts.tm_year += 100u;
+}
+
+return mktimegm();
+}
+
+/* read back and compare with current system time */
+static
+void test_rtc_current(void)
+{
+uint8_t buf;
+time_t expected, actual;
+
+/* magic address to zero RTC time offset
+ * as tests may be run in any order
+ */
+buf = 0xff;
+i2c_send(i2c, addr, , 1);
+
+actual = time(NULL);
+/* new second may start here */
+expected = rtc_gettime();
+g_assert_cmpuint(expected, <=, actual + 1);
+g_assert_cmpuint(expected, >=, actual);
+}
+
+
+static uint8_t test_time_24_12am[8] = {
+0, /* address */
+/* Wed, 22 Nov 2017 00:30:53 + */
+0x53,
+0x30,
+0x00, /* 12 AM in 24 hour mode */
+0x03, /* monday is our day 1 */
+0x22,
+0x11 | 0x80,
+0x17,
+};
+
+static uint8_t test_time_24_6am[8] = {
+0, /* address */
+/* Wed, 22 Nov 2017 06:30:53 + */
+0x53,
+0x30,
+0x06, /* 6 AM in 24 hour mode */
+0x03, /* monday is our day 1 */
+0x22,
+0x11 | 0x80,
+0x17,
+};
+
+static uint8_t test_time_24_12pm[8] = {
+0, /* address */
+/* Wed, 22 Nov 2017 12:30:53 + */
+0x53,
+0x30,
+0x12, /* 12 PM in 24 hour mode */
+0x03, /* monday is our day 1 */
+0x22,
+0x11 | 0x80,
+0x17,
+};
+
+static uint8_t test_time_24_6pm[8] = {
+0, /* address */
+/* Wed, 22 Nov 2017 18:30:53 + */
+0x53,
+0x30,
+0x18, /* 6 PM in 24 hour mode */
+0x03, /* monday is our day 1 */
+0x22,
+0x11 | 0x80,
+0x17,
+};
+
+/* write in and read back known time */
+static
+void test_rtc_set(const void *raw)
+{
+const uint8_t *testti

[Qemu-devel] [PATCH 0/5] Generalize Dallas/Maxim I2C RTC devices

2018-02-18 Thread Michael Davidsaver
These changes previously appeared as part of a series "Add MVME3100 PPC SBC v2"
back in November.  David Gibson, who looked that that series, suggested getting
this reviewed separately.  There doesn't appear to be a listed maintainer
for this code, so I'm addressing this to the 3 people who have made more than
cosmetic changes to it.  The most recent of these was in 2012.

This series replaces the ds1338 RTC with a model covering a number of these
similar chips: ds1307, ds1337, ds1338, ds1339, ds1340, ds1375, ds1388,
and ds3231.

The limits of the new model are the same as the old.  Only the time of day
registers, and NVRAM are modeled.  The alarm and control registers are not.

I've added a more thorough test of the time of day function, covering
reading and setting in both 12 and 24 hour mode.  In the process
I found two minor issues with the ds1338 model.  These are described in the
commit message for #3.  So this series first adds those tests which pass with
both old and new model.  Then later adds some additional tests which only
pass with the new model.


Michael Davidsaver (5):
  timer: ds1338 add magic reset for test code
  tests: more thorough test of ds1338
  timer: generalize Dallas/Maxim RTC i2c devices
  tests: ds-rtc-i2c-test test 12 hour mode and DoW
  tests: drop ds1338-test

 default-configs/arm-softmmu.mak |   2 +-
 hw/timer/Makefile.objs  |   2 +-
 hw/timer/ds-rtc-i2c.c   | 466 
 hw/timer/ds1338.c   | 239 -
 tests/Makefile.include  |   4 +-
 tests/ds-rtc-i2c-test.c | 245 +
 tests/ds1338-test.c |  75 ---
 7 files changed, 715 insertions(+), 318 deletions(-)
 create mode 100644 hw/timer/ds-rtc-i2c.c
 delete mode 100644 hw/timer/ds1338.c
 create mode 100644 tests/ds-rtc-i2c-test.c
 delete mode 100644 tests/ds1338-test.c

-- 
2.11.0




[Qemu-devel] [PATCH 4/5] tests: ds-rtc-i2c-test test 12 hour mode and DoW

2018-02-18 Thread Michael Davidsaver
Test time set+get in 12 hour mode.
Also test handling of day of week
offset.

Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 tests/ds-rtc-i2c-test.c | 54 -
 1 file changed, 53 insertions(+), 1 deletion(-)

diff --git a/tests/ds-rtc-i2c-test.c b/tests/ds-rtc-i2c-test.c
index 464eb08558..226ac1399e 100644
--- a/tests/ds-rtc-i2c-test.c
+++ b/tests/ds-rtc-i2c-test.c
@@ -92,6 +92,18 @@ static uint8_t test_time_24_12am[8] = {
 0x17,
 };
 
+static uint8_t test_time_12_12am[8] = {
+0, /* address */
+/* Wed, 22 Nov 2017 00:30:53 + */
+0x53,
+0x30,
+0x52, /* 12 AM in 12 hour mode */
+0x03, /* monday is our day 1 */
+0x22,
+0x11 | 0x80,
+0x17,
+};
+
 static uint8_t test_time_24_6am[8] = {
 0, /* address */
 /* Wed, 22 Nov 2017 06:30:53 + */
@@ -104,6 +116,18 @@ static uint8_t test_time_24_6am[8] = {
 0x17,
 };
 
+static uint8_t test_time_12_6am[8] = {
+0, /* address */
+/* Wed, 22 Nov 2017 06:30:53 + */
+0x53,
+0x30,
+0x46, /* 6 AM in 12 hour mode */
+0x03, /* monday is our day 1 */
+0x22,
+0x11 | 0x80,
+0x17,
+};
+
 static uint8_t test_time_24_12pm[8] = {
 0, /* address */
 /* Wed, 22 Nov 2017 12:30:53 + */
@@ -116,6 +140,18 @@ static uint8_t test_time_24_12pm[8] = {
 0x17,
 };
 
+static uint8_t test_time_12_12pm[8] = {
+0, /* address */
+/* Wed, 22 Nov 2017 12:30:53 + */
+0x53,
+0x30,
+0x72, /* 12 PM in 24 hour mode */
+0x03, /* monday is our day 1 */
+0x22,
+0x11 | 0x80,
+0x17,
+};
+
 static uint8_t test_time_24_6pm[8] = {
 0, /* address */
 /* Wed, 22 Nov 2017 18:30:53 + */
@@ -128,6 +164,18 @@ static uint8_t test_time_24_6pm[8] = {
 0x17,
 };
 
+static uint8_t test_time_12_6pm[8] = {
+0, /* address */
+/* Wed, 22 Nov 2017 18:30:53 + */
+0x53,
+0x30,
+0x66, /* 6 PM in 12 hour mode */
+0x03, /* monday is our day 1 */
+0x22,
+0x11 | 0x80,
+0x17,
+};
+
 /* write in and read back known time */
 static
 void test_rtc_set(const void *raw)
@@ -151,7 +199,7 @@ void test_rtc_set(const void *raw)
 g_assert_cmpuint(testtime[1], ==, buf[0]); /* SEC */
 g_assert_cmpuint(testtime[2], ==, buf[1]); /* MIN */
 g_assert_cmpuint(testtime[3], ==, buf[2]); /* HOUR */
-/* skip comparing Day of Week.  Not handled correctly */
+g_assert_cmpuint(testtime[4], ==, buf[3]); /* DoW */
 g_assert_cmpuint(testtime[5], ==, buf[4]); /* DoM */
 if (use_century) {
 g_assert_cmpuint(testtime[6], ==, buf[5]); /* MON+century */
@@ -183,6 +231,10 @@ int main(int argc, char *argv[])
 qtest_add_data_func("/ds-rtc-i2c/set24_6am", test_time_24_6am, 
test_rtc_set);
 qtest_add_data_func("/ds-rtc-i2c/set24_12pm", test_time_24_12pm, 
test_rtc_set);
 qtest_add_data_func("/ds-rtc-i2c/set24_6pm", test_time_24_6pm, 
test_rtc_set);
+qtest_add_data_func("/ds-rtc-i2c/set12_12am", test_time_12_12am, 
test_rtc_set);
+qtest_add_data_func("/ds-rtc-i2c/set12_6am", test_time_12_6am, 
test_rtc_set);
+qtest_add_data_func("/ds-rtc-i2c/set12_12pm", test_time_12_12pm, 
test_rtc_set);
+qtest_add_data_func("/ds-rtc-i2c/set12_6pm", test_time_12_6pm, 
test_rtc_set);
 qtest_add_func("/ds-rtc-i2c/current", test_rtc_current);
 
 ret = g_test_run();
-- 
2.11.0




Re: [Qemu-devel] [PATCH 05/17] timer: generalize Dallas/Maxim RTC i2c devices

2017-12-27 Thread Michael Davidsaver
On 12/06/2017 05:14 AM, David Gibson wrote:
> On Sun, Dec 03, 2017 at 03:15:10PM -0600, Michael Davidsaver wrote:
>> On 11/29/2017 11:13 PM, David Gibson wrote:
>>> On Sun, Nov 26, 2017 at 03:59:03PM -0600, Michael Davidsaver wrote:
>>>> Support for: ds1307, ds1337, ds1338, ds1339,
>>>> ds1340, ds1375, ds1388, and ds3231.
>>>>
>>>> Tested with ds1338 and ds1375.
>>>>
>>>> Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
>>>
>>> I certainly like the idea of consolidating this code, but reviewing to
>>> see that the new code really is a generalization of the old is
>>> something I won't have time for for a while.
>>>
>>> Also, hw/timer is not within my purview so it'll probably need to go
>>> another path to merge.
>>
>> Could you be a bit more explicit about what, if anything, I need to do
>> to move this forward?
> 
> Ugh.. that's pretty tough, since ds1338 doesn't have an activate
> maintainer.  You can look at the git history for some possible
> candidates of people to ask about it, but it hasn't been touched much
> in quite a while.
> 
> One approach that could help is to re-order so that your testing
> rework goes before the change to ds1338.  If your new generalization
> can pass the same set of tests as the original ds1338 code, that's at
> least a good start on being convincing that it's a true superset of
> the previous functionality.

A slight wrinkle is that my testing found two bugs with the original
ds1338 model (also one in my new code).  The two don't seem
significant practically.  It actually isn't possible to switch to
12-hour mode.  And there is an obscure off by one situation possible
with wday_offset and timezones.  Of course most guests use 24-hour mode
and ignore the RTC day-of-week.

The upshot of this is that several test cases now fail when run against 
ds1338.c.

My recommendation would be to start by looking at the test code.
This could be compared against guest code.  When I send the next
iteration I'll include some links.

> The other approach is to do the rework in a rather longer series of
> patches.  Start by simply moving ds1338.c, then do a mechanical
> replacement of the names within it, then start generalizing and
> altering.  That's a lot of work for you, but it makes it much easier
> to review each step

I know from my first foray into QEMU land that this is preferable for review.
Unfortunately, I expanded from my previous ds1375 model instead of the ds1338.



signature.asc
Description: OpenPGP digital signature


Re: [Qemu-devel] [PATCH 13/17] e500: move PCI host bridge into CCSR

2017-12-26 Thread Michael Davidsaver
On 12/06/2017 05:11 AM, David Gibson wrote:
> On Tue, Dec 05, 2017 at 10:42:25PM -0500, Michael Davidsaver wrote:
>> On 12/05/2017 01:53 AM, David Gibson wrote:
>>> On Sun, Nov 26, 2017 at 03:59:11PM -0600, Michael Davidsaver wrote:
>>>> Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
>>>
>>> Hmm.  Is there anything you're *not* planning to move under the CCSR.
>>
>> Well, the decrementer/timebase initialization for one as this has
>> nothing to do with the CCSR registers.
> 
> Right, but no actual devices, even small ones?

Well, there is the GPIO controller ("mpc8xxx_gpio") as I have frankly
have no idea where it comes from.  Neither MPC8540 nor 8544 define
anything at CCSR offset 0xFF000.  The registers modeled differ
from the GPIO controller which is defined at 0xE0030.

So I'm considering this to be specific to the existing boards.

>> I haven't added the TSEC/eTSEC instances either.
>> Partly this is because the existing boards, for reasons I don't understand,
>> use virtio NICs.
>>
>> Further, the mpc8540 has TSEC instances 1 and 2, while the mpc8544
>> has instances 1 and 3.  So I decided to leave NIC setup to the Machine
>> rather then add the extra code to parameterize this under the CCSR device.
>>
>>> If not, I'm really wondering if the CCSR ought to be a device in its
>>> own right, rather than just a container memory region used within the
>>> machine.
>>
>> I don't think I follow what you mean by "device" in this context?
>> The CCSR object is a SysBusDevice in the qom tree ("/machine/e500-ccsr").
>> What device-like characteristics could it have?
> 
> Sorry, I wasn't clear.  the CCSR definitely *is* a device in the
> current scheme, but I'm wondering if that was a good idea.

I think I see what you're getting at.  You're right that CCSR
isn't a "device" in the same sense as eg. a UART.  In my mind
it's more like a PCI host bridge, having a few registers itself,
though serving mainly to route to the devices behind it.

I see the CCSR "device" as the bridge onto the system bus.
In some ways it might be considered to be the only device
on the system bus apart from the CPU(s).  This "device"
handles first level routing of physical addresses to
RAM, PCI, or local bus via the LAWBAR* registers (unmodeled).
Or to the I/O devices in the CCSR range via CCSRBAR.

I don't have plans to model that LAWBAR* registers,
as it hasn't proved necessary for RTEMS or Linux guests.
I have considered how this could be done as Linux does
touch these registers, but doesn't readback/check the
values it has written.  I think having a CCSR "device"
would make it simpler to model the local windows
should this become desirable.  eg. if Linux starts
validating LAWBAR* or to run unmodified u-boot.



signature.asc
Description: OpenPGP digital signature


Re: [Qemu-devel] [PATCH 13/17] e500: move PCI host bridge into CCSR

2017-12-05 Thread Michael Davidsaver
On 12/05/2017 01:53 AM, David Gibson wrote:
> On Sun, Nov 26, 2017 at 03:59:11PM -0600, Michael Davidsaver wrote:
>> Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
> 
> Hmm.  Is there anything you're *not* planning to move under the CCSR.

Well, the decrementer/timebase initialization for one as this has
nothing to do with the CCSR registers.

I haven't added the TSEC/eTSEC instances either.
Partly this is because the existing boards, for reasons I don't understand,
use virtio NICs.

Further, the mpc8540 has TSEC instances 1 and 2, while the mpc8544
has instances 1 and 3.  So I decided to leave NIC setup to the Machine
rather then add the extra code to parameterize this under the CCSR device.

> If not, I'm really wondering if the CCSR ought to be a device in its
> own right, rather than just a container memory region used within the
> machine.

I don't think I follow what you mean by "device" in this context?
The CCSR object is a SysBusDevice in the qom tree ("/machine/e500-ccsr").
What device-like characteristics could it have?


>> ---
>>  hw/ppc/e500.c  | 13 -
>>  hw/ppc/e500_ccsr.c | 27 +++
>>  2 files changed, 31 insertions(+), 9 deletions(-)
>>
>> diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
>> index cfd5ed0152..b0c8495aef 100644
>> --- a/hw/ppc/e500.c
>> +++ b/hw/ppc/e500.c
>> @@ -769,6 +769,8 @@ void ppce500_init(MachineState *machine, PPCE500Params 
>> *params)
>>  qdev_prop_set_uint32(dev, "mpic-model", params->mpic_version);
>>  qdev_prop_set_uint32(dev, "base", params->ccsrbar_base);
>>  qdev_prop_set_uint32(dev, "ram-size", ram_size);
>> +qdev_prop_set_uint32(dev, "pci_first_slot", params->pci_first_slot);
>> +qdev_prop_set_uint32(dev, "pci_first_pin_irq", pci_irq_nrs[0]);
>>  qdev_init_nofail(dev);
>>  ccsr_addr_space = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
>>  
>> @@ -778,20 +780,13 @@ void ppce500_init(MachineState *machine, PPCE500Params 
>> *params)
>>  
>>  
>>  /* PCI */
>> -dev = qdev_create(NULL, "e500-pcihost");
>> -object_property_add_child(qdev_get_machine(), "pci-host", OBJECT(dev),
>> -  _abort);
>> -qdev_prop_set_uint32(dev, "first_slot", params->pci_first_slot);
>> -qdev_prop_set_uint32(dev, "first_pin_irq", pci_irq_nrs[0]);
>> -qdev_init_nofail(dev);
>> +dev = DEVICE(object_resolve_path("/machine/pci-host", 0));
>> +assert(dev);
>>  s = SYS_BUS_DEVICE(dev);
>>  for (i = 0; i < PCI_NUM_PINS; i++) {
>>  sysbus_connect_irq(s, i, qdev_get_gpio_in(mpicdev, pci_irq_nrs[i]));
>>  }
>>  
>> -memory_region_add_subregion(ccsr_addr_space, MPC8544_PCI_REGS_OFFSET,
>> -sysbus_mmio_get_region(s, 0));
>> -
>>  pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
>>  if (!pci_bus)
>>  printf("couldn't create PCI controller!\n");
>> diff --git a/hw/ppc/e500_ccsr.c b/hw/ppc/e500_ccsr.c
>> index cd8216daaf..4ec8f7524d 100644
>> --- a/hw/ppc/e500_ccsr.c
>> +++ b/hw/ppc/e500_ccsr.c
>> @@ -50,6 +50,8 @@
>>  
>>  #define E500_DUART_OFFSET(N) (0x4500 + (N) * 0x100)
>>  
>> +#define E500_PCI_OFFSET  (0x8000ULL)
>> +
>>  #define E500_PORPLLSR(0xE)
>>  #define E500_PVR (0xE00A0)
>>  #define E500_SVR (0xE00A4)
>> @@ -75,6 +77,7 @@ typedef struct {
>>  
>>  DeviceState *pic;
>>  DeviceState *i2c;
>> +DeviceState *pcihost;
>>  } CCSRState;
>>  
>>  #define TYPE_E500_CCSR "e500-ccsr"
>> @@ -201,6 +204,7 @@ static void e500_ccsr_init(Object *obj)
>>  DeviceState *dev = DEVICE(obj);
>>  CCSRState *ccsr = E500_CCSR(dev);
>>  
>> +/* prepare MPIC */
>>  assert(current_machine);
>>  if (kvm_enabled()) {
>>  
>> @@ -228,6 +232,18 @@ static void e500_ccsr_init(Object *obj)
>>  object_property_add_alias(obj, "mpic-model",
>>OBJECT(ccsr->pic), "model",
>>_fatal);
>> +
>> +/* prepare PCI host bridge */
>> +ccsr->pcihost = qdev_create(NULL, "e500-pcihost");
>> +object_property_add_child(qdev_get_machine(), "pci-host", 
>> OBJECT(ccsr->pcihost),
>> +  _abort);
>> +
>> +object_property_add_alias(

Re: [Qemu-devel] [PATCH 12/17] e500: add i2c controller to CCSR

2017-12-05 Thread Michael Davidsaver
On 12/05/2017 01:49 AM, David Gibson wrote:
> On Sun, Nov 26, 2017 at 03:59:10PM -0600, Michael Davidsaver wrote:
>> Add i2c controller found on mpc8540,
>> mpc8544, and P2010 (newer ppc, unmodeled).
> 
> This adds it unconditionally.  Are there any E500 models where it
> doesn't exist?

Not in the devices I've looked at, though I certainly haven't looked
at them all.  In fact the mpc8544 has two i2c controllers.

I keep mentioning the P2010 as it is about a decade
newer than the mpc85xx chips.  My _assumption_ is that the commonalities
between these are a reasonable least common denominator.


>>
>> Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
>> ---
>>  hw/ppc/e500_ccsr.c | 15 +++
>>  1 file changed, 15 insertions(+)
>>
>> diff --git a/hw/ppc/e500_ccsr.c b/hw/ppc/e500_ccsr.c
>> index c479ed91ee..cd8216daaf 100644
>> --- a/hw/ppc/e500_ccsr.c
>> +++ b/hw/ppc/e500_ccsr.c
>> @@ -46,6 +46,8 @@
>>  #define E500_ERR_DETECT  (0x2e40)
>>  #define E500_ERR_DISABLE (0x2e44)
>>  
>> +#define E500_I2C_OFFSET  (0x3000)
>> +
>>  #define E500_DUART_OFFSET(N) (0x4500 + (N) * 0x100)
>>  
>>  #define E500_PORPLLSR(0xE)
>> @@ -72,6 +74,7 @@ typedef struct {
>>  uint32_t ccb_freq;
>>  
>>  DeviceState *pic;
>> +DeviceState *i2c;
>>  } CCSRState;
>>  
>>  #define TYPE_E500_CCSR "e500-ccsr"
>> @@ -272,6 +275,18 @@ static void e500_ccsr_realize(DeviceState *dev, Error 
>> **errp)
>>  sysbus_mmio_get_region(pic, 0));
>>  /* Note: MPIC internal interrupts are offset by 16 */
>>  
>> +/* attach I2C controller */
>> +ccsr->i2c = qdev_create(NULL, "mpc8540-i2c");
> 
> Ah.. so I think I missed this on many earlier patches.  I believe
> you're not generally supposed to create new subdevices at realize()
> time.  Instead the device should be created at CCSR instance_init()
> time (but the sub device's "realized" property will need to be set to
> 1 from CCSR realize()).
> 
>> +object_property_add_child(qdev_get_machine(), "i2c[*]",
>> +  OBJECT(ccsr->i2c), NULL);
>> +qdev_init_nofail(ccsr->i2c);
>> +memory_region_add_subregion(>iomem, E500_I2C_OFFSET,
>> +sysbus_mmio_get_region(
>> +SYS_BUS_DEVICE(ccsr->i2c), 0));
>> +sysbus_connect_irq(SYS_BUS_DEVICE(ccsr->i2c), 0,
>> +  qdev_get_gpio_in(ccsr->pic, 16 + 27));
>> +
>> +
>>  /* DUARTS */
>>  /* for mpc8540, mpc8544, and P2010 (unmodeled), the DUART reference 
>> clock
>>   * is the CCB clock divided by 16.
> 




signature.asc
Description: OpenPGP digital signature


Re: [Qemu-devel] [PATCH 02/12] e500: consolidate mpc8540 guts with e500-ccsr

2017-12-05 Thread Michael Davidsaver
On 12/05/2017 10:12 PM, David Gibson wrote:
> On Wed, Nov 22, 2017 at 02:36:43PM +1100, David Gibson wrote:
>> On Sun, Nov 19, 2017 at 09:24:10PM -0600, Michael Davidsaver wrote:
>>> Preparation for adding more MPC control
>>> registers.
>>>
>>> Use e500 SVR to enable part specific registers.
>>> Only the mpc8544 reset register at present.
>>>
>>> Expose CCSR as SysBusDevice region to eliminate
>>> e500-ccsr.h.
>>>
>>> Track CCSR base address within device, and map on reset,
>>> in preparation for CCSRBAR.
>>>
>>> Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
>>
>> Applied to ppc-for-2.12.
> 
> Sorry.  I've now pulled this from ppc-for-2.12, because it caused a
> breakage of make check (specifically the boot-serial-test with ppc64).

Oops, I'll begin running this test myself.  So far I've only been running
tests for i386, amd64, arm, and ppc.



Re: [Qemu-devel] [PATCH 05/17] timer: generalize Dallas/Maxim RTC i2c devices

2017-12-03 Thread Michael Davidsaver
On 11/29/2017 11:13 PM, David Gibson wrote:
> On Sun, Nov 26, 2017 at 03:59:03PM -0600, Michael Davidsaver wrote:
>> Support for: ds1307, ds1337, ds1338, ds1339,
>> ds1340, ds1375, ds1388, and ds3231.
>>
>> Tested with ds1338 and ds1375.
>>
>> Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
> 
> I certainly like the idea of consolidating this code, but reviewing to
> see that the new code really is a generalization of the old is
> something I won't have time for for a while.
> 
> Also, hw/timer is not within my purview so it'll probably need to go
> another path to merge.

Could you be a bit more explicit about what, if anything, I need to do
to move this forward?


>> ---
>>  default-configs/arm-softmmu.mak |   2 +-
>>  hw/timer/Makefile.objs  |   2 +-
>>  hw/timer/ds-rtc-i2c.c   | 461 
>> 
>>  hw/timer/ds1338.c   | 239 -
>>  4 files changed, 463 insertions(+), 241 deletions(-)
>>  create mode 100644 hw/timer/ds-rtc-i2c.c
>>  delete mode 100644 hw/timer/ds1338.c
>>
>> diff --git a/default-configs/arm-softmmu.mak 
>> b/default-configs/arm-softmmu.mak
>> index d37edc4312..b857823681 100644
>> --- a/default-configs/arm-softmmu.mak
>> +++ b/default-configs/arm-softmmu.mak
>> @@ -31,7 +31,7 @@ CONFIG_SMC91C111=y
>>  CONFIG_ALLWINNER_EMAC=y
>>  CONFIG_IMX_FEC=y
>>  CONFIG_FTGMAC100=y
>> -CONFIG_DS1338=y
>> +CONFIG_DSRTCI2C=y
>>  CONFIG_PFLASH_CFI01=y
>>  CONFIG_PFLASH_CFI02=y
>>  CONFIG_MICRODRIVE=y
>> diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs
>> index 8c19eac3b6..290015ebec 100644
>> --- a/hw/timer/Makefile.objs
>> +++ b/hw/timer/Makefile.objs
>> @@ -3,7 +3,7 @@ common-obj-$(CONFIG_ARM_MPTIMER) += arm_mptimer.o
>>  common-obj-$(CONFIG_ARM_V7M) += armv7m_systick.o
>>  common-obj-$(CONFIG_A9_GTIMER) += a9gtimer.o
>>  common-obj-$(CONFIG_CADENCE) += cadence_ttc.o
>> -common-obj-$(CONFIG_DS1338) += ds1338.o
>> +common-obj-$(CONFIG_DSRTCI2C) += ds-rtc-i2c.o
>>  common-obj-$(CONFIG_HPET) += hpet.o
>>  common-obj-$(CONFIG_I8254) += i8254_common.o i8254.o
>>  common-obj-$(CONFIG_M48T59) += m48t59.o
>> diff --git a/hw/timer/ds-rtc-i2c.c b/hw/timer/ds-rtc-i2c.c
>> new file mode 100644
>> index 00..ad2f8f2a68
>> --- /dev/null
>> +++ b/hw/timer/ds-rtc-i2c.c
>> @@ -0,0 +1,461 @@
>> +/* Emulation of various Dallas/Maxim RTCs accessed via I2C bus
>> + *
>> + * Copyright (c) 2017 Michael Davidsaver
>> + * Copyright (c) 2009 CodeSourcery
>> + *
>> + * Authors: Michael Davidsaver
>> + *  Paul Brook
>> + *
>> + * This work is licensed under the terms of the GNU GPL, version 2.  See
>> + * the LICENSE file in the top-level directory.
>> + *
>> + * Models real time read/set and NVRAM.
>> + * Does not model alarms, or control/status registers.
>> + *
>> + * Generalized register map is:
>> + *   [Current time]
>> + *   [Alarm settings] (optional)
>> + *   [Control/Status] (optional)
>> + *   [Non-volatile memory] (optional)
>> + *
>> + * The current time registers are almost always the same,
>> + * with the exception being that some have a CENTURY bit
>> + * in the month register.
>> + */
>> +#include "qemu/osdep.h"
>> +#include "qemu/log.h"
>> +#include "qemu/timer.h"
>> +#include "qemu/bcd.h"
>> +#include "hw/hw.h"
>> +#include "hw/registerfields.h"
>> +#include "hw/i2c/i2c.h"
>> +#include "sysemu/qtest.h"
>> +#include "qemu/error-report.h"
>> +
>> +/* #define DEBUG_DSRTC */
>> +
>> +#ifdef DEBUG_DSRTC
>> +#define DPRINTK(FMT, ...) info_report(TYPE_DSRTC " : " FMT, ## __VA_ARGS__)
>> +#else
>> +#define DPRINTK(FMT, ...) do {} while (0)
>> +#endif
>> +
>> +#define LOG(MSK, FMT, ...) qemu_log_mask(MSK, TYPE_DSRTC " : " FMT "\n", \
>> +## __VA_ARGS__)
>> +
>> +#define DSRTC_REGSIZE (0x40)
>> +
>> +/* values stored in BCD */
>> +/* 00-59 */
>> +#define R_SEC   (0x0)
>> +/* 00-59 */
>> +#define R_MIN   (0x1)
>> +#define R_HOUR  (0x2)
>> +/* 1-7 */
>> +#define R_WDAY  (0x3)
>> +/* 0-31 */
>> +#define R_DATE  (0x4)
>> +#define R_MONTH (0x5)
>> +/* 0-99 */
>> +#define R_YEAR  (0x6)
>> +
>> +/* use 12 hour mode when set */
>> +FIELD(HOUR, SET12, 6, 1)
>> +/*

[Qemu-devel] [PATCH] etsec: fix IRQ (un)masking

2017-11-27 Thread Michael Davidsaver
Interrupt conditions occurring while masked are not being
signaled when later unmasked.
The fix is to raise/lower IRQs when IMASK is changed.

To avoid problems like this in future, consolidate
IRQ pin update logic in one function.

Also fix probable typo "IEVENT_TXF | IEVENT_TXF",
and update IRQ pins on reset.

Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 hw/net/fsl_etsec/etsec.c | 68 +++-
 hw/net/fsl_etsec/etsec.h |  2 ++
 hw/net/fsl_etsec/registers.h | 10 +++
 hw/net/fsl_etsec/rings.c | 12 +---
 4 files changed, 49 insertions(+), 43 deletions(-)

diff --git a/hw/net/fsl_etsec/etsec.c b/hw/net/fsl_etsec/etsec.c
index 9da1932970..0b66274ce3 100644
--- a/hw/net/fsl_etsec/etsec.c
+++ b/hw/net/fsl_etsec/etsec.c
@@ -49,6 +49,28 @@ static const int debug_etsec;
 }  \
 } while (0)
 
+/* call after any change to IEVENT or IMASK */
+void etsec_update_irq(eTSEC *etsec)
+{
+uint32_t ievent = etsec->regs[IEVENT].value;
+uint32_t imask  = etsec->regs[IMASK].value;
+uint32_t active = ievent & imask;
+
+int tx  = !!(active & IEVENT_TX_MASK);
+int rx  = !!(active & IEVENT_RX_MASK);
+int err = !!(active & IEVENT_ERR_MASK);
+
+DPRINTF("%s IRQ ievent=%"PRIx32" imask=%"PRIx32" %c%c%c\n",
+__func__, ievent, imask,
+tx  ? 'T' : '_',
+rx  ? 'R' : '_',
+err ? 'E' : '_');
+
+qemu_set_irq(etsec->tx_irq, tx);
+qemu_set_irq(etsec->rx_irq, rx);
+qemu_set_irq(etsec->err_irq, err);
+}
+
 static uint64_t etsec_read(void *opaque, hwaddr addr, unsigned size)
 {
 eTSEC  *etsec = opaque;
@@ -139,31 +161,6 @@ static void write_rbasex(eTSEC  *etsec,
 etsec->regs[RBPTR0 + (reg_index - RBASE0)].value = value & ~0x7;
 }
 
-static void write_ievent(eTSEC  *etsec,
- eTSEC_Register *reg,
- uint32_treg_index,
- uint32_tvalue)
-{
-/* Write 1 to clear */
-reg->value &= ~value;
-
-if (!(reg->value & (IEVENT_TXF | IEVENT_TXF))) {
-qemu_irq_lower(etsec->tx_irq);
-}
-if (!(reg->value & (IEVENT_RXF | IEVENT_RXF))) {
-qemu_irq_lower(etsec->rx_irq);
-}
-
-if (!(reg->value & (IEVENT_MAG | IEVENT_GTSC | IEVENT_GRSC | IEVENT_TXC |
-IEVENT_RXC | IEVENT_BABR | IEVENT_BABT | IEVENT_LC |
-IEVENT_CRL | IEVENT_FGPI | IEVENT_FIR | IEVENT_FIQ |
-IEVENT_DPE | IEVENT_PERR | IEVENT_EBERR | IEVENT_TXE |
-IEVENT_XFUN | IEVENT_BSY | IEVENT_MSRO | IEVENT_MMRD |
-IEVENT_MMRW))) {
-qemu_irq_lower(etsec->err_irq);
-}
-}
-
 static void write_dmactrl(eTSEC  *etsec,
   eTSEC_Register *reg,
   uint32_treg_index,
@@ -178,9 +175,7 @@ static void write_dmactrl(eTSEC  *etsec,
 } else {
 /* Graceful receive stop now */
 etsec->regs[IEVENT].value |= IEVENT_GRSC;
-if (etsec->regs[IMASK].value & IMASK_GRSCEN) {
-qemu_irq_raise(etsec->err_irq);
-}
+etsec_update_irq(etsec);
 }
 }
 
@@ -191,9 +186,7 @@ static void write_dmactrl(eTSEC  *etsec,
 } else {
 /* Graceful transmit stop now */
 etsec->regs[IEVENT].value |= IEVENT_GTSC;
-if (etsec->regs[IMASK].value & IMASK_GTSCEN) {
-qemu_irq_raise(etsec->err_irq);
-}
+etsec_update_irq(etsec);
 }
 }
 
@@ -222,7 +215,16 @@ static void etsec_write(void *opaque,
 
 switch (reg_index) {
 case IEVENT:
-write_ievent(etsec, reg, reg_index, value);
+/* Write 1 to clear */
+reg->value &= ~value;
+
+etsec_update_irq(etsec);
+break;
+
+case IMASK:
+reg->value = value;
+
+etsec_update_irq(etsec);
 break;
 
 case DMACTRL:
@@ -337,6 +339,8 @@ static void etsec_reset(DeviceState *d)
 MII_SR_EXTENDED_STATUS  | MII_SR_100T2_HD_CAPS | MII_SR_100T2_FD_CAPS |
 MII_SR_10T_HD_CAPS  | MII_SR_10T_FD_CAPS   | MII_SR_100X_HD_CAPS  |
 MII_SR_100X_FD_CAPS | MII_SR_100T4_CAPS;
+
+etsec_update_irq(etsec);
 }
 
 static ssize_t etsec_receive(NetClientState *nc,
diff --git a/hw/net/fsl_etsec/etsec.h b/hw/net/fsl_etsec/etsec.h
index 30c828e241..877988572e 100644
--- a/hw/net/fsl_etsec/etsec.h
+++ b/hw/net/fsl_etsec/etsec.h
@@ -163,6 +163,8 @@ DeviceState *etsec_create(hwaddrbase,
   qemu_irq  rx_irq,
   qemu_irq  err_irq);
 
+void etsec_update_irq(eTSEC *etsec);
+
 void etsec_

Re: [Qemu-devel] [PATCH 03/17] i2c: add mpc8540 i2c controller

2017-11-27 Thread Michael Davidsaver
On 11/27/2017 01:12 AM, David Gibson wrote:
> On Sun, Nov 26, 2017 at 03:59:01PM -0600, Michael Davidsaver wrote:
>> Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
>> ---
>>  hw/i2c/Makefile.objs |   1 +
>>  hw/i2c/mpc8540_i2c.c | 307 
>> +++
>>  hw/i2c/trace-events  |   6 +
>>  3 files changed, 314 insertions(+)
>>  create mode 100644 hw/i2c/mpc8540_i2c.c
>>
>> diff --git a/hw/i2c/Makefile.objs b/hw/i2c/Makefile.objs
>> index 0594dea3ae..79af1dd901 100644
>> --- a/hw/i2c/Makefile.objs
>> +++ b/hw/i2c/Makefile.objs
>> @@ -9,3 +9,4 @@ common-obj-$(CONFIG_IMX_I2C) += imx_i2c.o
>>  common-obj-$(CONFIG_ASPEED_SOC) += aspeed_i2c.o
>>  obj-$(CONFIG_OMAP) += omap_i2c.o
>>  obj-$(CONFIG_PPC4XX) += ppc4xx_i2c.o
>> +obj-$(CONFIG_E500) += mpc8540_i2c.o
>> diff --git a/hw/i2c/mpc8540_i2c.c b/hw/i2c/mpc8540_i2c.c
>> new file mode 100644
>> index 00..b9f5773b35
>> --- /dev/null
>> +++ b/hw/i2c/mpc8540_i2c.c
>> @@ -0,0 +1,307 @@
>> +/*
>> + * MPC8540 I2C bus interface
>> + * As described in
>> + * MPC8540 PowerQUICC III Integrated Host Processor Reference Manual, Rev. 1
>> + * Part 2 chapter 11
>> + *
>> + * Compatible I2C controllers are found on other Freescale chips
>> + * including mpc8544 and P2010.
>> + *
>> + * Copyright (c) 2015 Michael Davidsaver
>> + *
>> + * This work is licensed under the terms of the GNU GPL, version 2.  See
>> + * the LICENSE file in the top-level directory.
>> + */
>> +#include "qemu/osdep.h"
>> +#include "qemu/log.h"
>> +#include "hw/hw.h"
>> +#include "hw/registerfields.h"
>> +#include "hw/i2c/i2c.h"
>> +#include "hw/sysbus.h"
>> +#include "qemu/error-report.h"
>> +
>> +#include "trace.h"
>> +
>> +/* #define DEBUG_LVL 0 */
>> +
>> +#ifdef DEBUG_LVL
>> +#define DPRINTK(LVL, FMT, ...) do { \
>> +if ((LVL) <= DEBUG_LVL) {\
>> +info_report(TYPE_MPC8540_I2C " : " FMT, ## __VA_ARGS__); \
>> +} } while (0)
>> +#else
>> +#define DPRINTK(LVL, FMT, ...) do {} while (0)
>> +#endif
> 
> So, you have both this DPRINTK stuff, and some trace events, which
> seems a bit odd?  Why not just one or the other.

My thinking is to have trace events for the commonly used points (by me at 
least)
for troubleshooting devices on the i2c bus, but leave the others for 
troubleshooting
the i2c controller itself as DPRINTK.

So this is mainly my laziness in not seeing sufficient benefit to defining 
events for the
remaining 5 DPRINTK s.

>> +
>> +#define LOG(MSK, FMT, ...) qemu_log_mask(MSK, TYPE_MPC8540_I2C \
>> +" : " FMT "\n", ## __VA_ARGS__)
>> +
>> +#define TYPE_MPC8540_I2C "mpc8540-i2c"
>> +#define MPC8540_I2C(obj) OBJECT_CHECK(MPC8540I2CState, (obj), 
>> TYPE_MPC8540_I2C)
>> +
>> +/* offsets relative to CCSR offset 0x3000 */
>> +#define R_I2CADR (0)
>> +#define R_I2CFDR (4)
>> +#define R_I2CCR  (8)
>> +#define R_I2CSR  (0xc)
>> +#define R_I2CDR  (0x10)
>> +#define R_I2CDFSRR (0x14)
>> +
>> +FIELD(I2CCR, MEN, 7, 1)
>> +FIELD(I2CCR, MIEN, 6, 1)
>> +FIELD(I2CCR, MSTA, 5, 1)
>> +FIELD(I2CCR, MTX, 4, 1)
>> +FIELD(I2CCR, TXAK, 3, 1)
>> +FIELD(I2CCR, RSTA, 2, 1)
>> +FIELD(I2CCR, BCST, 0, 1)
>> +
>> +FIELD(I2CSR, MCF, 7, 1)
>> +FIELD(I2CSR, MAAS, 6, 1)
>> +FIELD(I2CSR, MBB, 5, 1)
>> +FIELD(I2CSR, MAL, 4, 1)
>> +FIELD(I2CSR, BCSTM, 3, 1)
>> +FIELD(I2CSR, SRW, 2, 1)
>> +FIELD(I2CSR, MIF, 1, 1)
>> +FIELD(I2CSR, RXAK, 0, 1)
>> +
>> +typedef struct MPC8540I2CState {
>> +SysBusDevice parent_obj;
>> +
>> +I2CBus *bus;
>> +
>> +uint8_t ctrl, sts;
>> +uint8_t freq, filt;
>> +/* Reads are pipelined, this is the next data value */
>> +uint8_t dbuf, dbuf_valid;
>> +
>> +qemu_irq irq;
>> +
>> +MemoryRegion mmio;
>> +} MPC8540I2CState;
>> +
>> +#define I2CCR(BIT) FIELD_EX32(i2c->ctrl, I2CCR, BIT)
>> +#define I2CSR(BIT) FIELD_EX32(i2c->sts, I2CSR, BIT)
>> +
>> +#define I2CSR_SET(BIT, VAL) do {\
>> +i2c->sts = FIELD_DP32(i2c->sts, I2CSR, BIT, VAL);\
>> +} while (0)
>> +
>> +static
>> +void mpc8540_update_irq(MPC8540I2CState *i2c)
>> +{
>> +int ena = i2c->ctrl & 0x40,
>> +sts = i2c->sts & 0x02,
>> +act = !!(ena &&am

[Qemu-devel] [PATCH 16/17] tests: run ds-rtc-i2c-test w/ ppc/mvme3100

2017-11-26 Thread Michael Davidsaver
Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 tests/Makefile.include  | 3 ++-
 tests/ds-rtc-i2c-test.c | 8 
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 56045cdf09..062d4e5b7b 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -308,6 +308,7 @@ check-qtest-ppc-y += tests/boot-order-test$(EXESUF)
 check-qtest-ppc-y += tests/prom-env-test$(EXESUF)
 check-qtest-ppc-y += tests/drive_del-test$(EXESUF)
 check-qtest-ppc-y += tests/boot-serial-test$(EXESUF)
+check-qtest-ppc-y += tests/ds-rtc-i2c-test$(EXESUF)
 
 check-qtest-ppc64-y = tests/spapr-phb-test$(EXESUF)
 gcov-files-ppc64-y = ppc64-softmmu/hw/ppc/spapr_pci.c
@@ -745,7 +746,7 @@ tests/bios-tables-test$(EXESUF): tests/bios-tables-test.o \
tests/boot-sector.o tests/acpi-utils.o $(libqos-obj-y)
 tests/pxe-test$(EXESUF): tests/pxe-test.o tests/boot-sector.o $(libqos-obj-y)
 tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y)
-tests/ds-rtc-i2c-test$(EXESUF): tests/ds-rtc-i2c-test.o $(libqos-imx-obj-y)
+tests/ds-rtc-i2c-test$(EXESUF): tests/ds-rtc-i2c-test.o $(libqos-imx-obj-y) 
$(libqos-e500-obj-y)
 tests/m25p80-test$(EXESUF): tests/m25p80-test.o
 tests/i440fx-test$(EXESUF): tests/i440fx-test.o $(libqos-pc-obj-y)
 tests/q35-test$(EXESUF): tests/q35-test.o $(libqos-pc-obj-y)
diff --git a/tests/ds-rtc-i2c-test.c b/tests/ds-rtc-i2c-test.c
index 0586dbd467..f7dab1863e 100644
--- a/tests/ds-rtc-i2c-test.c
+++ b/tests/ds-rtc-i2c-test.c
@@ -18,6 +18,9 @@
 #define IMX25_I2C_0_BASE 0x43F8
 #define DS1338_ADDR 0x68
 
+#define E500_CCSR_BASE 0xff70
+#define DS1375_ADDR 0xd0
+
 static I2CAdapter *i2c;
 static uint8_t addr;
 static bool use_century;
@@ -148,6 +151,11 @@ int main(int argc, char *argv[])
 addr = DS1338_ADDR;
 use_century = false;
 
+} else if (strcmp(arch, "ppc") == 0) {
+qtest_start("-machine mvme3100-1152");
+i2c = e500_i2c_create(E500_CCSR_BASE);
+addr = DS1375_ADDR;
+use_century = true;
 }
 
 qtest_add_data_func("/ds-rtc-i2c/set24", test_time_24, test_rtc_set);
-- 
2.11.0




[Qemu-devel] [PATCH 15/17] ppc: add mvme3100 machine

2017-11-26 Thread Michael Davidsaver
Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 default-configs/ppc-softmmu.mak |   1 +
 hw/ppc/Makefile.objs|   1 +
 hw/ppc/mvme3100.c   | 740 
 hw/ppc/mvme3100_cpld.c  | 192 +++
 4 files changed, 934 insertions(+)
 create mode 100644 hw/ppc/mvme3100.c
 create mode 100644 hw/ppc/mvme3100_cpld.c

diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak
index bb225c6e46..3777194a4a 100644
--- a/default-configs/ppc-softmmu.mak
+++ b/default-configs/ppc-softmmu.mak
@@ -52,3 +52,4 @@ CONFIG_SERIAL_ISA=y
 CONFIG_MC146818RTC=y
 CONFIG_ISA_TESTDEV=y
 CONFIG_RS6000_MC=y
+CONFIG_DSRTCI2C=y
diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs
index c1a63d0c39..c1118aaa42 100644
--- a/hw/ppc/Makefile.objs
+++ b/hw/ppc/Makefile.objs
@@ -26,5 +26,6 @@ obj-$(CONFIG_MAC) += mac_newworld.o
 obj-$(CONFIG_E500) += e500.o mpc8544ds.o e500plat.o
 obj-$(CONFIG_E500) += ppce500_spin.o
 obj-$(CONFIG_E500) += e500_ccsr.o
+obj-$(CONFIG_E500) += mvme3100.o mvme3100_cpld.o
 # PowerPC 440 Xilinx ML507 reference board.
 obj-$(CONFIG_XILINX) += virtex_ml507.o
diff --git a/hw/ppc/mvme3100.c b/hw/ppc/mvme3100.c
new file mode 100644
index 00..8eb6a3a9a4
--- /dev/null
+++ b/hw/ppc/mvme3100.c
@@ -0,0 +1,740 @@
+/*
+ * MVME3100 board emulation
+ *
+ * Copyright (c) 2015 Michael Davidsaver
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the LICENSE file in the top-level directory.
+ *
+ * This model was developed according to the
+ * MVME3100 Single Board Computer Programmer's Reference
+ * P/N: 6806800G37B
+ * July 2014
+ *
+ * mvme3100-1152
+ *   677MHz core, 256MB ram, 64MB flash
+ * mvme3100-1263
+ *   833MHz core, 512MB ram, 128MB flash
+ *
+ * MOTLoad on mvme3100-1152 says:
+ *   MPU-Type =MPC8540
+ *   MPU-Int Clock Speed  =666MHz
+ *   MPU-CCB Clock Speed  =333MHz
+ *   MPU-DDR Clock Speed  =166MHz
+ *   MPU-PCI Clock Speed  =66MHz, PCI, 64-bit
+ *   MPU-Int Cache(L2) Enabled, 256KB, L2CTL =A8000300
+ *   Reset/Boot Vector=Flash0
+ *   Local Memory Found   =1000 (&268435456)
+ *
+ * MOTLoad on mvme3100-1263 says:
+ *   MPU-Type =MPC8540
+ *   MPU-Int Clock Speed  =833MHz
+ *   MPU-CCB Clock Speed  =333MHz
+ *   MPU-DDR Clock Speed  =166MHz
+ *   MPU-PCI Clock Speed  =66MHz, PCI, 64-bit
+ *   MPU-Int Cache(L2) Enabled, 256KB, L2CTL =A8000300
+ *   Reset/Boot Vector=Flash0
+ *   Local Memory Found   =2000 (&536870912)
+ *
+ * Clock ratios
+ *   CCB/PCI  -> 5/1
+ *   core/CCB -> 2/1 (-1152)
+ *-> 5/2 (-1263)
+ *
+ * The overall memory map is determined by the Local Address Windows.
+ * We do not model the LAWs explicitly.
+ *
+ * MOTLoad configures as follows (a super set of table 1-4)
+ *   (MOTLoad RTOS Version 2.0,  PAL Version 1.2 RM04)
+ * LAW 0, 7 - disabled
+ * LAW 1 - 0x -> 0x7fff - RAM 2G
+ * LAW 2 - 0x8000 -> 0xbfff - PCI 1G
+ * LAW 3 - 0xc000 -> 0xdfff - PCI 512MB
+ * LAW 4 - 0xe000 -> 0xe0ff - PCI 16MB
+ * gap   - 0xe100 -> 0xbfff - CCSR @ 0xe100
+ * LAW 5 - 0xe200 -> 0xe2ff - LBC 16MB
+ * gap   - 0xe300 -> 0xefff
+ * LAW 6 - 0xf000 -> 0x - LBC 256MB
+ *
+ * And validated against the RTEMS 4.9.6 mvme3100 BSP
+ */
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qapi/error.h"
+#include "qapi/visitor.h"
+#include "e500.h"
+#include "cpu.h"
+#include "qemu-common.h"
+#include "cpu-qom.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/dma.h"
+#include "sysemu/block-backend.h"
+#include "hw/loader.h"
+#include "hw/pci/pci.h"
+#include "hw/boards.h"
+#include "hw/ppc/ppc.h"
+#include "hw/net/fsl_etsec/etsec.h"
+#include "sysemu/device_tree.h"
+#include "sysemu/qtest.h"
+#include "hw/ppc/openpic.h"
+#include "qemu/error-report.h"
+
+/* Same as prep.c and other PPC boards */
+#define CFG_ADDR 0xf510
+
+#define TYPE_MVME3100 MACHINE_TYPE_NAME("mvme3100")
+#define MVME3100(obj) OBJECT_CHECK(MVME3100State, (obj), TYPE_MVME3100)
+#define MVME3100_GET_CLASS(obj) \
+OBJECT_GET_CLASS(MVME3100Class, (obj), TYPE_MVME3100)
+#define MVME3100_CLASS(klass) \
+OBJECT_CLASS_CHECK(MVME3100Class, (klass), TYPE_MVME3100)
+
+#define E500_TSEC_OFFSET(N) (0x24000 + (N) * 0x1000)
+
+/* Complex Core Bus frequency */
+#define CCB_FREQ (3u)
+
+typedef struct mvme3100_info {
+const char *desc;
+uint32_t cpu_freq;
+uint32_t porpllsr;
+uint32_t ram_size;
+} mvme3100_info;
+
+typedef struct MVME3100Class {
+/*< private >*/
+MachineClass parent_class;
+/*< public >*/
+
+const mvme3100_info *info;
+} MVME3100Class;
+
+typedef struct MVME3100State {
+

[Qemu-devel] [PATCH 12/17] e500: add i2c controller to CCSR

2017-11-26 Thread Michael Davidsaver
Add i2c controller found on mpc8540,
mpc8544, and P2010 (newer ppc, unmodeled).

Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 hw/ppc/e500_ccsr.c | 15 +++
 1 file changed, 15 insertions(+)

diff --git a/hw/ppc/e500_ccsr.c b/hw/ppc/e500_ccsr.c
index c479ed91ee..cd8216daaf 100644
--- a/hw/ppc/e500_ccsr.c
+++ b/hw/ppc/e500_ccsr.c
@@ -46,6 +46,8 @@
 #define E500_ERR_DETECT  (0x2e40)
 #define E500_ERR_DISABLE (0x2e44)
 
+#define E500_I2C_OFFSET  (0x3000)
+
 #define E500_DUART_OFFSET(N) (0x4500 + (N) * 0x100)
 
 #define E500_PORPLLSR(0xE)
@@ -72,6 +74,7 @@ typedef struct {
 uint32_t ccb_freq;
 
 DeviceState *pic;
+DeviceState *i2c;
 } CCSRState;
 
 #define TYPE_E500_CCSR "e500-ccsr"
@@ -272,6 +275,18 @@ static void e500_ccsr_realize(DeviceState *dev, Error 
**errp)
 sysbus_mmio_get_region(pic, 0));
 /* Note: MPIC internal interrupts are offset by 16 */
 
+/* attach I2C controller */
+ccsr->i2c = qdev_create(NULL, "mpc8540-i2c");
+object_property_add_child(qdev_get_machine(), "i2c[*]",
+  OBJECT(ccsr->i2c), NULL);
+qdev_init_nofail(ccsr->i2c);
+memory_region_add_subregion(>iomem, E500_I2C_OFFSET,
+sysbus_mmio_get_region(
+SYS_BUS_DEVICE(ccsr->i2c), 0));
+sysbus_connect_irq(SYS_BUS_DEVICE(ccsr->i2c), 0,
+  qdev_get_gpio_in(ccsr->pic, 16 + 27));
+
+
 /* DUARTS */
 /* for mpc8540, mpc8544, and P2010 (unmodeled), the DUART reference clock
  * is the CCB clock divided by 16.
-- 
2.11.0




[Qemu-devel] [PATCH 17/17] tests: add mvme3100-test

2017-11-26 Thread Michael Davidsaver
Exercise some features of the mvme3100 CPLD logic
and read from the eeprom w/ VPD.

Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 tests/Makefile.include |  3 ++
 tests/mvme3100-test.c  | 79 ++
 2 files changed, 82 insertions(+)
 create mode 100644 tests/mvme3100-test.c

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 062d4e5b7b..97bce77ee4 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -373,6 +373,8 @@ check-qtest-s390x-y += tests/virtio-balloon-test$(EXESUF)
 check-qtest-s390x-y += tests/virtio-console-test$(EXESUF)
 check-qtest-s390x-y += tests/virtio-serial-test$(EXESUF)
 
+check-qtest-ppc-$(CONFIG_E500) += tests/mvme3100-test$(EXESUF)
+
 check-qtest-generic-y += tests/qom-test$(EXESUF)
 check-qtest-generic-y += tests/test-hmp$(EXESUF)
 
@@ -782,6 +784,7 @@ tests/i82801b11-test$(EXESUF): tests/i82801b11-test.o
 tests/ac97-test$(EXESUF): tests/ac97-test.o
 tests/es1370-test$(EXESUF): tests/es1370-test.o
 tests/intel-hda-test$(EXESUF): tests/intel-hda-test.o
+tests/mvme3100-test$(EXESUF): tests/mvme3100-test.o $(libqos-e500-obj-y)
 tests/ioh3420-test$(EXESUF): tests/ioh3420-test.o
 tests/usb-hcd-ohci-test$(EXESUF): tests/usb-hcd-ohci-test.o $(libqos-usb-obj-y)
 tests/usb-hcd-uhci-test$(EXESUF): tests/usb-hcd-uhci-test.o $(libqos-usb-obj-y)
diff --git a/tests/mvme3100-test.c b/tests/mvme3100-test.c
new file mode 100644
index 00..6dde8d1d29
--- /dev/null
+++ b/tests/mvme3100-test.c
@@ -0,0 +1,79 @@
+#include 
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "libqos/libqos.h"
+#include "libqos/i2c.h"
+
+#define assert_equal(A, B) g_assert_cmphex((A), ==, (B))
+
+static
+I2CAdapter *i2c;
+
+static
+void test_ccsr(void)
+{
+/* CCSRBAR is self referential */
+assert_equal(readl(0xff70), 0x000ff700);
+
+/* introspect memory size */
+assert_equal(readl(0xff702080), 0x8000);
+/* value is (ram_size-1)>>24 */
+assert_equal(readl(0xff702000), 15);
+}
+
+static
+void test_cpld(void)
+{
+/* read/write to test register */
+assert_equal(readl(0xe210), 0x);
+assert_equal(readl(0xe214), 0x);
+
+writel(0xe210, 0x12345678);
+
+assert_equal(readl(0xe210), 0x12345678);
+assert_equal(readl(0xe214), 0x12345678 ^ 0x);
+}
+
+static
+void test_eeprom(void)
+{
+char buf[] = "\x00\x00MOTOROLA";
+
+/* 1. zero address pointer
+ * 2. write 8 bytes,
+ * 3. re-zero address pointer
+ */
+i2c_send(i2c, 0xa8, (uint8_t *)buf, 10);
+i2c_send(i2c, 0xa8, (uint8_t *)buf, 2);
+
+/* read 8 bytes */
+i2c_recv(i2c, 0xa8, (uint8_t *)buf, 8);
+buf[8] = '\0';
+
+/* Read header for Motorola VPD info */
+g_assert_cmpstr(buf, ==, "MOTOROLA");
+}
+
+int main(int argc, char *argv[])
+{
+int ret;
+g_test_init(, , NULL);
+
+qtest_start("-machine mvme3100-1152");
+
+i2c = e500_i2c_create(0xff70);
+
+qtest_add_func("/mvme3100/ccsr", test_ccsr);
+qtest_add_func("/mvme3100/cpld", test_cpld);
+qtest_add_func("/mvme3100/eeprom", test_eeprom);
+
+ret = g_test_run();
+
+printf("Tests done\n");
+
+qtest_end();
+printf("Tests end\n");
+
+return ret;
+}
-- 
2.11.0




[Qemu-devel] [PATCH 14/17] e500: split mpc8544ds specific initialization

2017-11-26 Thread Michael Davidsaver
split off the remaining board specific parts
of e500_init() as mpc85xx_init() which
will be used by the existing
mpc8544ds and generic e500 boards.

Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 hw/ppc/e500.c  | 49 -
 hw/ppc/e500.h  |  3 ++-
 hw/ppc/e500plat.c  |  2 +-
 hw/ppc/mpc8544ds.c |  2 +-
 4 files changed, 36 insertions(+), 20 deletions(-)

diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index b0c8495aef..0ac7cdf6a1 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -690,7 +690,32 @@ static void ppce500_power_off(void *opaque, int line, int 
on)
 }
 }
 
-void ppce500_init(MachineState *machine, PPCE500Params *params)
+
+void ppce500_init(MachineState *machine, uint32_t decrementer_freq)
+{
+int i;
+for (i = 0; i < smp_cpus; i++) {
+PowerPCCPU *cpu;
+CPUState *cs;
+CPUPPCState *env;
+
+cpu = POWERPC_CPU(cpu_create(machine->cpu_type));
+env = >env;
+cs = CPU(cpu);
+
+if (env->mmu_model != POWERPC_MMU_BOOKE206) {
+error_report("MMU model %i not supported by this machine.",
+ env->mmu_model);
+exit(1);
+}
+
+env->spr_cb[SPR_BOOKE_PIR].default_value = cs->cpu_index = i;
+
+ppc_booke_timers_init(cpu, decrementer_freq, PPC_TIMER_E500);
+}
+}
+
+void mpc85xx_init(MachineState *machine, PPCE500Params *params)
 {
 MemoryRegion *address_space_mem = get_system_memory();
 MemoryRegion *ram = g_new(MemoryRegion, 1);
@@ -716,31 +741,21 @@ void ppce500_init(MachineState *machine, PPCE500Params 
*params)
 CPUPPCState *firstenv = NULL;
 MemoryRegion *ccsr_addr_space;
 SysBusDevice *s;
+CPUState *cs;
 
-for (i = 0; i < smp_cpus; i++) {
+ppce500_init(machine, 4);
+
+CPU_FOREACH(cs) {
 PowerPCCPU *cpu;
-CPUState *cs;
 
-cpu = POWERPC_CPU(cpu_create(machine->cpu_type));
+cpu = POWERPC_CPU(cs);
 env = >env;
-cs = CPU(cpu);
 
-if (env->mmu_model != POWERPC_MMU_BOOKE206) {
-fprintf(stderr, "MMU model %i not supported by this machine.\n",
-env->mmu_model);
-exit(1);
-}
 
+/* Register reset handler */
 if (!firstenv) {
 firstenv = env;
-}
 
-env->spr_cb[SPR_BOOKE_PIR].default_value = cs->cpu_index = i;
-
-ppc_booke_timers_init(cpu, 4, PPC_TIMER_E500);
-
-/* Register reset handler */
-if (!i) {
 /* Primary CPU */
 struct boot_info *boot_info;
 boot_info = g_malloc0(sizeof(struct boot_info));
diff --git a/hw/ppc/e500.h b/hw/ppc/e500.h
index 70ba1d8f4f..350be17462 100644
--- a/hw/ppc/e500.h
+++ b/hw/ppc/e500.h
@@ -24,7 +24,8 @@ typedef struct PPCE500Params {
 hwaddr spin_base;
 } PPCE500Params;
 
-void ppce500_init(MachineState *machine, PPCE500Params *params);
+void ppce500_init(MachineState *machine, uint32_t decrementer_freq);
+void mpc85xx_init(MachineState *machine, PPCE500Params *params);
 
 hwaddr booke206_page_size_to_tlb(uint64_t size);
 
diff --git a/hw/ppc/e500plat.c b/hw/ppc/e500plat.c
index e59e80fb9e..103efc68c2 100644
--- a/hw/ppc/e500plat.c
+++ b/hw/ppc/e500plat.c
@@ -55,7 +55,7 @@ static void e500plat_init(MachineState *machine)
 params.mpic_version = OPENPIC_MODEL_FSL_MPIC_20;
 }
 
-ppce500_init(machine, );
+mpc85xx_init(machine, );
 }
 
 static void e500plat_machine_init(MachineClass *mc)
diff --git a/hw/ppc/mpc8544ds.c b/hw/ppc/mpc8544ds.c
index 1717953ec7..7de4ed8ae2 100644
--- a/hw/ppc/mpc8544ds.c
+++ b/hw/ppc/mpc8544ds.c
@@ -47,7 +47,7 @@ static void mpc8544ds_init(MachineState *machine)
 exit(1);
 }
 
-ppce500_init(machine, );
+mpc85xx_init(machine, );
 }
 
 
-- 
2.11.0




[Qemu-devel] [PATCH 05/17] timer: generalize Dallas/Maxim RTC i2c devices

2017-11-26 Thread Michael Davidsaver
Support for: ds1307, ds1337, ds1338, ds1339,
ds1340, ds1375, ds1388, and ds3231.

Tested with ds1338 and ds1375.

Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 default-configs/arm-softmmu.mak |   2 +-
 hw/timer/Makefile.objs  |   2 +-
 hw/timer/ds-rtc-i2c.c   | 461 
 hw/timer/ds1338.c   | 239 -
 4 files changed, 463 insertions(+), 241 deletions(-)
 create mode 100644 hw/timer/ds-rtc-i2c.c
 delete mode 100644 hw/timer/ds1338.c

diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index d37edc4312..b857823681 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -31,7 +31,7 @@ CONFIG_SMC91C111=y
 CONFIG_ALLWINNER_EMAC=y
 CONFIG_IMX_FEC=y
 CONFIG_FTGMAC100=y
-CONFIG_DS1338=y
+CONFIG_DSRTCI2C=y
 CONFIG_PFLASH_CFI01=y
 CONFIG_PFLASH_CFI02=y
 CONFIG_MICRODRIVE=y
diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs
index 8c19eac3b6..290015ebec 100644
--- a/hw/timer/Makefile.objs
+++ b/hw/timer/Makefile.objs
@@ -3,7 +3,7 @@ common-obj-$(CONFIG_ARM_MPTIMER) += arm_mptimer.o
 common-obj-$(CONFIG_ARM_V7M) += armv7m_systick.o
 common-obj-$(CONFIG_A9_GTIMER) += a9gtimer.o
 common-obj-$(CONFIG_CADENCE) += cadence_ttc.o
-common-obj-$(CONFIG_DS1338) += ds1338.o
+common-obj-$(CONFIG_DSRTCI2C) += ds-rtc-i2c.o
 common-obj-$(CONFIG_HPET) += hpet.o
 common-obj-$(CONFIG_I8254) += i8254_common.o i8254.o
 common-obj-$(CONFIG_M48T59) += m48t59.o
diff --git a/hw/timer/ds-rtc-i2c.c b/hw/timer/ds-rtc-i2c.c
new file mode 100644
index 00..ad2f8f2a68
--- /dev/null
+++ b/hw/timer/ds-rtc-i2c.c
@@ -0,0 +1,461 @@
+/* Emulation of various Dallas/Maxim RTCs accessed via I2C bus
+ *
+ * Copyright (c) 2017 Michael Davidsaver
+ * Copyright (c) 2009 CodeSourcery
+ *
+ * Authors: Michael Davidsaver
+ *  Paul Brook
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the LICENSE file in the top-level directory.
+ *
+ * Models real time read/set and NVRAM.
+ * Does not model alarms, or control/status registers.
+ *
+ * Generalized register map is:
+ *   [Current time]
+ *   [Alarm settings] (optional)
+ *   [Control/Status] (optional)
+ *   [Non-volatile memory] (optional)
+ *
+ * The current time registers are almost always the same,
+ * with the exception being that some have a CENTURY bit
+ * in the month register.
+ */
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qemu/timer.h"
+#include "qemu/bcd.h"
+#include "hw/hw.h"
+#include "hw/registerfields.h"
+#include "hw/i2c/i2c.h"
+#include "sysemu/qtest.h"
+#include "qemu/error-report.h"
+
+/* #define DEBUG_DSRTC */
+
+#ifdef DEBUG_DSRTC
+#define DPRINTK(FMT, ...) info_report(TYPE_DSRTC " : " FMT, ## __VA_ARGS__)
+#else
+#define DPRINTK(FMT, ...) do {} while (0)
+#endif
+
+#define LOG(MSK, FMT, ...) qemu_log_mask(MSK, TYPE_DSRTC " : " FMT "\n", \
+## __VA_ARGS__)
+
+#define DSRTC_REGSIZE (0x40)
+
+/* values stored in BCD */
+/* 00-59 */
+#define R_SEC   (0x0)
+/* 00-59 */
+#define R_MIN   (0x1)
+#define R_HOUR  (0x2)
+/* 1-7 */
+#define R_WDAY  (0x3)
+/* 0-31 */
+#define R_DATE  (0x4)
+#define R_MONTH (0x5)
+/* 0-99 */
+#define R_YEAR  (0x6)
+
+/* use 12 hour mode when set */
+FIELD(HOUR, SET12, 6, 1)
+/* 00-23 */
+FIELD(HOUR, HOUR24, 0, 6)
+FIELD(HOUR, AMPM, 5, 1)
+/* 1-12 (not 0-11!) */
+FIELD(HOUR, HOUR12, 0, 5)
+
+/* 1-12 */
+FIELD(MONTH, MONTH, 0, 5)
+FIELD(MONTH, CENTURY, 7, 1)
+
+typedef struct DSRTCInfo {
+/* if bit 7 of the Month register is set after Y2K */
+bool has_century;
+/* address of first non-volatile memory cell.
+ * nv_start >= reg_end means no NV memory.
+ */
+uint8_t nv_start;
+/* total size of register range.  When address counter rolls over. */
+uint8_t reg_size;
+} DSRTCInfo;
+
+typedef struct DSRTCState {
+I2CSlave parent_obj;
+
+const DSRTCInfo *info;
+
+qemu_irq alarm_irq;
+
+/* register address counter */
+uint8_t addr;
+/* when writing, whether the address has been sent */
+bool addrd;
+
+int64_t time_offset;
+int8_t wday_offset;
+
+uint8_t regs[DSRTC_REGSIZE];
+} DSRTCState;
+
+typedef struct DSRTCClass {
+I2CSlaveClass parent_class;
+
+const DSRTCInfo *info;
+} DSRTCClass;
+
+#define TYPE_DSRTC "ds-rtc-i2c"
+#define DSRTC(obj) OBJECT_CHECK(DSRTCState, (obj), TYPE_DSRTC)
+#define DSRTC_GET_CLASS(obj) \
+OBJECT_GET_CLASS(DSRTCClass, obj, TYPE_DSRTC)
+#define DSRTC_CLASS(klass) \
+OBJECT_CLASS_CHECK(DSRTCClass, klass, TYPE_DSRTC)
+
+static const VMStateDescription vmstate_dsrtc = {
+.name = TYPE_DSRTC,
+.version_id = 1,
+.minimum_version_id = 1,
+.fields = (VMStateField[]) {
+VMSTATE_I2C_SLAVE(parent_obj, DSRTCState),
+VMSTATE_INT64(time_offset, DSRTCState),
+   

[Qemu-devel] [PATCH 09/17] e500: move mpic under CCSR

2017-11-26 Thread Michael Davidsaver
Start moving code out of ppce500_init()

Existing ppce500_init_mpic() suggests that MPIC may not be created w/ KVM.
However, ppce500_init() used mpicdev unconditionally, and would
fail if the MPIC isn't created.  So require creation.

Not tested with KVM for lack of hardware.

Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 hw/ppc/e500.c  | 102 +++--
 hw/ppc/e500_ccsr.c |  85 +---
 2 files changed, 84 insertions(+), 103 deletions(-)

diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index e22919f4f1..1872bb8eaa 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -29,7 +29,6 @@
 #include "sysemu/kvm.h"
 #include "kvm_ppc.h"
 #include "sysemu/device_tree.h"
-#include "hw/ppc/openpic.h"
 #include "hw/ppc/ppc.h"
 #include "hw/loader.h"
 #include "elf.h"
@@ -679,92 +678,6 @@ static void ppce500_cpu_reset(void *opaque)
 mmubooke_create_initial_mapping(env);
 }
 
-static DeviceState *ppce500_init_mpic_qemu(PPCE500Params *params,
-   qemu_irq **irqs)
-{
-DeviceState *dev;
-SysBusDevice *s;
-int i, j, k;
-
-dev = qdev_create(NULL, TYPE_OPENPIC);
-object_property_add_child(qdev_get_machine(), "pic", OBJECT(dev),
-  _fatal);
-qdev_prop_set_uint32(dev, "model", params->mpic_version);
-qdev_prop_set_uint32(dev, "nb_cpus", smp_cpus);
-
-qdev_init_nofail(dev);
-s = SYS_BUS_DEVICE(dev);
-
-k = 0;
-for (i = 0; i < smp_cpus; i++) {
-for (j = 0; j < OPENPIC_OUTPUT_NB; j++) {
-sysbus_connect_irq(s, k++, irqs[i][j]);
-}
-}
-
-return dev;
-}
-
-static DeviceState *ppce500_init_mpic_kvm(PPCE500Params *params,
-  qemu_irq **irqs, Error **errp)
-{
-Error *err = NULL;
-DeviceState *dev;
-CPUState *cs;
-
-dev = qdev_create(NULL, TYPE_KVM_OPENPIC);
-qdev_prop_set_uint32(dev, "model", params->mpic_version);
-
-object_property_set_bool(OBJECT(dev), true, "realized", );
-if (err) {
-error_propagate(errp, err);
-object_unparent(OBJECT(dev));
-return NULL;
-}
-
-CPU_FOREACH(cs) {
-if (kvm_openpic_connect_vcpu(dev, cs)) {
-fprintf(stderr, "%s: failed to connect vcpu to irqchip\n",
-__func__);
-abort();
-}
-}
-
-return dev;
-}
-
-static DeviceState *ppce500_init_mpic(MachineState *machine,
-  PPCE500Params *params,
-  MemoryRegion *ccsr,
-  qemu_irq **irqs)
-{
-DeviceState *dev = NULL;
-SysBusDevice *s;
-
-if (kvm_enabled()) {
-Error *err = NULL;
-
-if (machine_kernel_irqchip_allowed(machine)) {
-dev = ppce500_init_mpic_kvm(params, irqs, );
-}
-if (machine_kernel_irqchip_required(machine) && !dev) {
-error_reportf_err(err,
-  "kernel_irqchip requested but unavailable: ");
-exit(1);
-}
-}
-
-if (!dev) {
-dev = ppce500_init_mpic_qemu(params, irqs);
-}
-
-s = SYS_BUS_DEVICE(dev);
-memory_region_add_subregion(ccsr, MPC8544_MPIC_REGS_OFFSET,
-s->mmio[0].memory);
-
-return dev;
-}
-
 static void ppce500_power_off(void *opaque, int line, int on)
 {
 if (on) {
@@ -794,18 +707,14 @@ void ppce500_init(MachineState *machine, PPCE500Params 
*params)
 /* irq num for pin INTA, INTB, INTC and INTD is 1, 2, 3 and
  * 4 respectively */
 unsigned int pci_irq_nrs[PCI_NUM_PINS] = {1, 2, 3, 4};
-qemu_irq **irqs;
 DeviceState *dev, *mpicdev;
 CPUPPCState *firstenv = NULL;
 MemoryRegion *ccsr_addr_space;
 SysBusDevice *s;
 
-irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *));
-irqs[0] = g_malloc0(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
 for (i = 0; i < smp_cpus; i++) {
 PowerPCCPU *cpu;
 CPUState *cs;
-qemu_irq *input;
 
 cpu = POWERPC_CPU(cpu_create(machine->cpu_type));
 env = >env;
@@ -821,13 +730,7 @@ void ppce500_init(MachineState *machine, PPCE500Params 
*params)
 firstenv = env;
 }
 
-irqs[i] = irqs[0] + (i * OPENPIC_OUTPUT_NB);
-input = (qemu_irq *)env->irq_inputs;
-irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT];
-irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT];
 env->spr_cb[SPR_BOOKE_PIR].default_value = cs->cpu_index = i;
-env->mpic_iack = params->ccsrbar_base +
- MPC8544_MPIC_REGS_OFFSET + 0xa0;
 
 ppc_booke_timers_init(cpu, 4, PPC_TIMER_E500);

[Qemu-devel] [PATCH 13/17] e500: move PCI host bridge into CCSR

2017-11-26 Thread Michael Davidsaver
Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 hw/ppc/e500.c  | 13 -
 hw/ppc/e500_ccsr.c | 27 +++
 2 files changed, 31 insertions(+), 9 deletions(-)

diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index cfd5ed0152..b0c8495aef 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -769,6 +769,8 @@ void ppce500_init(MachineState *machine, PPCE500Params 
*params)
 qdev_prop_set_uint32(dev, "mpic-model", params->mpic_version);
 qdev_prop_set_uint32(dev, "base", params->ccsrbar_base);
 qdev_prop_set_uint32(dev, "ram-size", ram_size);
+qdev_prop_set_uint32(dev, "pci_first_slot", params->pci_first_slot);
+qdev_prop_set_uint32(dev, "pci_first_pin_irq", pci_irq_nrs[0]);
 qdev_init_nofail(dev);
 ccsr_addr_space = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
 
@@ -778,20 +780,13 @@ void ppce500_init(MachineState *machine, PPCE500Params 
*params)
 
 
 /* PCI */
-dev = qdev_create(NULL, "e500-pcihost");
-object_property_add_child(qdev_get_machine(), "pci-host", OBJECT(dev),
-  _abort);
-qdev_prop_set_uint32(dev, "first_slot", params->pci_first_slot);
-qdev_prop_set_uint32(dev, "first_pin_irq", pci_irq_nrs[0]);
-qdev_init_nofail(dev);
+dev = DEVICE(object_resolve_path("/machine/pci-host", 0));
+assert(dev);
 s = SYS_BUS_DEVICE(dev);
 for (i = 0; i < PCI_NUM_PINS; i++) {
 sysbus_connect_irq(s, i, qdev_get_gpio_in(mpicdev, pci_irq_nrs[i]));
 }
 
-memory_region_add_subregion(ccsr_addr_space, MPC8544_PCI_REGS_OFFSET,
-sysbus_mmio_get_region(s, 0));
-
 pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
 if (!pci_bus)
 printf("couldn't create PCI controller!\n");
diff --git a/hw/ppc/e500_ccsr.c b/hw/ppc/e500_ccsr.c
index cd8216daaf..4ec8f7524d 100644
--- a/hw/ppc/e500_ccsr.c
+++ b/hw/ppc/e500_ccsr.c
@@ -50,6 +50,8 @@
 
 #define E500_DUART_OFFSET(N) (0x4500 + (N) * 0x100)
 
+#define E500_PCI_OFFSET  (0x8000ULL)
+
 #define E500_PORPLLSR(0xE)
 #define E500_PVR (0xE00A0)
 #define E500_SVR (0xE00A4)
@@ -75,6 +77,7 @@ typedef struct {
 
 DeviceState *pic;
 DeviceState *i2c;
+DeviceState *pcihost;
 } CCSRState;
 
 #define TYPE_E500_CCSR "e500-ccsr"
@@ -201,6 +204,7 @@ static void e500_ccsr_init(Object *obj)
 DeviceState *dev = DEVICE(obj);
 CCSRState *ccsr = E500_CCSR(dev);
 
+/* prepare MPIC */
 assert(current_machine);
 if (kvm_enabled()) {
 
@@ -228,6 +232,18 @@ static void e500_ccsr_init(Object *obj)
 object_property_add_alias(obj, "mpic-model",
   OBJECT(ccsr->pic), "model",
   _fatal);
+
+/* prepare PCI host bridge */
+ccsr->pcihost = qdev_create(NULL, "e500-pcihost");
+object_property_add_child(qdev_get_machine(), "pci-host", 
OBJECT(ccsr->pcihost),
+  _abort);
+
+object_property_add_alias(obj, "pci_first_slot",
+  OBJECT(ccsr->pcihost), "first_slot",
+  _fatal);
+object_property_add_alias(obj, "pci_first_pin_irq",
+  OBJECT(ccsr->pcihost), "first_pin_irq",
+  _fatal);
 }
 
 static void e500_ccsr_realize(DeviceState *dev, Error **errp)
@@ -240,6 +256,7 @@ static void e500_ccsr_realize(DeviceState *dev, Error 
**errp)
   ccsr, "e500-ccsr", 1024 * 1024);
 sysbus_init_mmio(SYS_BUS_DEVICE(dev), >iomem);
 
+/* realize MPIC */
 qdev_init_nofail(ccsr->pic);
 pic = SYS_BUS_DEVICE(ccsr->pic);
 
@@ -275,6 +292,13 @@ static void e500_ccsr_realize(DeviceState *dev, Error 
**errp)
 sysbus_mmio_get_region(pic, 0));
 /* Note: MPIC internal interrupts are offset by 16 */
 
+/* realize PCI host bridge*/
+qdev_init_nofail(ccsr->pcihost);
+
+memory_region_add_subregion(>iomem, E500_PCI_OFFSET,
+sysbus_mmio_get_region(
+SYS_BUS_DEVICE(ccsr->pcihost), 0));
+
 /* attach I2C controller */
 ccsr->i2c = qdev_create(NULL, "mpc8540-i2c");
 object_property_add_child(qdev_get_machine(), "i2c[*]",
@@ -314,6 +338,9 @@ static Property e500_ccsr_props[] = {
 DEFINE_PROP_UINT32("porpllsr", CCSRState, porpllsr, 0),
 DEFINE_PROP_UINT32("ccb-freq", CCSRState, ccb_freq, 3u),
 /* "mpic-model" aliased from MPIC */
+/* "pci_first_slot"
+ * "pci_first_pin_irq" aliased from PCI host bridge
+ */
 DEFINE_PROP_END_OF_LIST()
 };
 
-- 
2.11.0




[Qemu-devel] [PATCH 07/17] e500: fix pci host bridge class/type

2017-11-26 Thread Michael Davidsaver
Correct some confusion wrt. the PCI facing
side of the PCI host bridge (not PCIe root complex).
The ref. manual for the mpc8533 (as well as
mpc8540 and mpc8540) give the class code as
PCI_CLASS_PROCESSOR_POWERPC.
While the PCI_HEADER_TYPE field is oddly omitted,
the tables in the "PCI Configuration Header"
section shows a type 0 layout using all 6 BAR
registers (as 2x 32, and 2x 64 bit regions)

So 997505065dc92e533debf5cb23012ba4e673d387
seems to be in error.  Although there was
perhaps some confusion as the mpc8533
has a separate PCIe root complex.
With PCIe, a root complex has PCI_HEADER_TYPE=1.

Neither the PCI host bridge, nor the PCIe
root complex advertise class PCI_CLASS_BRIDGE_PCI.

This was confusing Linux guests, which try
to interpret the host bridge as a pci-pci
bridge, but get confused and re-enumerate
the bus when the primary/secondary/subordinate
bus registers don't have valid values.

Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 hw/pci-host/ppce500.c | 5 -
 1 file changed, 5 deletions(-)

diff --git a/hw/pci-host/ppce500.c b/hw/pci-host/ppce500.c
index f2d108bc8a..8073d396ff 100644
--- a/hw/pci-host/ppce500.c
+++ b/hw/pci-host/ppce500.c
@@ -423,11 +423,6 @@ static void e500_pcihost_bridge_realize(PCIDevice *d, 
Error **errp)
   "/e500-ccsr"));
 MemoryRegion *ccsr_mr = sysbus_mmio_get_region(ccsr, 0);
 
-pci_config_set_class(d->config, PCI_CLASS_BRIDGE_PCI);
-d->config[PCI_HEADER_TYPE] =
-(d->config[PCI_HEADER_TYPE] & PCI_HEADER_TYPE_MULTI_FUNCTION) |
-PCI_HEADER_TYPE_BRIDGE;
-
 memory_region_init_alias(>bar0, OBJECT(ccsr), "e500-pci-bar0", ccsr_mr,
  0, memory_region_size(ccsr_mr));
 pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, >bar0);
-- 
2.11.0




[Qemu-devel] [PATCH 08/17] e500: additional CCSR registers

2017-11-26 Thread Michael Davidsaver
Add CCSRBAR to allow CCSR region to be relocated.

Guest memory size introspection via RAM config
registers.

Dummy RAM error controls.

Clock introspection via Power on Reset PLL
Status Register.

Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>

ccsrbase also update iack
---
 hw/ppc/e500.c  |  5 ++-
 hw/ppc/e500_ccsr.c | 93 --
 2 files changed, 95 insertions(+), 3 deletions(-)

diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index b90f4231a6..e22919f4f1 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -51,7 +51,9 @@
 
 #define RAM_SIZES_ALIGN(64UL << 20)
 
-/* TODO: parameterize */
+/* TODO: parameterize
+ * Some CCSR offsets duplicated in e500_ccsr.c
+ */
 #define MPC8544_CCSRBAR_SIZE   0x0010ULL
 #define MPC8544_MPIC_REGS_OFFSET   0x4ULL
 #define MPC8544_MSI_REGS_OFFSET   0x41600ULL
@@ -856,6 +858,7 @@ void ppce500_init(MachineState *machine, PPCE500Params 
*params)
 object_property_add_child(qdev_get_machine(), "e500-ccsr",
   OBJECT(dev), NULL);
 qdev_prop_set_uint32(dev, "base", params->ccsrbar_base);
+qdev_prop_set_uint32(dev, "ram-size", ram_size);
 qdev_init_nofail(dev);
 ccsr_addr_space = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
 
diff --git a/hw/ppc/e500_ccsr.c b/hw/ppc/e500_ccsr.c
index 1b586c3f42..9400d7cf13 100644
--- a/hw/ppc/e500_ccsr.c
+++ b/hw/ppc/e500_ccsr.c
@@ -30,13 +30,26 @@
 #include "hw/sysbus.h"
 
 /* E500_ denotes registers common to all */
+/* Some CCSR offsets duplicated in e500.c */
 
+#define E500_CCSRBAR (0)
+
+#define E500_CS0_BNDS(0x2000)
+
+#define E500_CS0_CONFIG  (0x2080)
+
+#define E500_ERR_DETECT  (0x2e40)
+#define E500_ERR_DISABLE (0x2e44)
+
+#define E500_PORPLLSR(0xE)
 #define E500_PVR (0xE00A0)
 #define E500_SVR (0xE00A4)
 
 #define MPC8544_RSTCR   (0xE00B0)
 #define MPC8544_RSTCR_RESET  (0x02)
 
+#define E500_MPIC_OFFSET   (0x4ULL)
+
 typedef struct {
 /*< private >*/
 SysBusDevice parent_obj;
@@ -44,19 +57,59 @@ typedef struct {
 
 MemoryRegion iomem;
 
-uint32_t defbase;
+uint32_t defbase, base;
+uint32_t ram_size;
+uint32_t merrd;
+
+uint32_t porpllsr;
+
+DeviceState *pic;
 } CCSRState;
 
 #define TYPE_E500_CCSR "e500-ccsr"
 #define E500_CCSR(obj) OBJECT_CHECK(CCSRState, (obj), TYPE_E500_CCSR)
 
+/* call after changing CCSRState::base */
+static void e500_ccsr_post_move(CCSRState *ccsr)
+{
+CPUState *cs;
+
+CPU_FOREACH(cs) {
+PowerPCCPU *cpu = POWERPC_CPU(cs);
+CPUPPCState *env = >env;
+
+env->mpic_iack = ccsr->base +
+ E500_MPIC_OFFSET + 0xa0;
+}
+
+sysbus_mmio_map(SYS_BUS_DEVICE(ccsr), 0, ccsr->base);
+}
+
 static uint64_t e500_ccsr_read(void *opaque, hwaddr addr,
   unsigned size)
 {
+CCSRState *ccsr = opaque;
 PowerPCCPU *cpu = POWERPC_CPU(current_cpu);
 CPUPPCState *env = >env;
 
 switch (addr) {
+case E500_CCSRBAR:
+return ccsr->base >> 12;
+case E500_CS0_BNDS:
+/* we model all RAM in a single chip with addresses [0, ram_size) */
+return (ccsr->ram_size - 1) >> 24;
+case E500_CS0_CONFIG:
+return 1 << 31;
+case E500_ERR_DETECT:
+return 0; /* (errors not modeled) */
+case E500_ERR_DISABLE:
+return ccsr->merrd;
+case E500_PORPLLSR:
+if (!ccsr->porpllsr) {
+qemu_log_mask(LOG_UNIMP,
+  "Machine does not provide valid PORPLLSR\n");
+}
+return ccsr->porpllsr;
 case E500_PVR:
 return env->spr[SPR_PVR];
 case E500_SVR:
@@ -72,10 +125,22 @@ static uint64_t e500_ccsr_read(void *opaque, hwaddr addr,
 static void e500_ccsr_write(void *opaque, hwaddr addr,
uint64_t value, unsigned size)
 {
+CCSRState *ccsr = opaque;
 PowerPCCPU *cpu = POWERPC_CPU(current_cpu);
 CPUPPCState *env = >env;
 uint32_t svr = env->spr[SPR_E500_SVR] >> 16;
 
+switch (addr) {
+case E500_CCSRBAR:
+value &= 0x000fff00;
+ccsr->base = value << 12;
+e500_ccsr_post_move(ccsr);
+return;
+case E500_ERR_DISABLE:
+ccsr->merrd = value & 0xd;
+return;
+}
+
 switch (svr) {
 case 0: /* generic.  assumed to be mpc8544ds or e500plat board */
 case 0x8034: /* mpc8544 */
@@ -104,11 +169,20 @@ static const MemoryRegionOps e500_ccsr_ops = {
 }
 };
 
+static int e500_ccsr_post_load(void *opaque, int version_id)
+{
+CCSRState *ccsr = opaque;
+
+e500_ccsr_post_move(ccsr);
+return 0;
+}
+
 static void e500_ccsr_reset(DeviceState *dev)
 {
 CCSRState *ccsr = E500_CCSR(dev);
 
-sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, ccsr->defbase);
+ccs

[Qemu-devel] [PATCH 03/17] i2c: add mpc8540 i2c controller

2017-11-26 Thread Michael Davidsaver
Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 hw/i2c/Makefile.objs |   1 +
 hw/i2c/mpc8540_i2c.c | 307 +++
 hw/i2c/trace-events  |   6 +
 3 files changed, 314 insertions(+)
 create mode 100644 hw/i2c/mpc8540_i2c.c

diff --git a/hw/i2c/Makefile.objs b/hw/i2c/Makefile.objs
index 0594dea3ae..79af1dd901 100644
--- a/hw/i2c/Makefile.objs
+++ b/hw/i2c/Makefile.objs
@@ -9,3 +9,4 @@ common-obj-$(CONFIG_IMX_I2C) += imx_i2c.o
 common-obj-$(CONFIG_ASPEED_SOC) += aspeed_i2c.o
 obj-$(CONFIG_OMAP) += omap_i2c.o
 obj-$(CONFIG_PPC4XX) += ppc4xx_i2c.o
+obj-$(CONFIG_E500) += mpc8540_i2c.o
diff --git a/hw/i2c/mpc8540_i2c.c b/hw/i2c/mpc8540_i2c.c
new file mode 100644
index 00..b9f5773b35
--- /dev/null
+++ b/hw/i2c/mpc8540_i2c.c
@@ -0,0 +1,307 @@
+/*
+ * MPC8540 I2C bus interface
+ * As described in
+ * MPC8540 PowerQUICC III Integrated Host Processor Reference Manual, Rev. 1
+ * Part 2 chapter 11
+ *
+ * Compatible I2C controllers are found on other Freescale chips
+ * including mpc8544 and P2010.
+ *
+ * Copyright (c) 2015 Michael Davidsaver
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the LICENSE file in the top-level directory.
+ */
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "hw/hw.h"
+#include "hw/registerfields.h"
+#include "hw/i2c/i2c.h"
+#include "hw/sysbus.h"
+#include "qemu/error-report.h"
+
+#include "trace.h"
+
+/* #define DEBUG_LVL 0 */
+
+#ifdef DEBUG_LVL
+#define DPRINTK(LVL, FMT, ...) do { \
+if ((LVL) <= DEBUG_LVL) {\
+info_report(TYPE_MPC8540_I2C " : " FMT, ## __VA_ARGS__); \
+} } while (0)
+#else
+#define DPRINTK(LVL, FMT, ...) do {} while (0)
+#endif
+
+#define LOG(MSK, FMT, ...) qemu_log_mask(MSK, TYPE_MPC8540_I2C \
+" : " FMT "\n", ## __VA_ARGS__)
+
+#define TYPE_MPC8540_I2C "mpc8540-i2c"
+#define MPC8540_I2C(obj) OBJECT_CHECK(MPC8540I2CState, (obj), TYPE_MPC8540_I2C)
+
+/* offsets relative to CCSR offset 0x3000 */
+#define R_I2CADR (0)
+#define R_I2CFDR (4)
+#define R_I2CCR  (8)
+#define R_I2CSR  (0xc)
+#define R_I2CDR  (0x10)
+#define R_I2CDFSRR (0x14)
+
+FIELD(I2CCR, MEN, 7, 1)
+FIELD(I2CCR, MIEN, 6, 1)
+FIELD(I2CCR, MSTA, 5, 1)
+FIELD(I2CCR, MTX, 4, 1)
+FIELD(I2CCR, TXAK, 3, 1)
+FIELD(I2CCR, RSTA, 2, 1)
+FIELD(I2CCR, BCST, 0, 1)
+
+FIELD(I2CSR, MCF, 7, 1)
+FIELD(I2CSR, MAAS, 6, 1)
+FIELD(I2CSR, MBB, 5, 1)
+FIELD(I2CSR, MAL, 4, 1)
+FIELD(I2CSR, BCSTM, 3, 1)
+FIELD(I2CSR, SRW, 2, 1)
+FIELD(I2CSR, MIF, 1, 1)
+FIELD(I2CSR, RXAK, 0, 1)
+
+typedef struct MPC8540I2CState {
+SysBusDevice parent_obj;
+
+I2CBus *bus;
+
+uint8_t ctrl, sts;
+uint8_t freq, filt;
+/* Reads are pipelined, this is the next data value */
+uint8_t dbuf, dbuf_valid;
+
+qemu_irq irq;
+
+MemoryRegion mmio;
+} MPC8540I2CState;
+
+#define I2CCR(BIT) FIELD_EX32(i2c->ctrl, I2CCR, BIT)
+#define I2CSR(BIT) FIELD_EX32(i2c->sts, I2CSR, BIT)
+
+#define I2CSR_SET(BIT, VAL) do {\
+i2c->sts = FIELD_DP32(i2c->sts, I2CSR, BIT, VAL);\
+} while (0)
+
+static
+void mpc8540_update_irq(MPC8540I2CState *i2c)
+{
+int ena = i2c->ctrl & 0x40,
+sts = i2c->sts & 0x02,
+act = !!(ena && sts);
+
+DPRINTK(1, "IRQ %c ena %c sts %c",
+act ? 'X' : '_',
+ena ? 'X' : '_',
+sts ? 'X' : '_');
+
+qemu_set_irq(i2c->irq, act);
+}
+
+static
+uint64_t mpc8540_i2c_read(void *opaque, hwaddr addr, unsigned size)
+{
+MPC8540I2CState *i2c = opaque;
+uint32_t val;
+
+switch (addr) {
+case R_I2CADR: /* ADDR */
+val = 0;
+break;
+case R_I2CFDR: /* Freq Div. */
+val = i2c->freq;
+break;
+case R_I2CCR: /* CONTROL */
+val = i2c->ctrl & ~0x06;
+break;
+case R_I2CSR: /* STATUS */
+val = i2c->sts;
+break;
+case R_I2CDR: /* DATA */
+/* Reads are "pipelined" and so return the previous value of the
+ * register
+ */
+val = i2c->dbuf;
+if (I2CCR(MEN) && I2CSR(MBB)) { /* enabled and busy */
+if (!i2c_bus_busy(i2c->bus) || I2CCR(MTX)) {
+if (!i2c->dbuf_valid) {
+LOG(LOG_GUEST_ERROR, "Read during addr or tx");
+}
+i2c->dbuf = 0xff;
+i2c->dbuf_valid = false;
+} else {
+int ret = i2c_recv(i2c->bus);
+i2c->dbuf = (uint8_t)ret;
+i2c->dbuf_valid = true;
+trace_mpc8540_i2c_read(i2c->dbuf);
+I2CSR_SET(MIF, 1);
+I2CSR_SET(RXAK, 0);
+mpc8540_update_irq(i2c);
+}
+} else {
+i2c->dbuf = 0xff;
+i2c->dbuf_valid = false;
+ 

[Qemu-devel] [PATCH 06/17] tests: rewrite testing for DS RTC devices

2017-11-26 Thread Michael Davidsaver
Replace existing ds1338-test with more thorough
test of time read and set.

Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 tests/Makefile.include  |   4 +-
 tests/ds-rtc-i2c-test.c | 162 
 tests/ds1338-test.c |  77 ---
 3 files changed, 164 insertions(+), 79 deletions(-)
 create mode 100644 tests/ds-rtc-i2c-test.c
 delete mode 100644 tests/ds1338-test.c

diff --git a/tests/Makefile.include b/tests/Makefile.include
index ad1c219423..56045cdf09 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -348,7 +348,7 @@ check-qtest-sparc64-y = tests/endianness-test$(EXESUF)
 check-qtest-sparc64-y += tests/prom-env-test$(EXESUF)
 
 check-qtest-arm-y = tests/tmp105-test$(EXESUF)
-check-qtest-arm-y += tests/ds1338-test$(EXESUF)
+check-qtest-arm-y += tests/ds-rtc-i2c-test$(EXESUF)
 check-qtest-arm-y += tests/m25p80-test$(EXESUF)
 gcov-files-arm-y += hw/misc/tmp105.c
 check-qtest-arm-y += tests/virtio-blk-test$(EXESUF)
@@ -745,7 +745,7 @@ tests/bios-tables-test$(EXESUF): tests/bios-tables-test.o \
tests/boot-sector.o tests/acpi-utils.o $(libqos-obj-y)
 tests/pxe-test$(EXESUF): tests/pxe-test.o tests/boot-sector.o $(libqos-obj-y)
 tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y)
-tests/ds1338-test$(EXESUF): tests/ds1338-test.o $(libqos-imx-obj-y)
+tests/ds-rtc-i2c-test$(EXESUF): tests/ds-rtc-i2c-test.o $(libqos-imx-obj-y)
 tests/m25p80-test$(EXESUF): tests/m25p80-test.o
 tests/i440fx-test$(EXESUF): tests/i440fx-test.o $(libqos-pc-obj-y)
 tests/q35-test$(EXESUF): tests/q35-test.o $(libqos-pc-obj-y)
diff --git a/tests/ds-rtc-i2c-test.c b/tests/ds-rtc-i2c-test.c
new file mode 100644
index 00..0586dbd467
--- /dev/null
+++ b/tests/ds-rtc-i2c-test.c
@@ -0,0 +1,162 @@
+/* Testing of Dallas/Maxim I2C bus RTC devices
+ *
+ * Copyright (c) 2017 Michael Davidsaver
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the LICENSE file in the top-level directory.
+ */
+#include 
+
+#include "qemu/osdep.h"
+#include "qemu/bcd.h"
+#include "qemu/cutils.h"
+#include "qemu/timer.h"
+#include "libqtest.h"
+#include "libqos/libqos.h"
+#include "libqos/i2c.h"
+
+#define IMX25_I2C_0_BASE 0x43F8
+#define DS1338_ADDR 0x68
+
+static I2CAdapter *i2c;
+static uint8_t addr;
+static bool use_century;
+
+static
+time_t rtc_gettime(void)
+{
+struct tm parts;
+uint8_t buf[7];
+
+buf[0] = 0;
+i2c_send(i2c, addr, buf, 1);
+i2c_recv(i2c, addr, buf, 7);
+
+parts.tm_sec = from_bcd(buf[0]);
+parts.tm_min = from_bcd(buf[1]);
+if (buf[2] & 0x40) {
+/* 12 hour */
+parts.tm_hour = from_bcd(buf[2] & 0x1f) % 12u;
+if (buf[2] & 0x20) {
+parts.tm_hour += 12u;
+}
+} else {
+/* 24 hour */
+parts.tm_hour = from_bcd(buf[2] & 0x3f);
+}
+parts.tm_wday = from_bcd(buf[3]);
+parts.tm_mday = from_bcd(buf[4]);
+parts.tm_mon =  from_bcd((buf[5] & 0x1f) - 1u);
+parts.tm_year = from_bcd(buf[6]);
+if (!use_century || (buf[5] & 0x80)) {
+parts.tm_year += 100u;
+}
+
+return mktimegm();
+}
+
+/* read back and compare with current system time */
+static
+void test_rtc_current(void)
+{
+uint8_t buf;
+time_t expected, actual;
+
+/* magic address to zero RTC time offset
+ * as tests may be run in any order
+ */
+buf = 0xff;
+i2c_send(i2c, addr, , 1);
+
+actual = time(NULL);
+/* new second may start here */
+expected = rtc_gettime();
+g_assert_cmpuint(expected, <=, actual + 1);
+g_assert_cmpuint(expected, >=, actual);
+}
+
+
+static uint8_t test_time_24[8] = {
+0, /* address */
+/* Wed, 22 Nov 2017 18:30:53 + */
+0x53,
+0x30,
+0x18, /* 6 PM in 24 hour mode */
+0x03, /* monday is our day 1 */
+0x22,
+0x11 | 0x80,
+0x17,
+};
+
+static uint8_t test_time_12[8] = {
+0, /* address */
+/* Wed, 22 Nov 2017 18:30:53 + */
+0x53,
+0x30,
+0x67, /* 6 PM in 12 hour mode */
+0x03, /* monday is our day 1 */
+0x22,
+0x11 | 0x80,
+0x17,
+};
+
+/* write in and read back known time */
+static
+void test_rtc_set(const void *raw)
+{
+const uint8_t *testtime = raw;
+uint8_t buf[7];
+unsigned retry = 2;
+
+for (; retry; retry--) {
+i2c_send(i2c, addr, testtime, 8);
+/* new second may start here */
+i2c_send(i2c, addr, testtime, 1);
+i2c_recv(i2c, addr, buf, 7);
+
+if (testtime[1] == buf[0]) {
+break;
+}
+/* we raced start of second, retry */
+};
+
+g_assert_cmpuint(testtime[1], ==, buf[0]);
+g_assert_cmpuint(testtime[2], ==, buf[1]);
+g_assert_cmpuint(testtime[3], ==, buf[2]);
+g_assert_cmpuint(testtime[4], ==, buf[3]);
+g_assert_cmpuint(testtime[5], ==, buf[4]);
+if (

[Qemu-devel] [PATCH 11/17] e500: derive baud from CCB clock

2017-11-26 Thread Michael Davidsaver
The CCB (Complex Core Bus) clock is the reference for the DUARTs
with an extra divide by 16.

>From the mpc8540, mpc8544, and P2010 ref manuals.
CCB=333MHz, with divider=0x87a gives ~9600 baud.
333e6 Hz/(16*0x87a) = 9591 Hz.
This is verified with a real mpc8540.

The existing value for the mpc8544ds boards is replaced.
Previously the uart "clock-frequency" device tree node
was left as zero, and at some point either u-boot or Linux
picks a value inconsistent with the frequency
given to serial_mm_init().
The FIFO timeout calculated from this was incorrect.

Now use an arbitrary (valid) CCB frequency of 333MHz
in the device tree and for the UART.

Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 hw/ppc/e500.c  |  9 -
 hw/ppc/e500_ccsr.c | 16 
 2 files changed, 20 insertions(+), 5 deletions(-)

diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index 2d87d91582..cfd5ed0152 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -49,6 +49,12 @@
 
 #define RAM_SIZES_ALIGN(64UL << 20)
 
+/* Somewhat arbitrarily choosen Complex Core Bus frequency
+ * for our simulation (real freq of mpc8544ds board unknown)
+ * Used in baud rate calculations.
+ */
+#define CCB_FREQ (3)
+
 /* TODO: parameterize
  * Some CCSR offsets duplicated in e500_ccsr.c
  */
@@ -113,7 +119,7 @@ static void dt_serial_create(void *fdt, unsigned long long 
offset,
 qemu_fdt_setprop_string(fdt, ser, "compatible", "ns16550");
 qemu_fdt_setprop_cells(fdt, ser, "reg", offset, 0x100);
 qemu_fdt_setprop_cell(fdt, ser, "cell-index", idx);
-qemu_fdt_setprop_cell(fdt, ser, "clock-frequency", 0);
+qemu_fdt_setprop_cell(fdt, ser, "clock-frequency", CCB_FREQ);
 qemu_fdt_setprop_cells(fdt, ser, "interrupts", 42, 2);
 qemu_fdt_setprop_phandle(fdt, ser, "interrupt-parent", mpic);
 qemu_fdt_setprop_string(fdt, "/aliases", alias, ser);
@@ -759,6 +765,7 @@ void ppce500_init(MachineState *machine, PPCE500Params 
*params)
 dev = qdev_create(NULL, "e500-ccsr");
 object_property_add_child(qdev_get_machine(), "e500-ccsr",
   OBJECT(dev), NULL);
+qdev_prop_set_uint32(dev, "ccb-freq", CCB_FREQ);
 qdev_prop_set_uint32(dev, "mpic-model", params->mpic_version);
 qdev_prop_set_uint32(dev, "base", params->ccsrbar_base);
 qdev_prop_set_uint32(dev, "ram-size", ram_size);
diff --git a/hw/ppc/e500_ccsr.c b/hw/ppc/e500_ccsr.c
index f1adba4e54..c479ed91ee 100644
--- a/hw/ppc/e500_ccsr.c
+++ b/hw/ppc/e500_ccsr.c
@@ -69,6 +69,7 @@ typedef struct {
 uint32_t merrd;
 
 uint32_t porpllsr;
+uint32_t ccb_freq;
 
 DeviceState *pic;
 } CCSRState;
@@ -272,15 +273,21 @@ static void e500_ccsr_realize(DeviceState *dev, Error 
**errp)
 /* Note: MPIC internal interrupts are offset by 16 */
 
 /* DUARTS */
+/* for mpc8540, mpc8544, and P2010 (unmodeled), the DUART reference clock
+ * is the CCB clock divided by 16.
+ * So baud rate is CCB/(16*divider)
+ */
 if (serial_hds[0]) {
-serial_mm_init(>iomem, E500_DUART_OFFSET(0),
-   0, qdev_get_gpio_in(ccsr->pic, 16 + 26), 399193,
+serial_mm_init(>iomem, E500_DUART_OFFSET(0), 0,
+   qdev_get_gpio_in(ccsr->pic, 16 + 26),
+   ccsr->ccb_freq / 16u,
serial_hds[0], DEVICE_BIG_ENDIAN);
 }
 
 if (serial_hds[1]) {
-serial_mm_init(>iomem, E500_DUART_OFFSET(1),
-   0, qdev_get_gpio_in(ccsr->pic, 16 + 26), 399193,
+serial_mm_init(>iomem, E500_DUART_OFFSET(1), 0,
+   qdev_get_gpio_in(ccsr->pic, 16 + 26),
+   ccsr->ccb_freq / 16u,
serial_hds[1], DEVICE_BIG_ENDIAN);
 }
 
@@ -290,6 +297,7 @@ static Property e500_ccsr_props[] = {
 DEFINE_PROP_UINT32("base", CCSRState, defbase, 0xff70),
 DEFINE_PROP_UINT32("ram-size", CCSRState, ram_size, 0),
 DEFINE_PROP_UINT32("porpllsr", CCSRState, porpllsr, 0),
+DEFINE_PROP_UINT32("ccb-freq", CCSRState, ccb_freq, 3u),
 /* "mpic-model" aliased from MPIC */
 DEFINE_PROP_END_OF_LIST()
 };
-- 
2.11.0




[Qemu-devel] [PATCH 01/17] openpic: debug w/ info_report()

2017-11-26 Thread Michael Davidsaver
Replace *printf() with *_report().
Remove trailing new lines.

Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 hw/intc/openpic.c | 102 +++---
 1 file changed, 51 insertions(+), 51 deletions(-)

diff --git a/hw/intc/openpic.c b/hw/intc/openpic.c
index 10d6e871fb..9159a06f07 100644
--- a/hw/intc/openpic.c
+++ b/hw/intc/openpic.c
@@ -46,6 +46,7 @@
 #include "qapi/qmp/qerror.h"
 #include "qemu/log.h"
 #include "qemu/timer.h"
+#include "qemu/error-report.h"
 
 //#define DEBUG_OPENPIC
 
@@ -58,8 +59,7 @@ static const int debug_openpic = 0;
 static int get_current_cpu(void);
 #define DPRINTF(fmt, ...) do { \
 if (debug_openpic) { \
-printf("Core%d: ", get_current_cpu()); \
-printf(fmt , ## __VA_ARGS__); \
+info_report("Core%d: " fmt, get_current_cpu(), ## __VA_ARGS__); \
 } \
 } while (0)
 
@@ -173,7 +173,7 @@ static int inttgt_to_output(int inttgt)
 }
 }
 
-fprintf(stderr, "%s: unsupported inttgt %d\n", __func__, inttgt);
+error_report("%s: unsupported inttgt %d", __func__, inttgt);
 return OPENPIC_OUTPUT_INT;
 }
 
@@ -372,7 +372,7 @@ static void IRQ_check(OpenPICState *opp, IRQQueue *q)
 break;
 }
 
-DPRINTF("IRQ_check: irq %d set ivpr_pr=%d pr=%d\n",
+DPRINTF("IRQ_check: irq %d set ivpr_pr=%d pr=%d",
 irq, IVPR_PRIORITY(opp->src[irq].ivpr), priority);
 
 if (IVPR_PRIORITY(opp->src[irq].ivpr) > priority) {
@@ -403,11 +403,11 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, 
int n_IRQ,
 dst = >dst[n_CPU];
 src = >src[n_IRQ];
 
-DPRINTF("%s: IRQ %d active %d was %d\n",
+DPRINTF("%s: IRQ %d active %d was %d",
 __func__, n_IRQ, active, was_active);
 
 if (src->output != OPENPIC_OUTPUT_INT) {
-DPRINTF("%s: output %d irq %d active %d was %d count %d\n",
+DPRINTF("%s: output %d irq %d active %d was %d count %d",
 __func__, src->output, n_IRQ, active, was_active,
 dst->outputs_active[src->output]);
 
@@ -417,13 +417,13 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, 
int n_IRQ,
  */
 if (active) {
 if (!was_active && dst->outputs_active[src->output]++ == 0) {
-DPRINTF("%s: Raise OpenPIC output %d cpu %d irq %d\n",
+DPRINTF("%s: Raise OpenPIC output %d cpu %d irq %d",
 __func__, src->output, n_CPU, n_IRQ);
 qemu_irq_raise(dst->irqs[src->output]);
 }
 } else {
 if (was_active && --dst->outputs_active[src->output] == 0) {
-DPRINTF("%s: Lower OpenPIC output %d cpu %d irq %d\n",
+DPRINTF("%s: Lower OpenPIC output %d cpu %d irq %d",
 __func__, src->output, n_CPU, n_IRQ);
 qemu_irq_lower(dst->irqs[src->output]);
 }
@@ -446,7 +446,7 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, 
int n_IRQ,
 IRQ_check(opp, >raised);
 
 if (active && priority <= dst->ctpr) {
-DPRINTF("%s: IRQ %d priority %d too low for ctpr %d on CPU %d\n",
+DPRINTF("%s: IRQ %d priority %d too low for ctpr %d on CPU %d",
 __func__, n_IRQ, priority, dst->ctpr, n_CPU);
 active = 0;
 }
@@ -454,10 +454,10 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, 
int n_IRQ,
 if (active) {
 if (IRQ_get_next(opp, >servicing) >= 0 &&
 priority <= dst->servicing.priority) {
-DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d\n",
+DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d",
 __func__, n_IRQ, dst->servicing.next, n_CPU);
 } else {
-DPRINTF("%s: Raise OpenPIC INT output cpu %d irq %d/%d\n",
+DPRINTF("%s: Raise OpenPIC INT output cpu %d irq %d/%d",
 __func__, n_CPU, n_IRQ, dst->raised.next);
 qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]);
 }
@@ -465,12 +465,12 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, 
int n_IRQ,
 IRQ_get_next(opp, >servicing);
 if (dst->raised.priority > dst->ctpr &&
 dst->raised.priority > dst->servicing.priority) {
-DPRINTF("%s: IRQ %d inactive, IRQ %d prio %d above %d/%d, CPU 
%d\n",
+DPRINTF("%s: IRQ %d inactive, IRQ %d prio %d above %d/%d, CPU %d",
 __func__, n_IRQ, dst->raised.next, dst-&

[Qemu-devel] [PATCH 04/17] qtest: add e500_i2c_create()

2017-11-26 Thread Michael Davidsaver
Add interface for testing i2c devices
with PPC e500.

Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 tests/Makefile.include  |  1 +
 tests/libqos/i2c-e500.c | 66 +
 tests/libqos/i2c.h  |  3 +++
 3 files changed, 70 insertions(+)
 create mode 100644 tests/libqos/i2c-e500.c

diff --git a/tests/Makefile.include b/tests/Makefile.include
index c002352134..ad1c219423 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -721,6 +721,7 @@ libqos-pc-obj-y += tests/libqos/malloc-pc.o 
tests/libqos/libqos-pc.o
 libqos-pc-obj-y += tests/libqos/ahci.o
 libqos-omap-obj-y = $(libqos-obj-y) tests/libqos/i2c-omap.o
 libqos-imx-obj-y = $(libqos-obj-y) tests/libqos/i2c-imx.o
+libqos-e500-obj-y = $(libqos-obj-y) tests/libqos/i2c-e500.o
 libqos-usb-obj-y = $(libqos-spapr-obj-y) $(libqos-pc-obj-y) tests/libqos/usb.o
 libqos-virtio-obj-y = $(libqos-spapr-obj-y) $(libqos-pc-obj-y) 
tests/libqos/virtio.o tests/libqos/virtio-pci.o tests/libqos/virtio-mmio.o 
tests/libqos/malloc-generic.o
 
diff --git a/tests/libqos/i2c-e500.c b/tests/libqos/i2c-e500.c
new file mode 100644
index 00..4272ada0a5
--- /dev/null
+++ b/tests/libqos/i2c-e500.c
@@ -0,0 +1,66 @@
+/*
+ * QTest I2C driver
+ *
+ * Copyright (c) 2016 Michael Davidsaver
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#include "qemu/osdep.h"
+#include "libqos/i2c.h"
+
+
+#include "qemu/bswap.h"
+#include "libqtest.h"
+
+typedef struct E500I2C {
+I2CAdapter parent;
+
+uint64_t addr;
+} E500I2C;
+
+static void e500_i2c_send(I2CAdapter *i2c, uint8_t addr,
+  const uint8_t *buf, uint16_t len)
+{
+E500I2C *s = (E500I2C *)i2c;
+
+writeb(s->addr + 0x8, 0xb0); /* Enable and START a write */
+writeb(s->addr + 0x10, addr & 0xfe); /* Send address for write */
+
+while (len--) {
+writeb(s->addr + 0x10, *buf++);
+}
+
+writeb(s->addr + 0x8, 0x80); /* STOP but leave enabled */
+}
+
+static void e500_i2c_recv(I2CAdapter *i2c, uint8_t addr,
+  uint8_t *buf, uint16_t len)
+{
+E500I2C *s = (E500I2C *)i2c;
+
+writeb(s->addr + 0x8, 0xa0); /* Enable and START a read */
+writeb(s->addr + 0x10, addr | 1); /* Send address for read */
+
+/* reads are "pipelined" so the initial value is junk */
+readb(s->addr + 0x10);
+
+while (len--) {
+*buf++ = readb(s->addr + 0x10);
+}
+
+writeb(s->addr + 0x8, 0x80); /* STOP but leave enabled */
+}
+
+I2CAdapter *e500_i2c_create(uint64_t ccsr_base)
+{
+E500I2C *s = g_malloc0(sizeof(*s));
+I2CAdapter *i2c = (I2CAdapter *)s;
+
+s->addr = ccsr_base + 0x3000;
+
+i2c->send = e500_i2c_send;
+i2c->recv = e500_i2c_recv;
+
+return i2c;
+}
diff --git a/tests/libqos/i2c.h b/tests/libqos/i2c.h
index 6e648f922a..40c59a7997 100644
--- a/tests/libqos/i2c.h
+++ b/tests/libqos/i2c.h
@@ -29,4 +29,7 @@ I2CAdapter *omap_i2c_create(uint64_t addr);
 /* libi2c-imx.c */
 I2CAdapter *imx_i2c_create(uint64_t addr);
 
+/* i2c-e500.c */
+I2CAdapter *e500_i2c_create(uint64_t ccsr_base);
+
 #endif
-- 
2.11.0




[Qemu-devel] [PATCH 10/17] e500: move uarts CCSR

2017-11-26 Thread Michael Davidsaver
Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 hw/ppc/e500.c  | 13 -
 hw/ppc/e500_ccsr.c | 18 ++
 2 files changed, 18 insertions(+), 13 deletions(-)

diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index 1872bb8eaa..2d87d91582 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -22,7 +22,6 @@
 #include "net/net.h"
 #include "qemu/config-file.h"
 #include "hw/hw.h"
-#include "hw/char/serial.h"
 #include "hw/pci/pci.h"
 #include "hw/boards.h"
 #include "sysemu/sysemu.h"
@@ -770,18 +769,6 @@ void ppce500_init(MachineState *machine, PPCE500Params 
*params)
 mpicdev = DEVICE(object_resolve_path("/machine/pic", 0));
 assert(mpicdev);
 
-/* Serial */
-if (serial_hds[0]) {
-serial_mm_init(ccsr_addr_space, MPC8544_SERIAL0_REGS_OFFSET,
-   0, qdev_get_gpio_in(mpicdev, 42), 399193,
-   serial_hds[0], DEVICE_BIG_ENDIAN);
-}
-
-if (serial_hds[1]) {
-serial_mm_init(ccsr_addr_space, MPC8544_SERIAL1_REGS_OFFSET,
-   0, qdev_get_gpio_in(mpicdev, 42), 399193,
-   serial_hds[1], DEVICE_BIG_ENDIAN);
-}
 
 /* PCI */
 dev = qdev_create(NULL, "e500-pcihost");
diff --git a/hw/ppc/e500_ccsr.c b/hw/ppc/e500_ccsr.c
index 68d952794e..f1adba4e54 100644
--- a/hw/ppc/e500_ccsr.c
+++ b/hw/ppc/e500_ccsr.c
@@ -31,6 +31,7 @@
 #include "sysemu/sysemu.h"
 #include "sysemu/kvm.h"
 #include "hw/sysbus.h"
+#include "hw/char/serial.h"
 #include "hw/ppc/openpic.h"
 
 /* E500_ denotes registers common to all */
@@ -45,6 +46,8 @@
 #define E500_ERR_DETECT  (0x2e40)
 #define E500_ERR_DISABLE (0x2e44)
 
+#define E500_DUART_OFFSET(N) (0x4500 + (N) * 0x100)
+
 #define E500_PORPLLSR(0xE)
 #define E500_PVR (0xE00A0)
 #define E500_SVR (0xE00A4)
@@ -266,6 +269,21 @@ static void e500_ccsr_realize(DeviceState *dev, Error 
**errp)
 
 memory_region_add_subregion(>iomem, E500_MPIC_OFFSET,
 sysbus_mmio_get_region(pic, 0));
+/* Note: MPIC internal interrupts are offset by 16 */
+
+/* DUARTS */
+if (serial_hds[0]) {
+serial_mm_init(>iomem, E500_DUART_OFFSET(0),
+   0, qdev_get_gpio_in(ccsr->pic, 16 + 26), 399193,
+   serial_hds[0], DEVICE_BIG_ENDIAN);
+}
+
+if (serial_hds[1]) {
+serial_mm_init(>iomem, E500_DUART_OFFSET(1),
+   0, qdev_get_gpio_in(ccsr->pic, 16 + 26), 399193,
+   serial_hds[1], DEVICE_BIG_ENDIAN);
+}
+
 }
 
 static Property e500_ccsr_props[] = {
-- 
2.11.0




[Qemu-devel] [PATCH 00/17] Add MVME3100 PPC SBC v2

2017-11-26 Thread Michael Davidsaver
Changes since previous iteration.

openpic: debug w/ info_report()

  New

i2c: start trace-events
i2c: add mpc8540 i2c controller

  Debugging cleanup and fix a spurious warning triggered by Linux guests.

qtest: add e500_i2c_create()

  Unchanged

timer: generalize Dallas/Maxim RTC i2c devices
tests: rewrite testing for DS RTC devices

  Combined models of ds1338 and ds1375 RTCs, along with untested support
  for some similar chips.
  Test case for setting time to exercise offset calculation.

e500: fix pci host bridge class/type

  After further investigation, revert the change which caused the host bridge
  to be identified as a pci-pci bridge.

e500: additional CCSR registers

  Also update CPUPPCState::mpic_iack when changing CCSRBAR.

e500: additional CCSR registers
e500: move mpic under CCSR
e500: move uarts CCSR
e500: derive baud from CCB clock
e500: add i2c controller to CCSR
e500: move PCI host bridge into CCSR

  Moved MPIC, UARTS, and PCI host bridge under CCSR device.
  Many of the PPCE500Params members become properties of the CCSR device.

e500: split mpc8544ds specific initialization

  Split ppce500_init() to create mpc85xx_init().
  mpc85xx_init() has all the bits used by the exist mpc8544ds and ppce500 
machines,
  but not by the new mvme3100 machine (which doesn't use PPCE500Params).

ppc: add mvme3100 machine

  Minor changes related to ppce500_init() changes

tests: run ds-rtc-i2c-test w/ ppc/mvme3100

  New

tests: add mvme3100-test

  Unchanged

Michael Davidsaver (17):
  openpic: debug w/ info_report()
  i2c: start trace-events
  i2c: add mpc8540 i2c controller
  qtest: add e500_i2c_create()
  timer: generalize Dallas/Maxim RTC i2c devices
  tests: rewrite testing for DS RTC devices
  e500: fix pci host bridge class/type
  e500: additional CCSR registers
  e500: move mpic under CCSR
  e500: move uarts CCSR
  e500: derive baud from CCB clock
  e500: add i2c controller to CCSR
  e500: move PCI host bridge into CCSR
  e500: split mpc8544ds specific initialization
  ppc: add mvme3100 machine
  tests: run ds-rtc-i2c-test w/ ppc/mvme3100
  tests: add mvme3100-test

 Makefile.objs   |   1 +
 default-configs/arm-softmmu.mak |   2 +-
 default-configs/ppc-softmmu.mak |   1 +
 hw/i2c/Makefile.objs|   1 +
 hw/i2c/mpc8540_i2c.c| 307 +
 hw/i2c/trace-events |   7 +
 hw/intc/openpic.c   | 102 +++---
 hw/pci-host/ppce500.c   |   5 -
 hw/ppc/Makefile.objs|   1 +
 hw/ppc/e500.c   | 175 +++---
 hw/ppc/e500.h   |   3 +-
 hw/ppc/e500_ccsr.c  | 246 -
 hw/ppc/e500plat.c   |   2 +-
 hw/ppc/mpc8544ds.c  |   2 +-
 hw/ppc/mvme3100.c   | 740 
 hw/ppc/mvme3100_cpld.c  | 192 +++
 hw/timer/Makefile.objs  |   2 +-
 hw/timer/ds-rtc-i2c.c   | 461 +
 hw/timer/ds1338.c   | 239 -
 tests/Makefile.include  |   9 +-
 tests/ds-rtc-i2c-test.c | 170 +
 tests/ds1338-test.c |  77 -
 tests/libqos/i2c-e500.c |  66 
 tests/libqos/i2c.h  |   3 +
 tests/mvme3100-test.c   |  79 +
 25 files changed, 2376 insertions(+), 517 deletions(-)
 create mode 100644 hw/i2c/mpc8540_i2c.c
 create mode 100644 hw/i2c/trace-events
 create mode 100644 hw/ppc/mvme3100.c
 create mode 100644 hw/ppc/mvme3100_cpld.c
 create mode 100644 hw/timer/ds-rtc-i2c.c
 delete mode 100644 hw/timer/ds1338.c
 create mode 100644 tests/ds-rtc-i2c-test.c
 delete mode 100644 tests/ds1338-test.c
 create mode 100644 tests/libqos/i2c-e500.c
 create mode 100644 tests/mvme3100-test.c

-- 
2.11.0




[Qemu-devel] [PATCH 02/17] i2c: start trace-events

2017-11-26 Thread Michael Davidsaver
Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 Makefile.objs   | 1 +
 hw/i2c/trace-events | 1 +
 2 files changed, 2 insertions(+)
 create mode 100644 hw/i2c/trace-events

diff --git a/Makefile.objs b/Makefile.objs
index 285c6f3c15..984ae8ecba 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -155,6 +155,7 @@ trace-events-subdirs += hw/arm
 trace-events-subdirs += hw/alpha
 trace-events-subdirs += hw/xen
 trace-events-subdirs += hw/ide
+trace-events-subdirs += hw/i2c
 trace-events-subdirs += ui
 trace-events-subdirs += audio
 trace-events-subdirs += net
diff --git a/hw/i2c/trace-events b/hw/i2c/trace-events
new file mode 100644
index 00..9284b1fbad
--- /dev/null
+++ b/hw/i2c/trace-events
@@ -0,0 +1 @@
+# See docs/devel/tracing.txt for syntax documentation.
-- 
2.11.0




Re: [Qemu-devel] [PATCH 01/12] e500: add board config options

2017-11-22 Thread Michael Davidsaver
On 11/21/2017 09:28 PM, David Gibson wrote:
> On Sun, Nov 19, 2017 at 09:24:09PM -0600, Michael Davidsaver wrote:
>> allow board code to skip common NIC and guest image setup
>> and configure decrementor frequency.
>> Existing boards unchanged.
>>
>> Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
> 
> So, it's spelled "decrementer".
> 
> Other than that, the patch looks correct.  However having a big common
> function for overall init with a pile of ad-hoc configuration
> parameters is usually not a great way to go.  I think what we want
> instead is to eliminate ppce500_init(), instead doing the setup logic
> separately in each of the e500 machines.   The large common slabs of
> code can be helpers in e500.c, but the overall logic - including most
> of the things controlled by the current params - would be under the
> individual machine's control.

I agree that ppce500_init() is unwieldy, and am willing to spend some
time on cleanup.  I'm just not sure what to do.

I can see moving initialization of at least the serial, i2c, gpio, and
possibly MPIC and PCI host bridge into the e500-ccsr class.

I'm not sure what to do with all the device tree construction code in
e500.c, which has a bunch of hard coded register offsets.  A comment
here summarizes the problem nicely.

> /* TODO: parameterize */
> #define MPC8544_CCSRBAR_SIZE   0x0010ULL
> #define MPC8544_MPIC_REGS_OFFSET   0x4ULL

It seems desirable to avoid having these offsets appear in two different
files, which could allow them to get out of sync.

I had the idea of using an Interface to split up device tree
construction, and was encouraged to find PnvXScomInterfaceClass which
seems be a way of combining device tree construction in a device class.
Is this the way to go?

Some guidance would be appreciated.

Michael


>> ---
>>  hw/ppc/e500.c  | 8 ++--
>>  hw/ppc/e500.h  | 3 +++
>>  hw/ppc/e500plat.c  | 1 +
>>  hw/ppc/mpc8544ds.c | 1 +
>>  4 files changed, 11 insertions(+), 2 deletions(-)
>>
>> diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
>> index 5cf0dabef3..9e7e1b29c4 100644
>> --- a/hw/ppc/e500.c
>> +++ b/hw/ppc/e500.c
>> @@ -826,7 +826,7 @@ void ppce500_init(MachineState *machine, PPCE500Params 
>> *params)
>>  env->mpic_iack = params->ccsrbar_base +
>>   MPC8544_MPIC_REGS_OFFSET + 0xa0;
>>  
>> -ppc_booke_timers_init(cpu, 4, PPC_TIMER_E500);
>> +ppc_booke_timers_init(cpu, params->decrementor_freq, 
>> PPC_TIMER_E500);
>>  
>>  /* Register reset handler */
>>  if (!i) {
>> @@ -899,7 +899,7 @@ void ppce500_init(MachineState *machine, PPCE500Params 
>> *params)
>>  if (!pci_bus)
>>  printf("couldn't create PCI controller!\n");
>>  
>> -if (pci_bus) {
>> +if (pci_bus && !params->tsec_nic) {
>>  /* Register network interfaces. */
>>  for (i = 0; i < nb_nics; i++) {
>>  pci_nic_init_nofail(_table[i], pci_bus, "virtio", NULL);
>> @@ -948,6 +948,10 @@ void ppce500_init(MachineState *machine, PPCE500Params 
>> *params)
>>  sysbus_mmio_get_region(s, 0));
>>  }
>>  
>> +if (params->skip_load) {
>> +return;
>> +}
>> +
>>  /* Load kernel. */
>>  if (machine->kernel_filename) {
>>  kernel_base = cur_base;
>> diff --git a/hw/ppc/e500.h b/hw/ppc/e500.h
>> index 70ba1d8f4f..40f72f2de2 100644
>> --- a/hw/ppc/e500.h
>> +++ b/hw/ppc/e500.h
>> @@ -22,6 +22,9 @@ typedef struct PPCE500Params {
>>  hwaddr pci_mmio_base;
>>  hwaddr pci_mmio_bus_base;
>>  hwaddr spin_base;
>> +uint32_t decrementor_freq; /* in Hz */
>> +bool skip_load;
>> +bool tsec_nic;
>>  } PPCE500Params;
>>  
>>  void ppce500_init(MachineState *machine, PPCE500Params *params);
>> diff --git a/hw/ppc/e500plat.c b/hw/ppc/e500plat.c
>> index e59e80fb9e..3d07987bd1 100644
>> --- a/hw/ppc/e500plat.c
>> +++ b/hw/ppc/e500plat.c
>> @@ -47,6 +47,7 @@ static void e500plat_init(MachineState *machine)
>>  .pci_mmio_base = 0xCULL,
>>  .pci_mmio_bus_base = 0xE000ULL,
>>  .spin_base = 0xFEF00ULL,
>> +.decrementor_freq = 4,
>>  };
>>  
>>  /* Older KVM versions don't support EPR which breaks guests when we 
>> announce
>> diff --git a/hw/ppc/mpc8544ds.c b/hw/ppc/mpc8544ds.c
>> index 1717953ec7..6d9931c475 100644
>> --- a/hw/ppc/mpc8544ds.c
>> +++ b/hw/ppc/mpc8544ds.c
>> @@ -40,6 +40,7 @@ static void mpc8544ds_init(MachineState *machine)
>>  .pci_mmio_bus_base = 0xC000ULL,
>>  .pci_pio_base = 0xE100ULL,
>>  .spin_base = 0xEF00ULL,
>> +.decrementor_freq = 4,
>>  };
>>  
>>  if (machine->ram_size > 0xc000) {
> 




signature.asc
Description: OpenPGP digital signature


Re: [Qemu-devel] [PATCH 08/12] e500: add mpc8540 i2c controller to ccsr

2017-11-22 Thread Michael Davidsaver
On 11/21/2017 10:08 PM, David Gibson wrote:
> On Sun, Nov 19, 2017 at 09:24:16PM -0600, Michael Davidsaver wrote:
>> Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
> 
> You're adding what seems to be a fairly specific device to the general
> e500 init - this again suggests that it should be split, putting
> creation of devices under control of individual machines.

I'll address the ppce500_init() part of this question separately.

In addition to the MPC8540, I find that documentation for the MPC8544
(modeled) and P2020 (un-modeled) show the same i2c controller registers.
 So I think it's reasonable for the generic ppce500 machine to have it
as well.

For what it's worth, the Linux driver for this unit
(drivers/i2c/busses/i2c-mpc.c) lists compatibility with a number of
other freescale SoCs with only some differences in clock selection (not
modeled).  The description for the module is:

> MODULE_DESCRIPTION("I2C-Bus adapter for MPC107 bridge and "
>"MPC824x/83xx/85xx/86xx/512x/52xx processors");



>> ---
>>  hw/ppc/e500.c | 8 
>>  1 file changed, 8 insertions(+)
>>
>> diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
>> index 6f77844303..bef7d313d4 100644
>> --- a/hw/ppc/e500.c
>> +++ b/hw/ppc/e500.c
>> @@ -861,6 +861,14 @@ void ppce500_init(MachineState *machine, PPCE500Params 
>> *params)
>>  qdev_init_nofail(dev);
>>  ccsr_addr_space = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
>>  
>> +dev = qdev_create(NULL, "mpc8540-i2c");
>> +object_property_add_child(qdev_get_machine(), "i2c[*]",
>> +  OBJECT(dev), NULL);
>> +qdev_init_nofail(dev);
>> +s = SYS_BUS_DEVICE(dev);
>> +memory_region_add_subregion(ccsr_addr_space, 0x3000,
>> +sysbus_mmio_get_region(s, 0));
>> +
>>  mpicdev = ppce500_init_mpic(machine, params, ccsr_addr_space, irqs);
>>  
>>  /* Serial */
> 




signature.asc
Description: OpenPGP digital signature


Re: [Qemu-devel] [PATCH 00/12] Add MVME3100 PPC SBC

2017-11-21 Thread Michael Davidsaver
On 11/21/2017 10:12 PM, David Gibson wrote:
...
> I've applied several patches from this series to ppc-for-2.12, others
> I've commented on.  If you could address the comments and rebase
> what's left on ppc-for-2.12, that would be great.

Will do.



signature.asc
Description: OpenPGP digital signature


Re: [Qemu-devel] [PATCH 03/12] e500: note possible bug with host bridge

2017-11-21 Thread Michael Davidsaver
On 11/21/2017 09:46 PM, David Gibson wrote:
> On Sun, Nov 19, 2017 at 09:24:11PM -0600, Michael Davidsaver wrote:
>> Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
> 
> I'm not sure if you're saying you think there is a hardware bug which
> we're faithfully emulating, or a software bug.

I mean that the emulation is incorrect in that it just sets
config[PCI_HEADER_TYPE]==PCI_HEADER_TYPE_BRIDGE but does none of the
other initialization of the base-pci-bridge class.

I specifically observed Linux being confused by the fact that the
primary, secondary, and subordinate bus registers don't work right
because they're actually the BAR2 address register.

Further, it seems odd that a host bridge would identify itself as a
pci-to-pci bridge.  The mpc8540 doesn't.  The mpc8544 docs aren't clear,
and I don't have a real one to test.  My inclination is to remove the
line changing PCI_HEADER_TYPE, but I'm hesitant about breaking things.
Especially since this doesn't trigger mis-behavior in Linux or RTEMS.

>> ---
>>  hw/pci-host/ppce500.c | 3 +++
>>  1 file changed, 3 insertions(+)
>>
>> diff --git a/hw/pci-host/ppce500.c b/hw/pci-host/ppce500.c
>> index f2d108bc8a..0e2833bd98 100644
>> --- a/hw/pci-host/ppce500.c
>> +++ b/hw/pci-host/ppce500.c
>> @@ -424,6 +424,9 @@ static void e500_pcihost_bridge_realize(PCIDevice *d, 
>> Error **errp)
>>  MemoryRegion *ccsr_mr = sysbus_mmio_get_region(ccsr, 0);
>>  
>>  pci_config_set_class(d->config, PCI_CLASS_BRIDGE_PCI);
>> +/* BUG? identifies as PCI_HEADER_TYPE_BRIDGE but uses
>> + * standard device config read/write
>> + */
>>  d->config[PCI_HEADER_TYPE] =
>>  (d->config[PCI_HEADER_TYPE] & PCI_HEADER_TYPE_MULTI_FUNCTION) |
>>  PCI_HEADER_TYPE_BRIDGE;
> 




signature.asc
Description: OpenPGP digital signature


[Qemu-devel] [PATCH 10/12] timer: add ds1375 RTC

2017-11-19 Thread Michael Davidsaver
only basic functionality implemented (read time and sram).
no set time or alarms.

Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 default-configs/ppc-softmmu.mak |   1 +
 hw/timer/Makefile.objs  |   1 +
 hw/timer/ds1375-i2c.c   | 293 
 3 files changed, 295 insertions(+)
 create mode 100644 hw/timer/ds1375-i2c.c

diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak
index bb225c6e46..04bfa79154 100644
--- a/default-configs/ppc-softmmu.mak
+++ b/default-configs/ppc-softmmu.mak
@@ -52,3 +52,4 @@ CONFIG_SERIAL_ISA=y
 CONFIG_MC146818RTC=y
 CONFIG_ISA_TESTDEV=y
 CONFIG_RS6000_MC=y
+CONFIG_DS1375=y
diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs
index 8c19eac3b6..6521d47367 100644
--- a/hw/timer/Makefile.objs
+++ b/hw/timer/Makefile.objs
@@ -4,6 +4,7 @@ common-obj-$(CONFIG_ARM_V7M) += armv7m_systick.o
 common-obj-$(CONFIG_A9_GTIMER) += a9gtimer.o
 common-obj-$(CONFIG_CADENCE) += cadence_ttc.o
 common-obj-$(CONFIG_DS1338) += ds1338.o
+common-obj-$(CONFIG_DS1375) += ds1375-i2c.o
 common-obj-$(CONFIG_HPET) += hpet.o
 common-obj-$(CONFIG_I8254) += i8254_common.o i8254.o
 common-obj-$(CONFIG_M48T59) += m48t59.o
diff --git a/hw/timer/ds1375-i2c.c b/hw/timer/ds1375-i2c.c
new file mode 100644
index 00..dba9cc05c4
--- /dev/null
+++ b/hw/timer/ds1375-i2c.c
@@ -0,0 +1,293 @@
+/*
+ * Dallas/Maxim ds1375 I2C RTC w/ SRAM
+ *
+ * Copyright (c) 2017 Michael Davidsaver
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the LICENSE file in the top-level directory.
+ *
+ * Only basic functionality is modeled (time and user SRAM).
+ * Alarms not modeled.
+ */
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "qemu/log.h"
+#include "qemu/timer.h"
+#include "qemu/bcd.h"
+#include "hw/hw.h"
+#include "hw/registerfields.h"
+#include "hw/i2c/i2c.h"
+
+#define DEBUG_DS1375
+
+#ifdef DEBUG_DS1375
+#define DPRINTK(FMT, ...) printf(TYPE_DS1375 " : " FMT, ## __VA_ARGS__)
+#else
+#define DPRINTK(FMT, ...) do {} while (0)
+#endif
+
+#define LOG(MSK, FMT, ...) qemu_log_mask(MSK, TYPE_DS1375 " : " FMT, \
+## __VA_ARGS__)
+
+#define TYPE_DS1375 "ds1375"
+#define DS1375(obj) OBJECT_CHECK(DS1375State, (obj), TYPE_DS1375)
+
+#define DS1375_REGSIZE 0x20
+
+#define R_SEC   (0x0)
+#define R_MIN   (0x1)
+#define R_HOUR  (0x2)
+#define R_WDAY  (0x3)
+#define R_DATE  (0x4)
+#define R_MONTH (0x5)
+#define R_YEAR  (0x6)
+#define R_A1SEC   (0x7)
+#define R_A1MIN   (0x8)
+#define R_A1HOUR  (0x9)
+#define R_A1DAY   (0xa)
+#define R_A2SEC   (0xb)
+#define R_A2MIN   (0xc)
+#define R_A2HOUR  (0xd)
+#define R_CTRL  (0xe)
+#define R_STS   (0xf)
+
+FIELD(HOUR, SET12, 6, 1)
+FIELD(HOUR, HOUR24, 0, 6)
+FIELD(HOUR, AMPM, 5, 1)
+FIELD(HOUR, HOUR12, 0, 5)
+
+FIELD(MONTH, MONTH, 0, 5)
+FIELD(MONTH, CENTURY, 7, 1)
+
+FIELD(CTRL, ECLK, 7, 1)
+FIELD(CTRL, CLKSEL, 5, 2)
+FIELD(CTRL, RS, 3, 2)
+FIELD(CTRL, INTCN, 2, 1)
+FIELD(CTRL, A2IE, 1, 1)
+FIELD(CTRL, A1IE, 0, 1)
+
+typedef struct DS1375State {
+I2CSlave parent_obj;
+
+/* register address counter */
+uint8_t addr;
+/* when writing, whether the address has been sent */
+bool addrd;
+
+int time_offset;
+
+uint8_t regs[DS1375_REGSIZE];
+} DS1375State;
+
+/* update current time register if clock enabled */
+static
+void ds1375_latch(DS1375State *ds)
+{
+struct tm now;
+
+if (!ARRAY_FIELD_EX32(ds->regs, CTRL, ECLK)) {
+return;
+}
+
+qemu_get_timedate(, ds->time_offset);
+
+DPRINTK("Current Time %3u/%2u/%u %2u:%2u:%2u (wday %u)\n",
+now.tm_year, now.tm_mon, now.tm_mday,
+now.tm_hour, now.tm_min, now.tm_sec,
+now.tm_wday);
+
+/* ensure unused bits are zero */
+memset(ds->regs, 0, R_YEAR + 1);
+
+ds->regs[R_SEC] = to_bcd(now.tm_sec);
+ds->regs[R_MIN] = to_bcd(now.tm_min);
+
+if (ARRAY_FIELD_EX32(ds->regs, HOUR, SET12) == 0) {
+/* 24 hour */
+ARRAY_FIELD_DP32(ds->regs, HOUR, HOUR24, to_bcd(now.tm_hour));
+} else {
+/* 12 hour am/pm */
+ARRAY_FIELD_DP32(ds->regs, HOUR, AMPM, now.tm_hour >= 12);
+ARRAY_FIELD_DP32(ds->regs, HOUR, HOUR12, to_bcd(now.tm_hour % 12u));
+}
+
+ds->regs[R_WDAY] = now.tm_wday; /* day of the week */
+ds->regs[R_DATE] = to_bcd(now.tm_mday);
+
+ARRAY_FIELD_DP32(ds->regs, MONTH, MONTH, to_bcd(now.tm_mon + 1));
+ARRAY_FIELD_DP32(ds->regs, MONTH, CENTURY, now.tm_year > 99);
+
+ds->regs[R_YEAR] = to_bcd(now.tm_year % 100u);
+
+DPRINTK("Latched time\n");
+}
+
+static
+void ds1375_update(DS1375State *ds)
+{
+struct tm now;
+
+now.tm_sec = from_bcd(ds->regs[R_SEC]);
+now.tm_min = from_bcd(ds->regs[R_MIN]);
+
+if (ARRAY_FIELD_E

[Qemu-devel] [PATCH 11/12] ppc: add mvme3100 machine

2017-11-19 Thread Michael Davidsaver
Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 hw/ppc/Makefile.objs   |   1 +
 hw/ppc/mvme3100.c  | 688 +
 hw/ppc/mvme3100_cpld.c | 192 ++
 3 files changed, 881 insertions(+)
 create mode 100644 hw/ppc/mvme3100.c
 create mode 100644 hw/ppc/mvme3100_cpld.c

diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs
index c1a63d0c39..c1118aaa42 100644
--- a/hw/ppc/Makefile.objs
+++ b/hw/ppc/Makefile.objs
@@ -26,5 +26,6 @@ obj-$(CONFIG_MAC) += mac_newworld.o
 obj-$(CONFIG_E500) += e500.o mpc8544ds.o e500plat.o
 obj-$(CONFIG_E500) += ppce500_spin.o
 obj-$(CONFIG_E500) += e500_ccsr.o
+obj-$(CONFIG_E500) += mvme3100.o mvme3100_cpld.o
 # PowerPC 440 Xilinx ML507 reference board.
 obj-$(CONFIG_XILINX) += virtex_ml507.o
diff --git a/hw/ppc/mvme3100.c b/hw/ppc/mvme3100.c
new file mode 100644
index 00..2e6d428533
--- /dev/null
+++ b/hw/ppc/mvme3100.c
@@ -0,0 +1,688 @@
+/*
+ * MVME3100 board emulation
+ *
+ * Copyright (c) 2015 Michael Davidsaver
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the LICENSE file in the top-level directory.
+ *
+ * This model was developed according to the
+ * MVME3100 Single Board Computer Programmer's Reference
+ * P/N: 6806800G37B
+ * July 2014
+ *
+ * mvme3100-1152
+ *   677MHz core, 256MB ram, 64MB flash
+ * mvme3100-1263
+ *   833MHz core, 512MB ram, 128MB flash
+ *
+ * MOTLoad on mvme3100-1152 says:
+ *   MPU-Type =MPC8540
+ *   MPU-Int Clock Speed  =666MHz
+ *   MPU-CCB Clock Speed  =333MHz
+ *   MPU-DDR Clock Speed  =166MHz
+ *   MPU-PCI Clock Speed  =66MHz, PCI, 64-bit
+ *   MPU-Int Cache(L2) Enabled, 256KB, L2CTL =A8000300
+ *   Reset/Boot Vector=Flash0
+ *   Local Memory Found   =1000 (&268435456)
+ *
+ * MOTLoad on mvme3100-1263 says:
+ *   MPU-Type =MPC8540
+ *   MPU-Int Clock Speed  =833MHz
+ *   MPU-CCB Clock Speed  =333MHz
+ *   MPU-DDR Clock Speed  =166MHz
+ *   MPU-PCI Clock Speed  =66MHz, PCI, 64-bit
+ *   MPU-Int Cache(L2) Enabled, 256KB, L2CTL =A8000300
+ *   Reset/Boot Vector=Flash0
+ *   Local Memory Found   =2000 (&536870912)
+ *
+ * Clock ratios
+ *   CCB/PCI  -> 5/1
+ *   core/CCB -> 2/1 (-1152)
+ *-> 5/2 (-1263)
+ *
+ * The overall memory map is determined by the Local Address Windows.
+ * We do not model the LAWs explicitly.
+ *
+ * MOTLoad configures as follows (a super set of table 1-4)
+ *   (MOTLoad RTOS Version 2.0,  PAL Version 1.2 RM04)
+ * LAW 0, 7 - disabled
+ * LAW 1 - 0x -> 0x7fff - RAM 2G
+ * LAW 2 - 0x8000 -> 0xbfff - PCI 1G
+ * LAW 3 - 0xc000 -> 0xdfff - PCI 512MB
+ * LAW 4 - 0xe000 -> 0xe0ff - PCI 16MB
+ * gap   - 0xe100 -> 0xbfff - CCSR @ 0xe100
+ * LAW 5 - 0xe200 -> 0xe2ff - LBC 16MB
+ * gap   - 0xe300 -> 0xefff
+ * LAW 6 - 0xf000 -> 0x - LBC 256MB
+ *
+ * And validated against the RTEMS 4.9.6 mvme3100 BSP
+ */
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qapi/error.h"
+#include "qapi/visitor.h"
+#include "e500.h"
+#include "cpu.h"
+#include "qemu-common.h"
+#include "cpu-qom.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/dma.h"
+#include "sysemu/block-backend.h"
+#include "hw/loader.h"
+#include "hw/pci/pci.h"
+#include "hw/boards.h"
+#include "hw/ppc/ppc.h"
+#include "hw/net/fsl_etsec/etsec.h"
+#include "sysemu/device_tree.h"
+#include "sysemu/qtest.h"
+#include "hw/ppc/openpic.h"
+#include "qemu/error-report.h"
+
+/* Same as prep.c and other PPC boards */
+#define CFG_ADDR 0xf510
+
+#define TYPE_MVME3100 MACHINE_TYPE_NAME("mvme3100")
+#define MVME3100(obj) OBJECT_CHECK(MVME3100State, (obj), TYPE_MVME3100)
+#define MVME3100_GET_CLASS(obj) \
+OBJECT_GET_CLASS(MVME3100Class, (obj), TYPE_MVME3100)
+#define MVME3100_CLASS(klass) \
+OBJECT_CLASS_CHECK(MVME3100Class, (klass), TYPE_MVME3100)
+
+
+typedef struct mvme3100_info {
+const char *desc;
+uint32_t cpu_freq;
+uint32_t porpllsr;
+uint32_t ram_size;
+} mvme3100_info;
+
+typedef struct MVME3100Class {
+/*< private >*/
+MachineClass parent_class;
+/*< public >*/
+
+const mvme3100_info *info;
+} MVME3100Class;
+
+typedef struct MVME3100State {
+/*< private >*/
+MachineState parent_obj;
+/*< public >*/
+
+uint32_t load_address,
+ entry_address;
+} MVME3100State;
+
+
+/* motload "global environment" variables */
+static
+const char *gev[] = {
+/* TODO: somehow snoop in slirp_instances to pick up IP config? */
+"mot-/dev/enet0-cipa=10.0.2.15",
+"mot-/dev/enet0-gipa=10.0.2.2",
+"mot-/dev/enet0-snma=255.255.255.0",

[Qemu-devel] [PATCH 09/12] nvram: add AT24Cx i2c eeprom

2017-11-19 Thread Michael Davidsaver
Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 hw/nvram/Makefile.objs  |   1 +
 hw/nvram/eeprom_at24c.c | 205 
 2 files changed, 206 insertions(+)
 create mode 100644 hw/nvram/eeprom_at24c.c

diff --git a/hw/nvram/Makefile.objs b/hw/nvram/Makefile.objs
index c018f6b2ff..0f4ee71dcb 100644
--- a/hw/nvram/Makefile.objs
+++ b/hw/nvram/Makefile.objs
@@ -1,5 +1,6 @@
 common-obj-$(CONFIG_DS1225Y) += ds1225y.o
 common-obj-y += eeprom93xx.o
+common-obj-y += eeprom_at24c.o
 common-obj-y += fw_cfg.o
 common-obj-y += chrp_nvram.o
 common-obj-$(CONFIG_MAC_NVRAM) += mac_nvram.o
diff --git a/hw/nvram/eeprom_at24c.c b/hw/nvram/eeprom_at24c.c
new file mode 100644
index 00..efa3621ac6
--- /dev/null
+++ b/hw/nvram/eeprom_at24c.c
@@ -0,0 +1,205 @@
+/*
+ * *AT24C* series I2C EEPROM
+ *
+ * Copyright (c) 2015 Michael Davidsaver
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the LICENSE file in the top-level directory.
+ */
+
+#include 
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/hw.h"
+#include "hw/i2c/i2c.h"
+#include "sysemu/block-backend.h"
+
+/* #define DEBUG_AT24C */
+
+#ifdef DEBUG_AT24C
+#define DPRINTK(FMT, ...) printf(TYPE_AT24C_EE " : " FMT, ## __VA_ARGS__)
+#else
+#define DPRINTK(FMT, ...) do {} while (0)
+#endif
+
+#define ERR(FMT, ...) fprintf(stderr, TYPE_AT24C_EE " : " FMT, \
+## __VA_ARGS__)
+
+#define TYPE_AT24C_EE "at24c-eeprom"
+#define AT24C_EE(obj) OBJECT_CHECK(EEPROMState, (obj), TYPE_AT24C_EE)
+
+typedef struct EEPROMState {
+I2CSlave parent_obj;
+
+/* address counter */
+uint16_t cur;
+/* total size in bytes */
+uint32_t rsize;
+bool writable;
+/* cells changed since last START? */
+bool changed;
+/* during WRITE, # of address bytes transfered */
+uint8_t haveaddr;
+
+uint8_t *mem;
+
+BlockBackend *blk;
+} EEPROMState;
+
+static
+int at24c_eeprom_event(I2CSlave *s, enum i2c_event event)
+{
+EEPROMState *ee = container_of(s, EEPROMState, parent_obj);
+
+switch (event) {
+case I2C_START_SEND:
+case I2C_START_RECV:
+case I2C_FINISH:
+ee->haveaddr = 0;
+DPRINTK("clear\n");
+if (ee->blk && ee->changed) {
+int len = blk_pwrite(ee->blk, 0, ee->mem, ee->rsize, 0);
+if (len != ee->rsize) {
+ERR(TYPE_AT24C_EE
+" : failed to write backing file\n");
+}
+DPRINTK("Wrote to backing file\n");
+}
+ee->changed = false;
+break;
+case I2C_NACK:
+break;
+}
+return 0;
+}
+
+static
+int at24c_eeprom_recv(I2CSlave *s)
+{
+EEPROMState *ee = AT24C_EE(s);
+int ret;
+
+ret = ee->mem[ee->cur];
+
+ee->cur = (ee->cur + 1u) % ee->rsize;
+DPRINTK("Recv %02x %c\n", ret, ret);
+
+return ret;
+}
+
+static
+int at24c_eeprom_send(I2CSlave *s, uint8_t data)
+{
+EEPROMState *ee = AT24C_EE(s);
+
+if (ee->haveaddr < 2) {
+ee->cur <<= 8;
+ee->cur |= data;
+ee->haveaddr++;
+if (ee->haveaddr == 2) {
+ee->cur %= ee->rsize;
+DPRINTK("Set pointer %04x\n", ee->cur);
+}
+
+} else {
+if (ee->writable) {
+DPRINTK("Send %02x\n", data);
+ee->mem[ee->cur] = data;
+ee->changed = true;
+} else {
+DPRINTK("Send error %02x read-only\n", data);
+}
+ee->cur = (ee->cur + 1u) % ee->rsize;
+
+}
+
+return 0;
+}
+
+static
+int at24c_eeprom_init(I2CSlave *i2c)
+{
+EEPROMState *ee = AT24C_EE(i2c);
+
+ee->mem = g_malloc0(ee->rsize);
+
+if (ee->blk) {
+int64_t len = blk_getlength(ee->blk);
+
+if (len != ee->rsize) {
+ERR(TYPE_AT24C_EE " : Backing file size %lu != %u\n",
+(unsigned long)len, (unsigned)ee->rsize);
+exit(1);
+}
+
+if (blk_set_perm(ee->blk, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE,
+ BLK_PERM_ALL, _fatal) < 0)
+{
+ERR(TYPE_AT24C_EE
+" : Backing file incorrect permission\n");
+exit(1);
+}
+}
+return 0;
+}
+
+static
+void at24c_eeprom_reset(DeviceState *state)
+{
+EEPROMState *ee = AT24C_EE(state);
+
+ee->changed = false;
+ee->cur = 0;
+ee->haveaddr = 0;
+
+memset(ee->mem, 0, ee->rsize);
+
+if (ee->blk) {
+int len = blk_pread(ee->blk, 0, ee->mem, ee->rsize);
+
+if (len != ee->rsize) {
+ERR(TYPE_AT24C_EE
+

[Qemu-devel] [PATCH 12/12] tests: add mvme3100-test

2017-11-19 Thread Michael Davidsaver
Exercise some features of the mvme3100 CPLD logic
and read from the eeprom w/ VPD.

Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 tests/Makefile.include |  3 ++
 tests/mvme3100-test.c  | 79 ++
 2 files changed, 82 insertions(+)
 create mode 100644 tests/mvme3100-test.c

diff --git a/tests/Makefile.include b/tests/Makefile.include
index ad1c219423..7ea041a885 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -372,6 +372,8 @@ check-qtest-s390x-y += tests/virtio-balloon-test$(EXESUF)
 check-qtest-s390x-y += tests/virtio-console-test$(EXESUF)
 check-qtest-s390x-y += tests/virtio-serial-test$(EXESUF)
 
+check-qtest-ppc-$(CONFIG_E500) += tests/mvme3100-test$(EXESUF)
+
 check-qtest-generic-y += tests/qom-test$(EXESUF)
 check-qtest-generic-y += tests/test-hmp$(EXESUF)
 
@@ -781,6 +783,7 @@ tests/i82801b11-test$(EXESUF): tests/i82801b11-test.o
 tests/ac97-test$(EXESUF): tests/ac97-test.o
 tests/es1370-test$(EXESUF): tests/es1370-test.o
 tests/intel-hda-test$(EXESUF): tests/intel-hda-test.o
+tests/mvme3100-test$(EXESUF): tests/mvme3100-test.o $(libqos-e500-obj-y)
 tests/ioh3420-test$(EXESUF): tests/ioh3420-test.o
 tests/usb-hcd-ohci-test$(EXESUF): tests/usb-hcd-ohci-test.o $(libqos-usb-obj-y)
 tests/usb-hcd-uhci-test$(EXESUF): tests/usb-hcd-uhci-test.o $(libqos-usb-obj-y)
diff --git a/tests/mvme3100-test.c b/tests/mvme3100-test.c
new file mode 100644
index 00..6dde8d1d29
--- /dev/null
+++ b/tests/mvme3100-test.c
@@ -0,0 +1,79 @@
+#include 
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "libqos/libqos.h"
+#include "libqos/i2c.h"
+
+#define assert_equal(A, B) g_assert_cmphex((A), ==, (B))
+
+static
+I2CAdapter *i2c;
+
+static
+void test_ccsr(void)
+{
+/* CCSRBAR is self referential */
+assert_equal(readl(0xff70), 0x000ff700);
+
+/* introspect memory size */
+assert_equal(readl(0xff702080), 0x8000);
+/* value is (ram_size-1)>>24 */
+assert_equal(readl(0xff702000), 15);
+}
+
+static
+void test_cpld(void)
+{
+/* read/write to test register */
+assert_equal(readl(0xe210), 0x);
+assert_equal(readl(0xe214), 0x);
+
+writel(0xe210, 0x12345678);
+
+assert_equal(readl(0xe210), 0x12345678);
+assert_equal(readl(0xe214), 0x12345678 ^ 0x);
+}
+
+static
+void test_eeprom(void)
+{
+char buf[] = "\x00\x00MOTOROLA";
+
+/* 1. zero address pointer
+ * 2. write 8 bytes,
+ * 3. re-zero address pointer
+ */
+i2c_send(i2c, 0xa8, (uint8_t *)buf, 10);
+i2c_send(i2c, 0xa8, (uint8_t *)buf, 2);
+
+/* read 8 bytes */
+i2c_recv(i2c, 0xa8, (uint8_t *)buf, 8);
+buf[8] = '\0';
+
+/* Read header for Motorola VPD info */
+g_assert_cmpstr(buf, ==, "MOTOROLA");
+}
+
+int main(int argc, char *argv[])
+{
+int ret;
+g_test_init(, , NULL);
+
+qtest_start("-machine mvme3100-1152");
+
+i2c = e500_i2c_create(0xff70);
+
+qtest_add_func("/mvme3100/ccsr", test_ccsr);
+qtest_add_func("/mvme3100/cpld", test_cpld);
+qtest_add_func("/mvme3100/eeprom", test_eeprom);
+
+ret = g_test_run();
+
+printf("Tests done\n");
+
+qtest_end();
+printf("Tests end\n");
+
+return ret;
+}
-- 
2.11.0




[Qemu-devel] [PATCH 07/12] qtest: add e500_i2c_create()

2017-11-19 Thread Michael Davidsaver
Add interface for testing i2c devices
with PPC e500.

Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 tests/Makefile.include  |  1 +
 tests/libqos/i2c-e500.c | 66 +
 tests/libqos/i2c.h  |  3 +++
 3 files changed, 70 insertions(+)
 create mode 100644 tests/libqos/i2c-e500.c

diff --git a/tests/Makefile.include b/tests/Makefile.include
index c002352134..ad1c219423 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -721,6 +721,7 @@ libqos-pc-obj-y += tests/libqos/malloc-pc.o 
tests/libqos/libqos-pc.o
 libqos-pc-obj-y += tests/libqos/ahci.o
 libqos-omap-obj-y = $(libqos-obj-y) tests/libqos/i2c-omap.o
 libqos-imx-obj-y = $(libqos-obj-y) tests/libqos/i2c-imx.o
+libqos-e500-obj-y = $(libqos-obj-y) tests/libqos/i2c-e500.o
 libqos-usb-obj-y = $(libqos-spapr-obj-y) $(libqos-pc-obj-y) tests/libqos/usb.o
 libqos-virtio-obj-y = $(libqos-spapr-obj-y) $(libqos-pc-obj-y) 
tests/libqos/virtio.o tests/libqos/virtio-pci.o tests/libqos/virtio-mmio.o 
tests/libqos/malloc-generic.o
 
diff --git a/tests/libqos/i2c-e500.c b/tests/libqos/i2c-e500.c
new file mode 100644
index 00..4272ada0a5
--- /dev/null
+++ b/tests/libqos/i2c-e500.c
@@ -0,0 +1,66 @@
+/*
+ * QTest I2C driver
+ *
+ * Copyright (c) 2016 Michael Davidsaver
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#include "qemu/osdep.h"
+#include "libqos/i2c.h"
+
+
+#include "qemu/bswap.h"
+#include "libqtest.h"
+
+typedef struct E500I2C {
+I2CAdapter parent;
+
+uint64_t addr;
+} E500I2C;
+
+static void e500_i2c_send(I2CAdapter *i2c, uint8_t addr,
+  const uint8_t *buf, uint16_t len)
+{
+E500I2C *s = (E500I2C *)i2c;
+
+writeb(s->addr + 0x8, 0xb0); /* Enable and START a write */
+writeb(s->addr + 0x10, addr & 0xfe); /* Send address for write */
+
+while (len--) {
+writeb(s->addr + 0x10, *buf++);
+}
+
+writeb(s->addr + 0x8, 0x80); /* STOP but leave enabled */
+}
+
+static void e500_i2c_recv(I2CAdapter *i2c, uint8_t addr,
+  uint8_t *buf, uint16_t len)
+{
+E500I2C *s = (E500I2C *)i2c;
+
+writeb(s->addr + 0x8, 0xa0); /* Enable and START a read */
+writeb(s->addr + 0x10, addr | 1); /* Send address for read */
+
+/* reads are "pipelined" so the initial value is junk */
+readb(s->addr + 0x10);
+
+while (len--) {
+*buf++ = readb(s->addr + 0x10);
+}
+
+writeb(s->addr + 0x8, 0x80); /* STOP but leave enabled */
+}
+
+I2CAdapter *e500_i2c_create(uint64_t ccsr_base)
+{
+E500I2C *s = g_malloc0(sizeof(*s));
+I2CAdapter *i2c = (I2CAdapter *)s;
+
+s->addr = ccsr_base + 0x3000;
+
+i2c->send = e500_i2c_send;
+i2c->recv = e500_i2c_recv;
+
+return i2c;
+}
diff --git a/tests/libqos/i2c.h b/tests/libqos/i2c.h
index 6e648f922a..40c59a7997 100644
--- a/tests/libqos/i2c.h
+++ b/tests/libqos/i2c.h
@@ -29,4 +29,7 @@ I2CAdapter *omap_i2c_create(uint64_t addr);
 /* libi2c-imx.c */
 I2CAdapter *imx_i2c_create(uint64_t addr);
 
+/* i2c-e500.c */
+I2CAdapter *e500_i2c_create(uint64_t ccsr_base);
+
 #endif
-- 
2.11.0




[Qemu-devel] [PATCH 05/12] e500: name openpic and pci host bridge

2017-11-19 Thread Michael Davidsaver
Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 hw/ppc/e500.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index 057be1751b..6f77844303 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -685,6 +685,8 @@ static DeviceState *ppce500_init_mpic_qemu(PPCE500Params 
*params,
 int i, j, k;
 
 dev = qdev_create(NULL, TYPE_OPENPIC);
+object_property_add_child(qdev_get_machine(), "pic", OBJECT(dev),
+  _fatal);
 qdev_prop_set_uint32(dev, "model", params->mpic_version);
 qdev_prop_set_uint32(dev, "nb_cpus", smp_cpus);
 
@@ -876,6 +878,8 @@ void ppce500_init(MachineState *machine, PPCE500Params 
*params)
 
 /* PCI */
 dev = qdev_create(NULL, "e500-pcihost");
+object_property_add_child(qdev_get_machine(), "pci-host", OBJECT(dev),
+  _abort);
 qdev_prop_set_uint32(dev, "first_slot", params->pci_first_slot);
 qdev_prop_set_uint32(dev, "first_pin_irq", pci_irq_nrs[0]);
 qdev_init_nofail(dev);
-- 
2.11.0




[Qemu-devel] [PATCH 00/12] Add MVME3100 PPC SBC

2017-11-19 Thread Michael Davidsaver
This series adds simulation of MVME3100 powerpc SBCs, originally from Motorola,
and now sold by Artesyn[1].  There are two variants differing in CPU
speed and memory size.

I've been working on this sporadically for the past 2 year.  Recently I've
finished all the features which I have in mind.  If this series is accepted
there is a continuation which adds VME bus.  I've found it
useful in software compatibility testing.  I wonder if there is
any interest at large?


There are two main parts of this series.  1-5 are changing code common
with the "ppce500" and "mpc8544ds" boards, with the remainder being
additions.

The changes are to how the CCSR region is handled in order to support
the CCSRBAR register which allows the whole region to be relocated.
Also added are a couple of memory and clock configuration registers
which RTEMS guests read.

#3 is actually a minor issue I found recently with the mpc8544 PCI host bridge,
which I'm uncertain how to address.  The host bridge device 0:0 identifies
itself as a bridge, but doesn't properly implement the bridge config registers.
This confuses Linux, which then does a full re-enumeration (successfully).

The rest are additions of an I2C controller, an I2C eeprom, an I2C RTC,
and new board code.

My testing has been almost exclusively with an RTEMS guest[2].
Though I have recently done a little with Linux.

RTEMS guests (and Linux too for now) require a stub bootloader[3] to
put the system in the same state as the real bootloader.
RTEMS has an unfortunately strong dependence on bootloader
provided configuration (eg. it doesn't re-enumerate the PCI bus).


[1] 
https://www.artesyn.com/computing/products/product/mvme3100-vme-board-with-freescale-mpc8540-system-on-chip-processor

[2] https://www.rtems.org/

[3] https://github.com/mdavidsaver/qemu/wiki


Michael Davidsaver (12):
  e500: add board config options
  e500: consolidate mpc8540 guts with e500-ccsr
  e500: note possible bug with host bridge
  e500: additional CCSR registers
  e500: name openpic and pci host bridge
  i2c: add mpc8540 i2c controller
  qtest: add e500_i2c_create()
  e500: add mpc8540 i2c controller to ccsr
  nvram: add AT24Cx i2c eeprom
  timer: add ds1375 RTC
  ppc: add mvme3100 machine
  tests: add mvme3100-test

 default-configs/ppc-softmmu.mak |   1 +
 hw/i2c/Makefile.objs|   1 +
 hw/i2c/mpc8540_i2c.c| 287 +
 hw/nvram/Makefile.objs  |   1 +
 hw/nvram/eeprom_at24c.c | 205 
 hw/pci-host/ppce500.c   |  13 +-
 hw/ppc/Makefile.objs|   4 +-
 hw/ppc/e500-ccsr.h  |  17 -
 hw/ppc/e500.c   |  59 ++--
 hw/ppc/e500.h   |   4 +
 hw/ppc/e500_ccsr.c  | 220 +
 hw/ppc/e500plat.c   |   2 +
 hw/ppc/mpc8544_guts.c   | 143 -
 hw/ppc/mpc8544ds.c  |   2 +
 hw/ppc/mvme3100.c   | 688 
 hw/ppc/mvme3100_cpld.c  | 192 +++
 hw/timer/Makefile.objs  |   1 +
 hw/timer/ds1375-i2c.c   | 293 +
 tests/Makefile.include  |   4 +
 tests/libqos/i2c-e500.c |  66 
 tests/libqos/i2c.h  |   3 +
 tests/mvme3100-test.c   |  79 +
 22 files changed, 2083 insertions(+), 202 deletions(-)
 create mode 100644 hw/i2c/mpc8540_i2c.c
 create mode 100644 hw/nvram/eeprom_at24c.c
 delete mode 100644 hw/ppc/e500-ccsr.h
 create mode 100644 hw/ppc/e500_ccsr.c
 delete mode 100644 hw/ppc/mpc8544_guts.c
 create mode 100644 hw/ppc/mvme3100.c
 create mode 100644 hw/ppc/mvme3100_cpld.c
 create mode 100644 hw/timer/ds1375-i2c.c
 create mode 100644 tests/libqos/i2c-e500.c
 create mode 100644 tests/mvme3100-test.c

-- 
2.11.0




[Qemu-devel] [PATCH 06/12] i2c: add mpc8540 i2c controller

2017-11-19 Thread Michael Davidsaver
Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 hw/i2c/Makefile.objs |   1 +
 hw/i2c/mpc8540_i2c.c | 287 +++
 2 files changed, 288 insertions(+)
 create mode 100644 hw/i2c/mpc8540_i2c.c

diff --git a/hw/i2c/Makefile.objs b/hw/i2c/Makefile.objs
index 0594dea3ae..79af1dd901 100644
--- a/hw/i2c/Makefile.objs
+++ b/hw/i2c/Makefile.objs
@@ -9,3 +9,4 @@ common-obj-$(CONFIG_IMX_I2C) += imx_i2c.o
 common-obj-$(CONFIG_ASPEED_SOC) += aspeed_i2c.o
 obj-$(CONFIG_OMAP) += omap_i2c.o
 obj-$(CONFIG_PPC4XX) += ppc4xx_i2c.o
+obj-$(CONFIG_E500) += mpc8540_i2c.o
diff --git a/hw/i2c/mpc8540_i2c.c b/hw/i2c/mpc8540_i2c.c
new file mode 100644
index 00..884052cc9b
--- /dev/null
+++ b/hw/i2c/mpc8540_i2c.c
@@ -0,0 +1,287 @@
+/*
+ * MPC8540 I2C bus interface
+ * As described in
+ * MPC8540 PowerQUICC III Integrated Host Processor Reference Manual, Rev. 1
+ * Part 2 chapter 11
+ *
+ * Copyright (c) 2015 Michael Davidsaver
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the LICENSE file in the top-level directory.
+ */
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "hw/hw.h"
+#include "hw/registerfields.h"
+#include "hw/i2c/i2c.h"
+#include "hw/sysbus.h"
+
+/* #define DEBUG_LVL 0 */
+
+#ifdef DEBUG_LVL
+#define DPRINTK(LVL, FMT, ...) do { if ((LVL) <= DEBUG_LVL) { \
+printf(TYPE_MPC8540_I2C " : " FMT, ## __VA_ARGS__); } } while (0)
+#else
+#define DPRINTK(LVL, FMT, ...) do {} while (0)
+#endif
+
+#define LOG(MSK, FMT, ...) qemu_log_mask(MSK, TYPE_MPC8540_I2C \
+" : " FMT, ## __VA_ARGS__)
+
+#define TYPE_MPC8540_I2C "mpc8540-i2c"
+#define MPC8540_I2C(obj) OBJECT_CHECK(I2CState, (obj), TYPE_MPC8540_I2C)
+
+/* offsets relative to CCSR offset 0x3000 */
+#define R_I2CADR (0)
+#define R_I2CFDR (4)
+#define R_I2CCR  (8)
+#define R_I2CSR  (0xc)
+#define R_I2CDR  (0x10)
+#define R_I2CDFSRR (0x14)
+
+FIELD(I2CCR, MEN, 7, 1)
+FIELD(I2CCR, MIEN, 6, 1)
+FIELD(I2CCR, MSTA, 5, 1)
+FIELD(I2CCR, MTX, 4, 1)
+FIELD(I2CCR, TXAK, 3, 1)
+FIELD(I2CCR, RSTA, 2, 1)
+FIELD(I2CCR, BCST, 0, 1)
+
+FIELD(I2CSR, MCF, 7, 1)
+FIELD(I2CSR, MAAS, 6, 1)
+FIELD(I2CSR, MBB, 5, 1)
+FIELD(I2CSR, MAL, 4, 1)
+FIELD(I2CSR, BCSTM, 3, 1)
+FIELD(I2CSR, SRW, 2, 1)
+FIELD(I2CSR, MIF, 1, 1)
+FIELD(I2CSR, RXAK, 0, 1)
+
+typedef struct I2CState {
+SysBusDevice parent_obj;
+
+I2CBus *bus;
+
+uint8_t ctrl, sts;
+uint8_t freq, filt;
+/* Reads are pipelined, this is the next data value */
+uint8_t dbuf;
+
+qemu_irq irq;
+
+MemoryRegion mmio;
+} I2CState;
+
+#define I2CCR(BIT) FIELD_EX32(i2c->ctrl, I2CCR, BIT)
+#define I2CSR(BIT) FIELD_EX32(i2c->sts, I2CSR, BIT)
+
+#define I2CSR_SET(BIT, VAL) do {\
+i2c->sts = FIELD_DP32(i2c->sts, I2CSR, BIT, VAL);\
+} while (0)
+
+static
+void mpc8540_update_irq(I2CState *i2c)
+{
+int ena = i2c->ctrl & 0x40,
+sts = i2c->sts & 0x02,
+act = !!(ena && sts);
+
+DPRINTK(1, "IRQ %c ena %c sts %c\n",
+act ? 'X' : '_',
+ena ? 'X' : '_',
+sts ? 'X' : '_');
+
+qemu_set_irq(i2c->irq, act);
+}
+
+static
+uint64_t mpc8540_i2c_read(void *opaque, hwaddr addr, unsigned size)
+{
+I2CState *i2c = opaque;
+uint32_t val, offset = addr;
+
+switch (offset) {
+case R_I2CADR: /* ADDR */
+val = 0;
+break;
+case R_I2CFDR: /* Freq Div. */
+val = i2c->freq;
+break;
+case R_I2CCR: /* CONTROL */
+val = i2c->ctrl & ~0x06;
+break;
+case R_I2CSR: /* STATUS */
+val = i2c->sts;
+break;
+case R_I2CDR: /* DATA */
+/* Reads are "pipelined" and so return the previous value of the
+ * register
+ */
+val = i2c->dbuf;
+if (I2CCR(MEN) && I2CSR(MBB)) { /* enabled and busy */
+if (!i2c_bus_busy(i2c->bus) || I2CCR(MTX)) {
+LOG(LOG_GUEST_ERROR, "Read during addr or tx\n");
+i2c->dbuf = 0xff;
+} else {
+int ret = i2c_recv(i2c->bus);
+i2c->dbuf = (uint8_t)ret;
+DPRINTK(0, "READ %02x ('%c')\n", i2c->dbuf, (char)i2c->dbuf);
+I2CSR_SET(MIF, 1);
+I2CSR_SET(RXAK, 0);
+mpc8540_update_irq(i2c);
+}
+} else {
+i2c->dbuf = 0xff;
+LOG(LOG_GUEST_ERROR, "Read when not enabled or busy\n");
+}
+break;
+case R_I2CDFSRR: /* FILTER */
+val = i2c->filt;
+break;
+default:
+val = 0xff;
+}
+
+DPRINTK(offset == 0xc ? 2 : 1, " read %08x -> %08x\n",
+(unsigned)offset, (unsigned)val);
+return val;
+}
+
+static
+void mpc8540_i2c_write(void *opaque, hwaddr addr, u

[Qemu-devel] [PATCH 03/12] e500: note possible bug with host bridge

2017-11-19 Thread Michael Davidsaver
Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 hw/pci-host/ppce500.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/hw/pci-host/ppce500.c b/hw/pci-host/ppce500.c
index f2d108bc8a..0e2833bd98 100644
--- a/hw/pci-host/ppce500.c
+++ b/hw/pci-host/ppce500.c
@@ -424,6 +424,9 @@ static void e500_pcihost_bridge_realize(PCIDevice *d, Error 
**errp)
 MemoryRegion *ccsr_mr = sysbus_mmio_get_region(ccsr, 0);
 
 pci_config_set_class(d->config, PCI_CLASS_BRIDGE_PCI);
+/* BUG? identifies as PCI_HEADER_TYPE_BRIDGE but uses
+ * standard device config read/write
+ */
 d->config[PCI_HEADER_TYPE] =
 (d->config[PCI_HEADER_TYPE] & PCI_HEADER_TYPE_MULTI_FUNCTION) |
 PCI_HEADER_TYPE_BRIDGE;
-- 
2.11.0




[Qemu-devel] [PATCH 04/12] e500: additional CCSR registers

2017-11-19 Thread Michael Davidsaver
Add CCSRBAR to allow CCSR region to be relocated.
Guest memory size introspection.
Dummy RAM error controls.
Guest clock introspection.

Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 hw/ppc/e500.c  |  2 ++
 hw/ppc/e500.h  |  1 +
 hw/ppc/e500_ccsr.c | 72 --
 hw/ppc/e500plat.c  |  1 +
 hw/ppc/mpc8544ds.c |  1 +
 5 files changed, 75 insertions(+), 2 deletions(-)

diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index 474a46a985..057be1751b 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -853,7 +853,9 @@ void ppce500_init(MachineState *machine, PPCE500Params 
*params)
 dev = qdev_create(NULL, "e500-ccsr");
 object_property_add_child(qdev_get_machine(), "e500-ccsr",
   OBJECT(dev), NULL);
+qdev_prop_set_uint32(dev, "porpllsr", params->porpllsr);
 qdev_prop_set_uint32(dev, "base", params->ccsrbar_base);
+qdev_prop_set_uint32(dev, "ram-size", ram_size);
 qdev_init_nofail(dev);
 ccsr_addr_space = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
 
diff --git a/hw/ppc/e500.h b/hw/ppc/e500.h
index 40f72f2de2..1f39095dfa 100644
--- a/hw/ppc/e500.h
+++ b/hw/ppc/e500.h
@@ -22,6 +22,7 @@ typedef struct PPCE500Params {
 hwaddr pci_mmio_base;
 hwaddr pci_mmio_bus_base;
 hwaddr spin_base;
+uint32_t porpllsr; /* value of PORPLLSR register */
 uint32_t decrementor_freq; /* in Hz */
 bool skip_load;
 bool tsec_nic;
diff --git a/hw/ppc/e500_ccsr.c b/hw/ppc/e500_ccsr.c
index 1b586c3f42..c58b17f06b 100644
--- a/hw/ppc/e500_ccsr.c
+++ b/hw/ppc/e500_ccsr.c
@@ -31,6 +31,16 @@
 
 /* E500_ denotes registers common to all */
 
+#define E500_CCSRBAR (0)
+
+#define E500_CS0_BNDS(0x2000)
+
+#define E500_CS0_CONFIG  (0x2080)
+
+#define E500_ERR_DETECT  (0x2e40)
+#define E500_ERR_DISABLE (0x2e44)
+
+#define E500_PORPLLSR(0xE)
 #define E500_PVR (0xE00A0)
 #define E500_SVR (0xE00A4)
 
@@ -44,7 +54,11 @@ typedef struct {
 
 MemoryRegion iomem;
 
-uint32_t defbase;
+uint32_t defbase, base;
+uint32_t ram_size;
+uint32_t merrd;
+
+uint32_t porpllsr;
 } CCSRState;
 
 #define TYPE_E500_CCSR "e500-ccsr"
@@ -53,10 +67,28 @@ typedef struct {
 static uint64_t e500_ccsr_read(void *opaque, hwaddr addr,
   unsigned size)
 {
+CCSRState *ccsr = opaque;
 PowerPCCPU *cpu = POWERPC_CPU(current_cpu);
 CPUPPCState *env = >env;
 
 switch (addr) {
+case E500_CCSRBAR:
+return ccsr->base >> 12;
+case E500_CS0_BNDS:
+/* we model all RAM in a single chip with addresses [0, ram_size) */
+return (ccsr->ram_size - 1) >> 24;
+case E500_CS0_CONFIG:
+return 1 << 31;
+case E500_ERR_DETECT:
+return 0; /* (errors not modeled) */
+case E500_ERR_DISABLE:
+return ccsr->merrd;
+case E500_PORPLLSR:
+if (!ccsr->porpllsr) {
+qemu_log_mask(LOG_UNIMP,
+  "Machine does not provide valid PORPLLSR\n");
+}
+return ccsr->porpllsr;
 case E500_PVR:
 return env->spr[SPR_PVR];
 case E500_SVR:
@@ -72,10 +104,22 @@ static uint64_t e500_ccsr_read(void *opaque, hwaddr addr,
 static void e500_ccsr_write(void *opaque, hwaddr addr,
uint64_t value, unsigned size)
 {
+CCSRState *ccsr = opaque;
 PowerPCCPU *cpu = POWERPC_CPU(current_cpu);
 CPUPPCState *env = >env;
 uint32_t svr = env->spr[SPR_E500_SVR] >> 16;
 
+switch (addr) {
+case E500_CCSRBAR:
+value &= 0x000fff00;
+ccsr->base = value << 12;
+sysbus_mmio_map(SYS_BUS_DEVICE(ccsr), 0, ccsr->base);
+return;
+case E500_ERR_DISABLE:
+ccsr->merrd = value & 0xd;
+return;
+}
+
 switch (svr) {
 case 0: /* generic.  assumed to be mpc8544ds or e500plat board */
 case 0x8034: /* mpc8544 */
@@ -104,11 +148,20 @@ static const MemoryRegionOps e500_ccsr_ops = {
 }
 };
 
+static int e500_ccsr_post_load(void *opaque, int version_id)
+{
+CCSRState *ccsr = opaque;
+
+sysbus_mmio_map(SYS_BUS_DEVICE(ccsr), 0, ccsr->base);
+return 0;
+}
+
 static void e500_ccsr_reset(DeviceState *dev)
 {
 CCSRState *ccsr = E500_CCSR(dev);
 
-sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, ccsr->defbase);
+ccsr->base = ccsr->defbase;
+e500_ccsr_post_load(ccsr, 1);
 }
 
 static void e500_ccsr_initfn(Object *obj)
@@ -123,15 +176,30 @@ static void e500_ccsr_initfn(Object *obj)
 
 static Property e500_ccsr_props[] = {
 DEFINE_PROP_UINT32("base", CCSRState, defbase, 0xff70),
+DEFINE_PROP_UINT32("ram-size", CCSRState, ram_size, 0),
+DEFINE_PROP_UINT32("porpllsr", CCSRState, porpllsr, 0),
 DEFINE_PROP_END_OF_LIST()
 };
 
+stat

[Qemu-devel] [PATCH 08/12] e500: add mpc8540 i2c controller to ccsr

2017-11-19 Thread Michael Davidsaver
Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 hw/ppc/e500.c | 8 
 1 file changed, 8 insertions(+)

diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index 6f77844303..bef7d313d4 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -861,6 +861,14 @@ void ppce500_init(MachineState *machine, PPCE500Params 
*params)
 qdev_init_nofail(dev);
 ccsr_addr_space = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
 
+dev = qdev_create(NULL, "mpc8540-i2c");
+object_property_add_child(qdev_get_machine(), "i2c[*]",
+  OBJECT(dev), NULL);
+qdev_init_nofail(dev);
+s = SYS_BUS_DEVICE(dev);
+memory_region_add_subregion(ccsr_addr_space, 0x3000,
+sysbus_mmio_get_region(s, 0));
+
 mpicdev = ppce500_init_mpic(machine, params, ccsr_addr_space, irqs);
 
 /* Serial */
-- 
2.11.0




[Qemu-devel] [PATCH 01/12] e500: add board config options

2017-11-19 Thread Michael Davidsaver
allow board code to skip common NIC and guest image setup
and configure decrementor frequency.
Existing boards unchanged.

Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 hw/ppc/e500.c  | 8 ++--
 hw/ppc/e500.h  | 3 +++
 hw/ppc/e500plat.c  | 1 +
 hw/ppc/mpc8544ds.c | 1 +
 4 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index 5cf0dabef3..9e7e1b29c4 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -826,7 +826,7 @@ void ppce500_init(MachineState *machine, PPCE500Params 
*params)
 env->mpic_iack = params->ccsrbar_base +
  MPC8544_MPIC_REGS_OFFSET + 0xa0;
 
-ppc_booke_timers_init(cpu, 4, PPC_TIMER_E500);
+ppc_booke_timers_init(cpu, params->decrementor_freq, PPC_TIMER_E500);
 
 /* Register reset handler */
 if (!i) {
@@ -899,7 +899,7 @@ void ppce500_init(MachineState *machine, PPCE500Params 
*params)
 if (!pci_bus)
 printf("couldn't create PCI controller!\n");
 
-if (pci_bus) {
+if (pci_bus && !params->tsec_nic) {
 /* Register network interfaces. */
 for (i = 0; i < nb_nics; i++) {
 pci_nic_init_nofail(_table[i], pci_bus, "virtio", NULL);
@@ -948,6 +948,10 @@ void ppce500_init(MachineState *machine, PPCE500Params 
*params)
 sysbus_mmio_get_region(s, 0));
 }
 
+if (params->skip_load) {
+return;
+}
+
 /* Load kernel. */
 if (machine->kernel_filename) {
 kernel_base = cur_base;
diff --git a/hw/ppc/e500.h b/hw/ppc/e500.h
index 70ba1d8f4f..40f72f2de2 100644
--- a/hw/ppc/e500.h
+++ b/hw/ppc/e500.h
@@ -22,6 +22,9 @@ typedef struct PPCE500Params {
 hwaddr pci_mmio_base;
 hwaddr pci_mmio_bus_base;
 hwaddr spin_base;
+uint32_t decrementor_freq; /* in Hz */
+bool skip_load;
+bool tsec_nic;
 } PPCE500Params;
 
 void ppce500_init(MachineState *machine, PPCE500Params *params);
diff --git a/hw/ppc/e500plat.c b/hw/ppc/e500plat.c
index e59e80fb9e..3d07987bd1 100644
--- a/hw/ppc/e500plat.c
+++ b/hw/ppc/e500plat.c
@@ -47,6 +47,7 @@ static void e500plat_init(MachineState *machine)
 .pci_mmio_base = 0xCULL,
 .pci_mmio_bus_base = 0xE000ULL,
 .spin_base = 0xFEF00ULL,
+.decrementor_freq = 4,
 };
 
 /* Older KVM versions don't support EPR which breaks guests when we 
announce
diff --git a/hw/ppc/mpc8544ds.c b/hw/ppc/mpc8544ds.c
index 1717953ec7..6d9931c475 100644
--- a/hw/ppc/mpc8544ds.c
+++ b/hw/ppc/mpc8544ds.c
@@ -40,6 +40,7 @@ static void mpc8544ds_init(MachineState *machine)
 .pci_mmio_bus_base = 0xC000ULL,
 .pci_pio_base = 0xE100ULL,
 .spin_base = 0xEF00ULL,
+.decrementor_freq = 4,
 };
 
 if (machine->ram_size > 0xc000) {
-- 
2.11.0




[Qemu-devel] [PATCH] e500: ppce500_init_mpic() return device instead of IRQ array

2017-10-20 Thread Michael Davidsaver
Actual number of interrupt pins isn't known
in ppce500_init_mpic() so a hardcoded number
was used, which causes a crash with older openpic.

Instead, return the DeviceState* and change ppce500_init()
to call qdev_get_gpio_in() to get only the irq pins
which are needed.

Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
---
 hw/ppc/e500.c | 32 +---
 1 file changed, 13 insertions(+), 19 deletions(-)

diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index b8d786c479..33adc809ba 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -729,15 +729,13 @@ static DeviceState *ppce500_init_mpic_kvm(PPCE500Params 
*params,
 return dev;
 }
 
-static qemu_irq *ppce500_init_mpic(MachineState *machine, PPCE500Params 
*params,
-   MemoryRegion *ccsr, qemu_irq **irqs)
+static DeviceState *ppce500_init_mpic(MachineState *machine,
+  PPCE500Params *params,
+  MemoryRegion *ccsr,
+  qemu_irq **irqs)
 {
-qemu_irq *mpic;
 DeviceState *dev = NULL;
 SysBusDevice *s;
-int i;
-
-mpic = g_new0(qemu_irq, 256);
 
 if (kvm_enabled()) {
 Error *err = NULL;
@@ -756,15 +754,11 @@ static qemu_irq *ppce500_init_mpic(MachineState *machine, 
PPCE500Params *params,
 dev = ppce500_init_mpic_qemu(params, irqs);
 }
 
-for (i = 0; i < 256; i++) {
-mpic[i] = qdev_get_gpio_in(dev, i);
-}
-
 s = SYS_BUS_DEVICE(dev);
 memory_region_add_subregion(ccsr, MPC8544_MPIC_REGS_OFFSET,
 s->mmio[0].memory);
 
-return mpic;
+return dev;
 }
 
 static void ppce500_power_off(void *opaque, int line, int on)
@@ -796,8 +790,8 @@ void ppce500_init(MachineState *machine, PPCE500Params 
*params)
 /* irq num for pin INTA, INTB, INTC and INTD is 1, 2, 3 and
  * 4 respectively */
 unsigned int pci_irq_nrs[PCI_NUM_PINS] = {1, 2, 3, 4};
-qemu_irq **irqs, *mpic;
-DeviceState *dev;
+qemu_irq **irqs;
+DeviceState *dev, *mpicdev;
 CPUPPCState *firstenv = NULL;
 MemoryRegion *ccsr_addr_space;
 SysBusDevice *s;
@@ -866,18 +860,18 @@ void ppce500_init(MachineState *machine, PPCE500Params 
*params)
 memory_region_add_subregion(address_space_mem, params->ccsrbar_base,
 ccsr_addr_space);
 
-mpic = ppce500_init_mpic(machine, params, ccsr_addr_space, irqs);
+mpicdev = ppce500_init_mpic(machine, params, ccsr_addr_space, irqs);
 
 /* Serial */
 if (serial_hds[0]) {
 serial_mm_init(ccsr_addr_space, MPC8544_SERIAL0_REGS_OFFSET,
-   0, mpic[42], 399193,
+   0, qdev_get_gpio_in(mpicdev, 42), 399193,
serial_hds[0], DEVICE_BIG_ENDIAN);
 }
 
 if (serial_hds[1]) {
 serial_mm_init(ccsr_addr_space, MPC8544_SERIAL1_REGS_OFFSET,
-   0, mpic[42], 399193,
+   0, qdev_get_gpio_in(mpicdev, 42), 399193,
serial_hds[1], DEVICE_BIG_ENDIAN);
 }
 
@@ -896,7 +890,7 @@ void ppce500_init(MachineState *machine, PPCE500Params 
*params)
 qdev_init_nofail(dev);
 s = SYS_BUS_DEVICE(dev);
 for (i = 0; i < PCI_NUM_PINS; i++) {
-sysbus_connect_irq(s, i, mpic[pci_irq_nrs[i]]);
+sysbus_connect_irq(s, i, qdev_get_gpio_in(mpicdev, pci_irq_nrs[i]));
 }
 
 memory_region_add_subregion(ccsr_addr_space, MPC8544_PCI_REGS_OFFSET,
@@ -927,7 +921,7 @@ void ppce500_init(MachineState *machine, PPCE500Params 
*params)
 dev = qdev_create(NULL, "mpc8xxx_gpio");
 s = SYS_BUS_DEVICE(dev);
 qdev_init_nofail(dev);
-sysbus_connect_irq(s, 0, mpic[MPC8XXX_GPIO_IRQ]);
+sysbus_connect_irq(s, 0, qdev_get_gpio_in(mpicdev, MPC8XXX_GPIO_IRQ));
 memory_region_add_subregion(ccsr_addr_space, MPC8XXX_GPIO_OFFSET,
 sysbus_mmio_get_region(s, 0));
 
@@ -947,7 +941,7 @@ void ppce500_init(MachineState *machine, PPCE500Params 
*params)
 
 for (i = 0; i < params->platform_bus_num_irqs; i++) {
 int irqn = params->platform_bus_first_irq + i;
-sysbus_connect_irq(s, i, mpic[irqn]);
+sysbus_connect_irq(s, i, qdev_get_gpio_in(mpicdev, irqn));
 }
 
 memory_region_add_subregion(address_space_mem,
-- 
2.11.0




Re: [Qemu-devel] [PATCH 3/9] armv7m: Rewrite NVIC to not use any GIC code

2017-02-19 Thread Michael Davidsaver
On 02/18/2017 01:38 PM, Peter Maydell wrote:
> On 18 February 2017 at 17:45, Michael Davidsaver <mdavidsa...@gmail.com> 
> wrote:
>> On 02/16/2017 09:11 AM, Peter Maydell wrote:
>>> I haven't actually checked real hardware behaviour, but I think
>>> we can fairly safely implement this as not checking the IPSR
>>> exception field. (We might as well go with the "reads 1 in
>>> handler mode" choice of UNKNOWN that the M3 documents, though.)
>>
>> For what it's worth, I dug up my TI TM4C1294 eval board and re-ran
>> test10.c [1] which is designed to probe this behavior by nesting
>> exceptions PendSV within SVC.  RETTOBASE is 0x800 in ICSR.
> 
> That's a Cortex-M4. From the test it looks like it
> has a different choice of UNKNOWN behaviour for
> the value in Handler mode, so real code in the field
> isn't going to be relying on that and it doesn't
> matter what we choose.

I've been away from arm/m for too long to claim any detailed knowledge
of the documentation.  My intent here is only to provide a data point w/
real hardware, not to interpret it.

> I don't think the test looks at the "what happens if the
> exception in the IPSR exception field isn't actually
> active" case, right?

Correct.




Re: [Qemu-devel] [PATCH 3/9] armv7m: Rewrite NVIC to not use any GIC code

2017-02-18 Thread Michael Davidsaver
On 02/16/2017 09:11 AM, Peter Maydell wrote:
> I haven't actually checked real hardware behaviour, but I think
> we can fairly safely implement this as not checking the IPSR
> exception field. (We might as well go with the "reads 1 in
> handler mode" choice of UNKNOWN that the M3 documents, though.)

For what it's worth, I dug up my TI TM4C1294 eval board and re-ran
test10.c [1] which is designed to probe this behavior by nesting
exceptions PendSV within SVC.  RETTOBASE is 0x800 in ICSR.

> 1..12
> # BASEPRI mask 00e0
> # DEBUG prio 00e0
> ok 1 -  ==  ICSR
> ok 2 -  ==  SHCSR
> # Call SVC
> # In SVC
> ok 3 - 080b == 080b ICSR
> ok 4 - 0080 == 0080 SHCSR
> # In PendSV
> ok 5 - 000e == 000e ICSR
> ok 6 - 0480 == 0480 SHCSR
> # Back in SVC
> ok 7 - 0003 == 0003 Back in SVC
> ok 8 - 080b == 080b ICSR
> ok 9 - 0080 == 0080 SHCSR
> # Back in main
> ok 10 - 0004 == 0004 Back in main
> ok 11 -  ==  ICSR
> ok 12 -  ==  SHCSR
> # Done

[1] https://github.com/mdavidsaver/baremetal/blob/qemutest/test10.c




Re: [Qemu-devel] [PATCH v2 01/26] armv7m: MRS/MSR handle unprivileged access

2017-01-12 Thread Michael Davidsaver
On 01/12/2017 09:14 AM, Peter Maydell wrote:
> ...
> Michael has confirmed to me that this was just an oversight.

This was me not knowing the process.  (just to confirm this publicly)




signature.asc
Description: OpenPGP digital signature


Re: [Qemu-devel] Any progress with the Cortex-M4 emulation?

2016-04-06 Thread Michael Davidsaver
On 04/06/2016 06:23 PM, Liviu Ionescu wrote:
> 
>> On 07 Apr 2016, at 01:04, Peter Maydell  wrote:
>>
>> ... Somebody needs to do the necessary work to fix the
>> code review issues. ...
> 
> in this case I'll probably wait for this process to be completed and 
> reevaluate the situation by then.

Liviu,

I haven't had time to complete a revision of my patch set so far this year.  
I've been busy with other work (good for me, bad for qemu), and don't see this 
situation changing for an least the next two months.  It sounds like you have 
time and inclination to do part of what I've started.  I hope my having done 
half of a too big job won't keep you from finishing part of it.

If you decide to work on this problem, please don't hesitate to appropriate, or 
ignore, what I've done so far.

For what it's worth, I did start another revision back in February.  It does 
include the change Peter requested to the storage of priorities wrt. prigroup, 
but doesn't break up the big "rewrite NVIC" patch.

https://github.com/mdavidsaver/qemu/tree/fixirq2

Separately, I have a set of target test programs which I can run both with qemu 
and a real board.  They mostly agree.  Aside from test8.c (MPU) they might be 
of interest.

https://github.com/mdavidsaver/baremetal/tree/qemutest



Michael



Re: [Qemu-devel] [PATCH v2 05/26] armv7m: add armv7m_excp_running_prio()

2015-12-27 Thread Michael Davidsaver
On 12/17/2015 09:36 AM, Peter Maydell wrote:
> On 3 December 2015 at 00:18, Michael Davidsaver <mdavidsa...@gmail.com> wrote:
>> Implements v7m exception priority algorithm
>> using FAULTMASK, PRIMASK, BASEPRI, and the highest
>> priority active exception.
>>
>> The number returned is the current execution priority
>> which may be in the range [-2,0x7f] when an exception is active
>> or 0x100 when no exception is active.
>> ---
>>  hw/intc/armv7m_nvic.c | 25 +
>>  target-arm/cpu.h  |  1 +
>>  2 files changed, 26 insertions(+)
>>
>> diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
>> index 6fc167e..0145ca7 100644
>> --- a/hw/intc/armv7m_nvic.c
>> +++ b/hw/intc/armv7m_nvic.c
>> @@ -18,6 +18,8 @@
>>
>>  typedef struct {
>>  GICState gic;
>> +uint8_t prigroup;
>> +
>>  struct {
>>  uint32_t control;
>>  uint32_t reload;
>> @@ -116,6 +118,29 @@ static void systick_reset(nvic_state *s)
>>  timer_del(s->systick.timer);
>>  }
>>
>> +/* @returns the active (running) exception priority.
>> + *only a higher (numerically lower) priority can preempt.
>> + */
>> +int armv7m_excp_running_prio(ARMCPU *cpu)
>> +{
>> +CPUARMState *env = >env;
>> +nvic_state *s = env->nvic;
>> +int running;
>> +
>> +if (env->daif & PSTATE_F) { /* FAULTMASK */
>> +running = -1;
>> +} else if (env->daif & PSTATE_I) { /* PRIMASK */
>> +running = 0;
>> +} else if (env->v7m.basepri > 0) {
>> +/* BASEPRI==1 -> masks [1,255] (not same as PRIMASK==1) */
>> +running = env->v7m.basepri >> (s->prigroup+1);
> This isn't right -- the effect of PRIGROUP is that we mask
> out the lower (subgroup) bits, but the upper group bits stay
> where they are rather than shifting down.
>
> So you want env->v7m.basepri & ~((1 << (s->prigroup + 1)) - 1);
>
> (the same mask you need to get the group priority for
> an interrupt).

I don't know about "right", but it is consistent with how the
.prio_group field is now handled in the nvic.  So I think the final
behavior is as specified.

There is no functional reason that I do this.  I just think it makes the
DPRINTF messages easier to interpret.  If you feel strongly I can change
this.




Re: [Qemu-devel] [PATCH v2 02/26] armv7m: Undo armv7m.hack

2015-12-27 Thread Michael Davidsaver
On 12/17/2015 10:38 AM, Peter Maydell wrote:
> On 3 December 2015 at 00:18, Michael Davidsaver <mdavidsa...@gmail.com> wrote:
>> Add CPU unassigned access handler in place of special
>> MemoryRegion to catch exception returns.
>>
>> The unassigned handler will signal other faults as either
>> prefetch or data exceptions, with the FSR code 0x8 to
>> distinguish them from memory translation faults (0xd).
>> Future code will make use of this distinction when
>> deciding to raise BusFault or MemManage exceptions.
> This patch breaks my Stellaris test image -- instead of starting
> it just sits there with a black screen.
>
> I've put a copy of that test image up at
>   http://people.linaro.org/~peter.maydell/stellaris.tgz
> You can run it with path/to/stellaris/runme path/to/qemu-system-arm .

There were several issues.  Two bugs (wrong IRQ enabled and systick not
enabled) and a "feature" (access to unimplemented registers for a PWM
controller is now a BusFault).

As a workaround for the "feature" I add a low priority MemoryRegion from
0x4000 -> 0x40ff which completes all reads with zero and logs. 
Please advise on how this should be handled.

With these changes both test programs appear to run correctly, although
the http server example has painfully slow load times and seems to hit
an out of memory condition if I look at it wrong.  Is this expected? 
(and the blub on the buttons page about "xml technology" is priceless)

I can see that the http server example spends some time attempting MII
operations on the NIC.  As these aren't modeled it spins and eventually
gives up.

> ...
> We could use a comment here (a) explaining what we're doing and (b)
> mentioning that this isn't architecturally correct -- ideally we
> should catch these exception exits on execution of the jump insn, not
> by letting the jump execute and then trapping when we actually try to
> execute at the magic addresses. 

Will do.

>> ...
>> @@ -294,19 +313,9 @@ static bool arm_v7m_cpu_exec_interrupt(CPUState *cs, 
>> int interrupt_request)
>>  cc->do_interrupt(cs);
>>  ret = true;
>>  }
>> -/* ARMv7-M interrupt return works by loading a magic value
>> - * into the PC.  On real hardware the load causes the
>> - * return to occur.  The qemu implementation performs the
>> - * jump normally, then does the exception return when the
>> - * CPU tries to execute code at the magic address.
>> - * This will cause the magic PC value to be pushed to
>> - * the stack if an interrupt occurred at the wrong time.
>> - * We avoid this by disabling interrupts when
>> - * pc contains a magic address.
>> - */
>>  if (interrupt_request & CPU_INTERRUPT_HARD
>>  && !(env->daif & PSTATE_I)
>> -&& (env->regs[15] < 0xfff0)) {
>> +) {
> Can we really drop this change? The thing it's guarding against
> (interrupt comes in while the PC is this not-really-an-address
> value) can still happen whether we catch the attempt to execute
> in translate.c or via the unassigned-access hook.

I don't think the M-profile case in gen_intermediate_code() in
translate.c can ever be reached without first hitting the unassigned
memory handler.  Before the code can be translated, the page containing
it must be loaded.  Such loads no longer succeed.

Put more literally, gen_intermediate_code() is only called from
tb_gen_code() where it comes after a call to get_page_addr_code(),
wherein the unassigned handler calls cpu_loop_exit().

I've replaced the M case for EXCP_EXCEPTION_EXIT in
gen_intermediate_code() with an assert.  So far it hasn't failed.




Re: [Qemu-devel] [PATCH v2 03/26] armv7m: Explicit error for bad vector table

2015-12-27 Thread Michael Davidsaver
On 12/17/2015 08:25 AM, Peter Maydell wrote:
> On 3 December 2015 at 00:18, Michael Davidsaver <mdavidsa...@gmail.com> wrote:
>> ...
>> +static
>> +uint32_t arm_v7m_load_vector(ARMCPU *cpu)
>> +
>> +{
>> +CPUState *cs = >parent_obj;
> This isn't the right way to cast to the base class of a QOM object.
> You want:
>CPUState *cs = CPU(cpu);

from cpu.h

> /* Since this macro is used a lot in hot code paths and in conjunction
> with
>  * FooCPU *foo_env_get_cpu(), we deviate from usual QOM practice by using
>  * an unchecked cast.
>  */
> #define CPU(obj) ((CPUState *)(obj))

Given the present definition of CPU() this change seems like a step
backwards in terms of safety as mis-use won't be caught at compile or
runtime.  I'll change it anyway.


>
>> +CPUARMState *env = >env;
>> +MemTxResult result;
>> +hwaddr vec = env->v7m.vecbase + env->v7m.exception * 4;
>> +uint32_t addr;
>> +
>> +addr = address_space_ldl(cs->as, vec,
>> + MEMTXATTRS_UNSPECIFIED, );
>> +if (result != MEMTX_OK) {
> We could use a comment here:
>/* Architecturally this should cause a HardFault setting HSFR.VECTTBL,
> * which would then be immediately followed by our failing to load
> * the entry vector for that HardFault, which is a Lockup case.
> * Since we don't model Lockup, we just report this guest error
> * via cpu_abort().
> */

Added.




Re: [Qemu-devel] [PATCH v2 06/26] armv7m: fix I and F flag handling

2015-12-27 Thread Michael Davidsaver
On 12/17/2015 10:18 AM, Peter Maydell wrote:
> On 17 December 2015 at 14:39, Peter Maydell <peter.mayd...@linaro.org> wrote:
>> On 3 December 2015 at 00:18, Michael Davidsaver <mdavidsa...@gmail.com> 
>> wrote:
>>> Despite having the same notation, these bits
>>> have completely different meaning than -AR.
>>>
>>> Use armv7m_excp_running_prio() and the highest
>>> pending exception priority to determine
>>> if the pending exception can interrupt preempt.
>>> ---
>>>  target-arm/cpu.c | 16 ++--
>>>  1 file changed, 6 insertions(+), 10 deletions(-)
>> Reviewed-by: Peter Maydell <peter.mayd...@linaro.org>
> ...except this breaks the build for linux-user:
>
>   LINK  arm-linux-user/qemu-arm
> target-arm/cpu.o: In function `arm_v7m_cpu_exec_interrupt':
> /home/petmay01/linaro/qemu-from-laptop/qemu/target-arm/cpu.c:316:
> undefined reference to `armv7m_excp_running_prio'
>
> because the function you're calling here is in armv7m_nvic.c,
> which isn't compiled into the linux-user binary.

Is there any reason to include the armv7m code in linux-user at all?




Re: [Qemu-devel] [PATCH v2 02/26] armv7m: Undo armv7m.hack

2015-12-27 Thread Michael Davidsaver
On 12/17/2015 10:38 AM, Peter Maydell wrote:
> We could use a comment here (a) explaining what we're doing and (b)
> mentioning that this isn't architecturally correct -- ideally we should
> catch these exception exits on execution of the jump insn, not by
> letting the jump execute and then trapping when we actually try to
> execute at the magic addresses.

I had an instructive little digression to investigate doing things the
"right way" (in tcg).  I can see how it would be done by adding a
conditional every time the PC could be updated.  To me the unassigned
handler trick/hack seems simpler (less likely to add a bug) and avoids
emitting more code for every ldm/pop instruction.




Re: [Qemu-devel] [PATCH 01/18] armv7m: MRS/MSR handle unprivileged access

2015-12-02 Thread Michael Davidsaver


On 11/17/2015 12:09 PM, Peter Maydell wrote:
> On 9 November 2015 at 01:11, Michael Davidsaver <mdavidsa...@gmail.com> wrote:
>> The MRS and MSR instruction handling isn't checking
>> the current permission level.
>>
>> Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
>> ---
>>  target-arm/helper.c | 79 
>> +
>>  1 file changed, 37 insertions(+), 42 deletions(-)
> 
> This patch looks good overall, but there's one style nit:
> 
>> +case 0 ... 7: /* xPSR sub-fields */
>> +mask = 0;
>> +if ((reg&1) && el) {
> 
> you want spaces around operators, so "reg & 1" here and elsewhere.

Would be nice if checkpatch.pl caught these, but I understand that this would 
be quite difficult to do well.  I've tried to catch this with grep and sort 
through the false positives.  I think I got them all.

> It would also be good to mention in the commit message the
> other things this patch is fixing:
>  * privileged attempts to write EPSR should do nothing
>  * accessing an unknown special register now triggers a
>guest-error warning rather than aborting QEMU

Will do.



Re: [Qemu-devel] [PATCH 05/18] armv7m: expand NVIC state

2015-12-02 Thread Michael Davidsaver


On 11/17/2015 01:10 PM, Peter Maydell wrote:
> On 9 November 2015 at 01:11, Michael Davidsaver <mdavidsa...@gmail.com> wrote:
>> Expand the NVIC to fully support -M priorities and masking.
>> Doesn't use GIC code.
>>
>> Move some state to ARMCPU to allow calculation of exception masking.
>>
>> Add storage for PRIGROUP to configure group/sub-group split.
>> Track group and sub-group in separate fields for quick comparison.
>> Mix in vector # with sub-group as per tie breaking rules.
>>
>> NVIC now derives directly from SysBusDevice, and
>> struct NVICClass is eliminated.
>>
>> Also add DPRINTF() macro.
>>
>> Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
> 
> This patch doesn't compile, because you've removed the definition of
> NVICClass, NVIC_CLASS, etc, but not their uses. A patchset needs to
> compile after every patch in it, not just at the end when all patches
> are applied. You'll need to rearrange your changes between patches
> a bit.

In the next rev. I've rearranged things so that each patches compiles.  At 
least according to 'git rebase -i -x make', so not a full rebuilt.

This does mean that the big block of changes to the NVIC are now almost 
entirely in one patch as I couldn't see how to split them up given that the 
nvic_state structure is changed so much.



Re: [Qemu-devel] [PATCH 00/18] Fix exception handling and msr/mrs access

2015-12-02 Thread Michael Davidsaver
On 11/20/2015 08:59 AM, Peter Maydell wrote:
> I think I've now done that at least for the earlier patches.
> There are probably some other finer details that I'll get to
> in a later round of patch review but hopefully you have enough
> to do some of the fixes and restructuring of this patchset for v2

Thanks for the comments.  I'll be addressing them individually and follow that 
with another patch set.



  1   2   >