174769fe7SAndreas Färber /* 274769fe7SAndreas Färber * QTest testcase for Realtek 8139 NIC 374769fe7SAndreas Färber * 474769fe7SAndreas Färber * Copyright (c) 2013-2014 SUSE LINUX Products GmbH 574769fe7SAndreas Färber * 674769fe7SAndreas Färber * This work is licensed under the terms of the GNU GPL, version 2 or later. 774769fe7SAndreas Färber * See the COPYING file in the top-level directory. 874769fe7SAndreas Färber */ 974769fe7SAndreas Färber 10681c28a3SPeter Maydell #include "qemu/osdep.h" 1174769fe7SAndreas Färber #include "libqtest.h" 12069bb583SFrediano Ziglio #include "libqos/pci-pc.h" 13e0cf11f3SAlberto Garcia #include "qemu/timer.h" 14069bb583SFrediano Ziglio #include "qemu-common.h" 1574769fe7SAndreas Färber 1674769fe7SAndreas Färber /* Tests only initialization so far. TODO: Replace with functional tests */ 1774769fe7SAndreas Färber static void nop(void) 1874769fe7SAndreas Färber { 1974769fe7SAndreas Färber } 2074769fe7SAndreas Färber 2137b9ab92SLaurent Vivier #define CLK 33333333 22069bb583SFrediano Ziglio 23069bb583SFrediano Ziglio static QPCIBus *pcibus; 24069bb583SFrediano Ziglio static QPCIDevice *dev; 25b4ba67d9SDavid Gibson static QPCIBar dev_bar; 26069bb583SFrediano Ziglio 27069bb583SFrediano Ziglio static void save_fn(QPCIDevice *dev, int devfn, void *data) 28069bb583SFrediano Ziglio { 29069bb583SFrediano Ziglio QPCIDevice **pdev = (QPCIDevice **) data; 30069bb583SFrediano Ziglio 31069bb583SFrediano Ziglio *pdev = dev; 32069bb583SFrediano Ziglio } 33069bb583SFrediano Ziglio 34069bb583SFrediano Ziglio static QPCIDevice *get_device(void) 35069bb583SFrediano Ziglio { 36069bb583SFrediano Ziglio QPCIDevice *dev; 37069bb583SFrediano Ziglio 38*143e6db6SEmanuele Giuseppe Esposito pcibus = qpci_new_pc(global_qtest, NULL); 39069bb583SFrediano Ziglio qpci_device_foreach(pcibus, 0x10ec, 0x8139, save_fn, &dev); 40069bb583SFrediano Ziglio g_assert(dev != NULL); 41069bb583SFrediano Ziglio 42069bb583SFrediano Ziglio return dev; 43069bb583SFrediano Ziglio } 44069bb583SFrediano Ziglio 45069bb583SFrediano Ziglio #define PORT(name, len, val) \ 46069bb583SFrediano Ziglio static unsigned __attribute__((unused)) in_##name(void) \ 47069bb583SFrediano Ziglio { \ 48b4ba67d9SDavid Gibson unsigned res = qpci_io_read##len(dev, dev_bar, (val)); \ 49069bb583SFrediano Ziglio g_test_message("*%s -> %x\n", #name, res); \ 50069bb583SFrediano Ziglio return res; \ 51069bb583SFrediano Ziglio } \ 52069bb583SFrediano Ziglio static void out_##name(unsigned v) \ 53069bb583SFrediano Ziglio { \ 54069bb583SFrediano Ziglio g_test_message("%x -> *%s\n", v, #name); \ 55b4ba67d9SDavid Gibson qpci_io_write##len(dev, dev_bar, (val), v); \ 56069bb583SFrediano Ziglio } 57069bb583SFrediano Ziglio 58069bb583SFrediano Ziglio PORT(Timer, l, 0x48) 59069bb583SFrediano Ziglio PORT(IntrMask, w, 0x3c) 60069bb583SFrediano Ziglio PORT(IntrStatus, w, 0x3E) 61069bb583SFrediano Ziglio PORT(TimerInt, l, 0x54) 62069bb583SFrediano Ziglio 63069bb583SFrediano Ziglio #define fatal(...) do { g_test_message(__VA_ARGS__); g_assert(0); } while (0) 64069bb583SFrediano Ziglio 65069bb583SFrediano Ziglio static void test_timer(void) 66069bb583SFrediano Ziglio { 67069bb583SFrediano Ziglio const unsigned from = 0.95 * CLK; 68069bb583SFrediano Ziglio const unsigned to = 1.6 * CLK; 69069bb583SFrediano Ziglio unsigned prev, curr, next; 70069bb583SFrediano Ziglio unsigned cnt, diff; 71069bb583SFrediano Ziglio 72069bb583SFrediano Ziglio out_IntrMask(0); 73069bb583SFrediano Ziglio 74069bb583SFrediano Ziglio in_IntrStatus(); 75069bb583SFrediano Ziglio in_Timer(); 76069bb583SFrediano Ziglio in_Timer(); 77069bb583SFrediano Ziglio 78069bb583SFrediano Ziglio /* Test 1. test counter continue and continue */ 79069bb583SFrediano Ziglio out_TimerInt(0); /* disable timer */ 80069bb583SFrediano Ziglio out_IntrStatus(0x4000); 81069bb583SFrediano Ziglio out_Timer(12345); /* reset timer to 0 */ 82069bb583SFrediano Ziglio curr = in_Timer(); 83069bb583SFrediano Ziglio if (curr > 0.1 * CLK) { 84069bb583SFrediano Ziglio fatal("time too big %u\n", curr); 85069bb583SFrediano Ziglio } 86069bb583SFrediano Ziglio for (cnt = 0; ; ) { 8713566fe3SStefan Hajnoczi clock_step(1 * NANOSECONDS_PER_SECOND); 88069bb583SFrediano Ziglio prev = curr; 89069bb583SFrediano Ziglio curr = in_Timer(); 90069bb583SFrediano Ziglio 91069bb583SFrediano Ziglio /* test skip is in a specific range */ 92069bb583SFrediano Ziglio diff = (curr-prev) & 0xffffffffu; 93069bb583SFrediano Ziglio if (diff < from || diff > to) { 94069bb583SFrediano Ziglio fatal("Invalid diff %u (%u-%u)\n", diff, from, to); 95069bb583SFrediano Ziglio } 96069bb583SFrediano Ziglio if (curr < prev && ++cnt == 3) { 97069bb583SFrediano Ziglio break; 98069bb583SFrediano Ziglio } 99069bb583SFrediano Ziglio } 100069bb583SFrediano Ziglio 101069bb583SFrediano Ziglio /* Test 2. Check we didn't get an interrupt with TimerInt == 0 */ 102069bb583SFrediano Ziglio if (in_IntrStatus() & 0x4000) { 103069bb583SFrediano Ziglio fatal("got an interrupt\n"); 104069bb583SFrediano Ziglio } 105069bb583SFrediano Ziglio 106069bb583SFrediano Ziglio /* Test 3. Setting TimerInt to 1 and Timer to 0 get interrupt */ 107069bb583SFrediano Ziglio out_TimerInt(1); 108069bb583SFrediano Ziglio out_Timer(0); 109069bb583SFrediano Ziglio clock_step(40); 110069bb583SFrediano Ziglio if ((in_IntrStatus() & 0x4000) == 0) { 111069bb583SFrediano Ziglio fatal("we should have an interrupt here!\n"); 112069bb583SFrediano Ziglio } 113069bb583SFrediano Ziglio 114069bb583SFrediano Ziglio /* Test 3. Check acknowledge */ 115069bb583SFrediano Ziglio out_IntrStatus(0x4000); 116069bb583SFrediano Ziglio if (in_IntrStatus() & 0x4000) { 117069bb583SFrediano Ziglio fatal("got an interrupt\n"); 118069bb583SFrediano Ziglio } 119069bb583SFrediano Ziglio 120069bb583SFrediano Ziglio /* Test. Status set after Timer reset */ 121069bb583SFrediano Ziglio out_Timer(0); 122069bb583SFrediano Ziglio out_TimerInt(0); 123069bb583SFrediano Ziglio out_IntrStatus(0x4000); 124069bb583SFrediano Ziglio curr = in_Timer(); 125069bb583SFrediano Ziglio out_TimerInt(curr + 0.5 * CLK); 12613566fe3SStefan Hajnoczi clock_step(1 * NANOSECONDS_PER_SECOND); 127069bb583SFrediano Ziglio out_Timer(0); 128069bb583SFrediano Ziglio if ((in_IntrStatus() & 0x4000) == 0) { 129069bb583SFrediano Ziglio fatal("we should have an interrupt here!\n"); 130069bb583SFrediano Ziglio } 131069bb583SFrediano Ziglio 132069bb583SFrediano Ziglio /* Test. Status set after TimerInt reset */ 133069bb583SFrediano Ziglio out_Timer(0); 134069bb583SFrediano Ziglio out_TimerInt(0); 135069bb583SFrediano Ziglio out_IntrStatus(0x4000); 136069bb583SFrediano Ziglio curr = in_Timer(); 137069bb583SFrediano Ziglio out_TimerInt(curr + 0.5 * CLK); 13813566fe3SStefan Hajnoczi clock_step(1 * NANOSECONDS_PER_SECOND); 139069bb583SFrediano Ziglio out_TimerInt(0); 140069bb583SFrediano Ziglio if ((in_IntrStatus() & 0x4000) == 0) { 141069bb583SFrediano Ziglio fatal("we should have an interrupt here!\n"); 142069bb583SFrediano Ziglio } 143069bb583SFrediano Ziglio 144069bb583SFrediano Ziglio /* Test 4. Increment TimerInt we should see an interrupt */ 145069bb583SFrediano Ziglio curr = in_Timer(); 146069bb583SFrediano Ziglio next = curr + 5.0 * CLK; 147069bb583SFrediano Ziglio out_TimerInt(next); 148069bb583SFrediano Ziglio for (cnt = 0; ; ) { 14913566fe3SStefan Hajnoczi clock_step(1 * NANOSECONDS_PER_SECOND); 150069bb583SFrediano Ziglio prev = curr; 151069bb583SFrediano Ziglio curr = in_Timer(); 152069bb583SFrediano Ziglio diff = (curr-prev) & 0xffffffffu; 153069bb583SFrediano Ziglio if (diff < from || diff > to) { 154069bb583SFrediano Ziglio fatal("Invalid diff %u (%u-%u)\n", diff, from, to); 155069bb583SFrediano Ziglio } 156069bb583SFrediano Ziglio if (cnt < 3 && curr > next) { 157069bb583SFrediano Ziglio if ((in_IntrStatus() & 0x4000) == 0) { 158069bb583SFrediano Ziglio fatal("we should have an interrupt here!\n"); 159069bb583SFrediano Ziglio } 160069bb583SFrediano Ziglio out_IntrStatus(0x4000); 161069bb583SFrediano Ziglio next = curr + 5.0 * CLK; 162069bb583SFrediano Ziglio out_TimerInt(next); 163069bb583SFrediano Ziglio if (++cnt == 3) { 164069bb583SFrediano Ziglio out_TimerInt(1); 165069bb583SFrediano Ziglio } 166069bb583SFrediano Ziglio /* Test 5. Second time we pass from 0 should see an interrupt */ 167069bb583SFrediano Ziglio } else if (cnt >= 3 && curr < prev) { 168069bb583SFrediano Ziglio /* here we should have an interrupt */ 169069bb583SFrediano Ziglio if ((in_IntrStatus() & 0x4000) == 0) { 170069bb583SFrediano Ziglio fatal("we should have an interrupt here!\n"); 171069bb583SFrediano Ziglio } 172069bb583SFrediano Ziglio out_IntrStatus(0x4000); 173069bb583SFrediano Ziglio if (++cnt == 5) { 174069bb583SFrediano Ziglio break; 175069bb583SFrediano Ziglio } 176069bb583SFrediano Ziglio } 177069bb583SFrediano Ziglio } 178069bb583SFrediano Ziglio 179069bb583SFrediano Ziglio g_test_message("Everythink is ok!\n"); 180069bb583SFrediano Ziglio } 181069bb583SFrediano Ziglio 182069bb583SFrediano Ziglio 183069bb583SFrediano Ziglio static void test_init(void) 184069bb583SFrediano Ziglio { 185069bb583SFrediano Ziglio uint64_t barsize; 186069bb583SFrediano Ziglio 187069bb583SFrediano Ziglio dev = get_device(); 188069bb583SFrediano Ziglio 189b4ba67d9SDavid Gibson dev_bar = qpci_iomap(dev, 0, &barsize); 190069bb583SFrediano Ziglio 191069bb583SFrediano Ziglio qpci_device_enable(dev); 192069bb583SFrediano Ziglio 193069bb583SFrediano Ziglio test_timer(); 194069bb583SFrediano Ziglio } 195069bb583SFrediano Ziglio 19674769fe7SAndreas Färber int main(int argc, char **argv) 19774769fe7SAndreas Färber { 19874769fe7SAndreas Färber int ret; 19974769fe7SAndreas Färber 200e5d1730dSEric Blake qtest_start("-device rtl8139"); 201e5d1730dSEric Blake 20274769fe7SAndreas Färber g_test_init(&argc, &argv, NULL); 20374769fe7SAndreas Färber qtest_add_func("/rtl8139/nop", nop); 204069bb583SFrediano Ziglio qtest_add_func("/rtl8139/timer", test_init); 20574769fe7SAndreas Färber 20674769fe7SAndreas Färber ret = g_test_run(); 20774769fe7SAndreas Färber 20874769fe7SAndreas Färber qtest_end(); 20974769fe7SAndreas Färber 21074769fe7SAndreas Färber return ret; 21174769fe7SAndreas Färber } 212