@ -68,6 +68,16 @@ static const CMSDKAPBWatchdogTestArgs machine_info[] = {
} ,
} ;
static void system_reset ( QTestState * qtest )
{
QDict * resp ;
resp = qtest_qmp ( qtest , " {'execute': 'system_reset'} " ) ;
g_assert ( qdict_haskey ( resp , " return " ) ) ;
qobject_unref ( resp ) ;
qtest_qmp_eventwait ( qtest , " RESET " ) ;
}
static void test_watchdog ( const void * ptr )
{
const CMSDKAPBWatchdogTestArgs * args = ptr ;
@ -159,6 +169,199 @@ static void test_clock_change(const void *ptr)
qtest_end ( ) ;
}
/* Tests the counter is not running after reset. */
static void test_watchdog_reset ( const void * ptr )
{
const CMSDKAPBWatchdogTestArgs * args = ptr ;
hwaddr wdog_base = args - > wdog_base ;
int64_t tick = args - > tick ;
g_autofree gchar * cmdline = g_strdup_printf ( " -machine %s " , args - > machine ) ;
qtest_start ( cmdline ) ;
g_assert_cmpuint ( readl ( wdog_base + WDOGRIS ) , = = , 0 ) ;
g_assert_cmphex ( readl ( wdog_base + WDOGLOAD ) , = = , WDOGLOAD_DEFAULT ) ;
g_assert_cmphex ( readl ( wdog_base + WDOGVALUE ) , = = , WDOGVALUE_DEFAULT ) ;
g_assert_cmphex ( readl ( wdog_base + WDOGCONTROL ) , = = , 0 ) ;
/*
* The counter should not be running if WDOGCONTROL . INTEN has not been set ,
* as it is the case after a cold reset .
*/
clock_step ( 15 * tick + 1 ) ;
g_assert_cmphex ( readl ( wdog_base + WDOGLOAD ) , = = , WDOGLOAD_DEFAULT ) ;
g_assert_cmphex ( readl ( wdog_base + WDOGVALUE ) , = = , WDOGVALUE_DEFAULT ) ;
/* Let the counter run before reset */
writel ( wdog_base + WDOGLOAD , 3000 ) ;
writel ( wdog_base + WDOGCONTROL , 1 ) ;
/* Verify it is running */
clock_step ( 1000 * tick + 1 ) ;
g_assert_cmpuint ( readl ( wdog_base + WDOGLOAD ) , = = , 3000 ) ;
g_assert_cmpuint ( readl ( wdog_base + WDOGVALUE ) , = = , 2000 ) ;
system_reset ( global_qtest ) ;
/* Check defaults after reset */
g_assert_cmphex ( readl ( wdog_base + WDOGLOAD ) , = = , WDOGLOAD_DEFAULT ) ;
g_assert_cmphex ( readl ( wdog_base + WDOGVALUE ) , = = , WDOGVALUE_DEFAULT ) ;
/* The counter should not be running after reset. */
clock_step ( 1000 * tick + 1 ) ;
g_assert_cmphex ( readl ( wdog_base + WDOGLOAD ) , = = , WDOGLOAD_DEFAULT ) ;
g_assert_cmphex ( readl ( wdog_base + WDOGVALUE ) , = = , WDOGVALUE_DEFAULT ) ;
qtest_end ( ) ;
}
/*
* Tests inten works as the counter enable based on this description :
*
* Enable the interrupt event , WDOGINT . Set HIGH to enable the counter and the
* interrupt , or LOW to disable the counter and interrupt . Reloads the counter
* from the value in WDOGLOAD when the interrupt is enabled , after previously
* being disabled .
*/
static void test_watchdog_inten ( const void * ptr )
{
const CMSDKAPBWatchdogTestArgs * args = ptr ;
hwaddr wdog_base = args - > wdog_base ;
int64_t tick = args - > tick ;
g_autofree gchar * cmdline = g_strdup_printf ( " -machine %s " , args - > machine ) ;
qtest_start ( cmdline ) ;
g_assert_cmpuint ( readl ( wdog_base + WDOGRIS ) , = = , 0 ) ;
g_assert_cmphex ( readl ( wdog_base + WDOGLOAD ) , = = , WDOGLOAD_DEFAULT ) ;
g_assert_cmphex ( readl ( wdog_base + WDOGVALUE ) , = = , WDOGVALUE_DEFAULT ) ;
/*
* When WDOGLOAD is written to , the count is immediately restarted from the
* new value .
*
* Note : the counter should not be running as long as WDOGCONTROL . INTEN is
* not set
*/
writel ( wdog_base + WDOGLOAD , 4000 ) ;
g_assert_cmpuint ( readl ( wdog_base + WDOGLOAD ) , = = , 4000 ) ;
g_assert_cmpuint ( readl ( wdog_base + WDOGVALUE ) , = = , 4000 ) ;
clock_step ( 500 * tick + 1 ) ;
g_assert_cmpuint ( readl ( wdog_base + WDOGLOAD ) , = = , 4000 ) ;
g_assert_cmpuint ( readl ( wdog_base + WDOGVALUE ) , = = , 4000 ) ;
/* Set HIGH WDOGCONTROL.INTEN to enable the counter and the interrupt */
writel ( wdog_base + WDOGCONTROL , 1 ) ;
clock_step ( 500 * tick + 1 ) ;
g_assert_cmpuint ( readl ( wdog_base + WDOGLOAD ) , = = , 4000 ) ;
g_assert_cmpuint ( readl ( wdog_base + WDOGVALUE ) , = = , 3500 ) ;
/* or LOW to disable the counter and interrupt. */
writel ( wdog_base + WDOGCONTROL , 0 ) ;
clock_step ( 100 * tick ) ;
g_assert_cmpuint ( readl ( wdog_base + WDOGLOAD ) , = = , 4000 ) ;
g_assert_cmpuint ( readl ( wdog_base + WDOGVALUE ) , = = , 3500 ) ;
/*
* Reloads the counter from the value in WDOGLOAD when the interrupt is
* enabled , after previously being disabled .
*/
writel ( wdog_base + WDOGCONTROL , 1 ) ;
g_assert_cmpuint ( readl ( wdog_base + WDOGLOAD ) , = = , 4000 ) ;
g_assert_cmpuint ( readl ( wdog_base + WDOGVALUE ) , = = , 4000 ) ;
/* Test counter is still on */
clock_step ( 50 * tick + 1 ) ;
g_assert_cmpuint ( readl ( wdog_base + WDOGLOAD ) , = = , 4000 ) ;
g_assert_cmpuint ( readl ( wdog_base + WDOGVALUE ) , = = , 3950 ) ;
/*
* When WDOGLOAD is written to , the count is immediately restarted from the
* new value .
*
* Note : the counter should be running since WDOGCONTROL . INTEN is set
*/
writel ( wdog_base + WDOGLOAD , 5000 ) ;
g_assert_cmpuint ( readl ( wdog_base + WDOGLOAD ) , = = , 5000 ) ;
g_assert_cmpuint ( readl ( wdog_base + WDOGVALUE ) , = = , 5000 ) ;
clock_step ( 4999 * tick + 1 ) ;
g_assert_cmpuint ( readl ( wdog_base + WDOGLOAD ) , = = , 5000 ) ;
g_assert_cmpuint ( readl ( wdog_base + WDOGVALUE ) , = = , 1 ) ;
g_assert_cmpuint ( readl ( wdog_base + WDOGRIS ) , = = , 0 ) ;
/* Finally disable and check the conditions don't change */
writel ( wdog_base + WDOGCONTROL , 0 ) ;
clock_step ( 10 * tick ) ;
g_assert_cmpuint ( readl ( wdog_base + WDOGLOAD ) , = = , 5000 ) ;
g_assert_cmpuint ( readl ( wdog_base + WDOGVALUE ) , = = , 1 ) ;
g_assert_cmpuint ( readl ( wdog_base + WDOGRIS ) , = = , 0 ) ;
qtest_end ( ) ;
}
/*
* Tests the following custom behavior :
*
* The Luminary version of this device ignores writes to this register after the
* guest has enabled interrupts ( so they can only be disabled again via reset ) .
*/
static void test_watchdog_inten_luminary ( const void * ptr )
{
const CMSDKAPBWatchdogTestArgs * args = ptr ;
hwaddr wdog_base = args - > wdog_base ;
int64_t tick = args - > tick ;
g_autofree gchar * cmdline = g_strdup_printf ( " -machine %s " , args - > machine ) ;
qtest_start ( cmdline ) ;
g_assert_cmpuint ( readl ( wdog_base + WDOGRIS ) , = = , 0 ) ;
g_assert_cmphex ( readl ( wdog_base + WDOGLOAD ) , = = , WDOGLOAD_DEFAULT ) ;
g_assert_cmphex ( readl ( wdog_base + WDOGVALUE ) , = = , WDOGVALUE_DEFAULT ) ;
/*
* When WDOGLOAD is written to , the count is immediately restarted from the
* new value .
*
* Note : the counter should not be running as long as WDOGCONTROL . INTEN is
* not set
*/
writel ( wdog_base + WDOGLOAD , 4000 ) ;
g_assert_cmpuint ( readl ( wdog_base + WDOGLOAD ) , = = , 4000 ) ;
g_assert_cmpuint ( readl ( wdog_base + WDOGVALUE ) , = = , 4000 ) ;
clock_step ( 500 * tick + 1 ) ;
g_assert_cmpuint ( readl ( wdog_base + WDOGLOAD ) , = = , 4000 ) ;
g_assert_cmpuint ( readl ( wdog_base + WDOGVALUE ) , = = , 4000 ) ;
/* Set HIGH WDOGCONTROL.INTEN to enable the counter and the interrupt */
writel ( wdog_base + WDOGCONTROL , 1 ) ;
clock_step ( 500 * tick + 1 ) ;
g_assert_cmpuint ( readl ( wdog_base + WDOGLOAD ) , = = , 4000 ) ;
g_assert_cmpuint ( readl ( wdog_base + WDOGVALUE ) , = = , 3500 ) ;
/*
* The Luminary version of this device ignores writes to this register after
* the guest has enabled interrupts
*/
writel ( wdog_base + WDOGCONTROL , 0 ) ;
clock_step ( 100 * tick ) ;
g_assert_cmpuint ( readl ( wdog_base + WDOGLOAD ) , = = , 4000 ) ;
g_assert_cmpuint ( readl ( wdog_base + WDOGVALUE ) , = = , 3400 ) ;
g_assert_cmphex ( readl ( wdog_base + WDOGCONTROL ) , = = , 0x1 ) ;
/* They can only be disabled again via reset */
system_reset ( global_qtest ) ;
/* Check defaults after reset */
g_assert_cmphex ( readl ( wdog_base + WDOGLOAD ) , = = , WDOGLOAD_DEFAULT ) ;
g_assert_cmphex ( readl ( wdog_base + WDOGVALUE ) , = = , WDOGVALUE_DEFAULT ) ;
g_assert_cmphex ( readl ( wdog_base + WDOGCONTROL ) , = = , 0 ) ;
/* The counter should not be running after reset. */
clock_step ( 1000 * tick + 1 ) ;
g_assert_cmphex ( readl ( wdog_base + WDOGLOAD ) , = = , WDOGLOAD_DEFAULT ) ;
g_assert_cmphex ( readl ( wdog_base + WDOGVALUE ) , = = , WDOGVALUE_DEFAULT ) ;
qtest_end ( ) ;
}
int main ( int argc , char * * argv )
{
int r ;
@ -172,10 +375,22 @@ int main(int argc, char **argv)
qtest_add_data_func ( " /cmsdk-apb-watchdog/watchdog_clock_change " ,
& machine_info [ MACHINE_LM3S811EVB ] ,
test_clock_change ) ;
qtest_add_data_func ( " /cmsdk-apb-watchdog/watchdog_reset " ,
& machine_info [ MACHINE_LM3S811EVB ] ,
test_watchdog_reset ) ;
qtest_add_data_func ( " /cmsdk-apb-watchdog/watchdog_inten_luminary " ,
& machine_info [ MACHINE_LM3S811EVB ] ,
test_watchdog_inten_luminary ) ;
}
if ( qtest_has_machine ( machine_info [ MACHINE_MPS2_AN385 ] . machine ) ) {
qtest_add_data_func ( " /cmsdk-apb-watchdog/watchdog_mps2 " ,
& machine_info [ MACHINE_MPS2_AN385 ] , test_watchdog ) ;
qtest_add_data_func ( " /cmsdk-apb-watchdog/watchdog_reset_mps2 " ,
& machine_info [ MACHINE_MPS2_AN385 ] ,
test_watchdog_reset ) ;
qtest_add_data_func ( " /cmsdk-apb-watchdog/watchdog_inten " ,
& machine_info [ MACHINE_MPS2_AN385 ] ,
test_watchdog_inten ) ;
}
r = g_test_run ( ) ;