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" 11dd210749SThomas Huth #include "libqtest-single.h" 12069bb583SFrediano Ziglio #include "libqos/pci-pc.h" 13e0cf11f3SAlberto Garcia #include "qemu/timer.h" 1474769fe7SAndreas Färber 155ebecf20SThomas Huth static int verbosity_level; 165ebecf20SThomas Huth 1774769fe7SAndreas Färber /* Tests only initialization so far. TODO: Replace with functional tests */ 1874769fe7SAndreas Färber static void nop(void) 1974769fe7SAndreas Färber { 2074769fe7SAndreas Färber } 2174769fe7SAndreas Färber 2237b9ab92SLaurent Vivier #define CLK 33333333 23069bb583SFrediano Ziglio 24069bb583SFrediano Ziglio static QPCIBus *pcibus; 25069bb583SFrediano Ziglio static QPCIDevice *dev; 26b4ba67d9SDavid Gibson static QPCIBar dev_bar; 27069bb583SFrediano Ziglio 28069bb583SFrediano Ziglio static void save_fn(QPCIDevice *dev, int devfn, void *data) 29069bb583SFrediano Ziglio { 30069bb583SFrediano Ziglio QPCIDevice **pdev = (QPCIDevice **) data; 31069bb583SFrediano Ziglio 32069bb583SFrediano Ziglio *pdev = dev; 33069bb583SFrediano Ziglio } 34069bb583SFrediano Ziglio 35069bb583SFrediano Ziglio static QPCIDevice *get_device(void) 36069bb583SFrediano Ziglio { 37069bb583SFrediano Ziglio QPCIDevice *dev; 38069bb583SFrediano Ziglio 39143e6db6SEmanuele Giuseppe Esposito pcibus = qpci_new_pc(global_qtest, NULL); 40069bb583SFrediano Ziglio qpci_device_foreach(pcibus, 0x10ec, 0x8139, save_fn, &dev); 41069bb583SFrediano Ziglio g_assert(dev != NULL); 42069bb583SFrediano Ziglio 43069bb583SFrediano Ziglio return dev; 44069bb583SFrediano Ziglio } 45069bb583SFrediano Ziglio 46069bb583SFrediano Ziglio #define PORT(name, len, val) \ 47069bb583SFrediano Ziglio static unsigned __attribute__((unused)) in_##name(void) \ 48069bb583SFrediano Ziglio { \ 49b4ba67d9SDavid Gibson unsigned res = qpci_io_read##len(dev, dev_bar, (val)); \ 505ebecf20SThomas Huth if (verbosity_level >= 2) { \ 5113ee9e30SThomas Huth g_test_message("*%s -> %x", #name, res); \ 525ebecf20SThomas Huth } \ 53069bb583SFrediano Ziglio return res; \ 54069bb583SFrediano Ziglio } \ 55069bb583SFrediano Ziglio static void out_##name(unsigned v) \ 56069bb583SFrediano Ziglio { \ 575ebecf20SThomas Huth if (verbosity_level >= 2) { \ 5813ee9e30SThomas Huth g_test_message("%x -> *%s", v, #name); \ 595ebecf20SThomas Huth } \ 60b4ba67d9SDavid Gibson qpci_io_write##len(dev, dev_bar, (val), v); \ 61069bb583SFrediano Ziglio } 62069bb583SFrediano Ziglio 63069bb583SFrediano Ziglio PORT(Timer, l, 0x48) 64069bb583SFrediano Ziglio PORT(IntrMask, w, 0x3c) 65069bb583SFrediano Ziglio PORT(IntrStatus, w, 0x3E) 66069bb583SFrediano Ziglio PORT(TimerInt, l, 0x54) 67069bb583SFrediano Ziglio 68069bb583SFrediano Ziglio #define fatal(...) do { g_test_message(__VA_ARGS__); g_assert(0); } while (0) 69069bb583SFrediano Ziglio 70069bb583SFrediano Ziglio static void test_timer(void) 71069bb583SFrediano Ziglio { 72069bb583SFrediano Ziglio const unsigned from = 0.95 * CLK; 73069bb583SFrediano Ziglio const unsigned to = 1.6 * CLK; 74069bb583SFrediano Ziglio unsigned prev, curr, next; 75069bb583SFrediano Ziglio unsigned cnt, diff; 76069bb583SFrediano Ziglio 77069bb583SFrediano Ziglio out_IntrMask(0); 78069bb583SFrediano Ziglio 79069bb583SFrediano Ziglio in_IntrStatus(); 80069bb583SFrediano Ziglio in_Timer(); 81069bb583SFrediano Ziglio in_Timer(); 82069bb583SFrediano Ziglio 83069bb583SFrediano Ziglio /* Test 1. test counter continue and continue */ 84069bb583SFrediano Ziglio out_TimerInt(0); /* disable timer */ 85069bb583SFrediano Ziglio out_IntrStatus(0x4000); 86069bb583SFrediano Ziglio out_Timer(12345); /* reset timer to 0 */ 87069bb583SFrediano Ziglio curr = in_Timer(); 88069bb583SFrediano Ziglio if (curr > 0.1 * CLK) { 89069bb583SFrediano Ziglio fatal("time too big %u\n", curr); 90069bb583SFrediano Ziglio } 91069bb583SFrediano Ziglio for (cnt = 0; ; ) { 9213566fe3SStefan Hajnoczi clock_step(1 * NANOSECONDS_PER_SECOND); 93069bb583SFrediano Ziglio prev = curr; 94069bb583SFrediano Ziglio curr = in_Timer(); 95069bb583SFrediano Ziglio 96069bb583SFrediano Ziglio /* test skip is in a specific range */ 97069bb583SFrediano Ziglio diff = (curr-prev) & 0xffffffffu; 98069bb583SFrediano Ziglio if (diff < from || diff > to) { 99069bb583SFrediano Ziglio fatal("Invalid diff %u (%u-%u)\n", diff, from, to); 100069bb583SFrediano Ziglio } 101069bb583SFrediano Ziglio if (curr < prev && ++cnt == 3) { 102069bb583SFrediano Ziglio break; 103069bb583SFrediano Ziglio } 104069bb583SFrediano Ziglio } 105069bb583SFrediano Ziglio 106069bb583SFrediano Ziglio /* Test 2. Check we didn't get an interrupt with TimerInt == 0 */ 107069bb583SFrediano Ziglio if (in_IntrStatus() & 0x4000) { 108069bb583SFrediano Ziglio fatal("got an interrupt\n"); 109069bb583SFrediano Ziglio } 110069bb583SFrediano Ziglio 111069bb583SFrediano Ziglio /* Test 3. Setting TimerInt to 1 and Timer to 0 get interrupt */ 112069bb583SFrediano Ziglio out_TimerInt(1); 113069bb583SFrediano Ziglio out_Timer(0); 114069bb583SFrediano Ziglio clock_step(40); 115069bb583SFrediano Ziglio if ((in_IntrStatus() & 0x4000) == 0) { 116069bb583SFrediano Ziglio fatal("we should have an interrupt here!\n"); 117069bb583SFrediano Ziglio } 118069bb583SFrediano Ziglio 119069bb583SFrediano Ziglio /* Test 3. Check acknowledge */ 120069bb583SFrediano Ziglio out_IntrStatus(0x4000); 121069bb583SFrediano Ziglio if (in_IntrStatus() & 0x4000) { 122069bb583SFrediano Ziglio fatal("got an interrupt\n"); 123069bb583SFrediano Ziglio } 124069bb583SFrediano Ziglio 125069bb583SFrediano Ziglio /* Test. Status set after Timer reset */ 126069bb583SFrediano Ziglio out_Timer(0); 127069bb583SFrediano Ziglio out_TimerInt(0); 128069bb583SFrediano Ziglio out_IntrStatus(0x4000); 129069bb583SFrediano Ziglio curr = in_Timer(); 130069bb583SFrediano Ziglio out_TimerInt(curr + 0.5 * CLK); 13113566fe3SStefan Hajnoczi clock_step(1 * NANOSECONDS_PER_SECOND); 132069bb583SFrediano Ziglio out_Timer(0); 133069bb583SFrediano Ziglio if ((in_IntrStatus() & 0x4000) == 0) { 134069bb583SFrediano Ziglio fatal("we should have an interrupt here!\n"); 135069bb583SFrediano Ziglio } 136069bb583SFrediano Ziglio 137069bb583SFrediano Ziglio /* Test. Status set after TimerInt reset */ 138069bb583SFrediano Ziglio out_Timer(0); 139069bb583SFrediano Ziglio out_TimerInt(0); 140069bb583SFrediano Ziglio out_IntrStatus(0x4000); 141069bb583SFrediano Ziglio curr = in_Timer(); 142069bb583SFrediano Ziglio out_TimerInt(curr + 0.5 * CLK); 14313566fe3SStefan Hajnoczi clock_step(1 * NANOSECONDS_PER_SECOND); 144069bb583SFrediano Ziglio out_TimerInt(0); 145069bb583SFrediano Ziglio if ((in_IntrStatus() & 0x4000) == 0) { 146069bb583SFrediano Ziglio fatal("we should have an interrupt here!\n"); 147069bb583SFrediano Ziglio } 148069bb583SFrediano Ziglio 149069bb583SFrediano Ziglio /* Test 4. Increment TimerInt we should see an interrupt */ 150069bb583SFrediano Ziglio curr = in_Timer(); 151069bb583SFrediano Ziglio next = curr + 5.0 * CLK; 152069bb583SFrediano Ziglio out_TimerInt(next); 153069bb583SFrediano Ziglio for (cnt = 0; ; ) { 15413566fe3SStefan Hajnoczi clock_step(1 * NANOSECONDS_PER_SECOND); 155069bb583SFrediano Ziglio prev = curr; 156069bb583SFrediano Ziglio curr = in_Timer(); 157069bb583SFrediano Ziglio diff = (curr-prev) & 0xffffffffu; 158069bb583SFrediano Ziglio if (diff < from || diff > to) { 159069bb583SFrediano Ziglio fatal("Invalid diff %u (%u-%u)\n", diff, from, to); 160069bb583SFrediano Ziglio } 161069bb583SFrediano Ziglio if (cnt < 3 && curr > next) { 162069bb583SFrediano Ziglio if ((in_IntrStatus() & 0x4000) == 0) { 163069bb583SFrediano Ziglio fatal("we should have an interrupt here!\n"); 164069bb583SFrediano Ziglio } 165069bb583SFrediano Ziglio out_IntrStatus(0x4000); 166069bb583SFrediano Ziglio next = curr + 5.0 * CLK; 167069bb583SFrediano Ziglio out_TimerInt(next); 168069bb583SFrediano Ziglio if (++cnt == 3) { 169069bb583SFrediano Ziglio out_TimerInt(1); 170069bb583SFrediano Ziglio } 171069bb583SFrediano Ziglio /* Test 5. Second time we pass from 0 should see an interrupt */ 172069bb583SFrediano Ziglio } else if (cnt >= 3 && curr < prev) { 173069bb583SFrediano Ziglio /* here we should have an interrupt */ 174069bb583SFrediano Ziglio if ((in_IntrStatus() & 0x4000) == 0) { 175069bb583SFrediano Ziglio fatal("we should have an interrupt here!\n"); 176069bb583SFrediano Ziglio } 177069bb583SFrediano Ziglio out_IntrStatus(0x4000); 178069bb583SFrediano Ziglio if (++cnt == 5) { 179069bb583SFrediano Ziglio break; 180069bb583SFrediano Ziglio } 181069bb583SFrediano Ziglio } 182069bb583SFrediano Ziglio } 183069bb583SFrediano Ziglio 18413ee9e30SThomas Huth g_test_message("Everythink is ok!"); 185069bb583SFrediano Ziglio } 186069bb583SFrediano Ziglio 187069bb583SFrediano Ziglio 188069bb583SFrediano Ziglio static void test_init(void) 189069bb583SFrediano Ziglio { 190069bb583SFrediano Ziglio uint64_t barsize; 191069bb583SFrediano Ziglio 192069bb583SFrediano Ziglio dev = get_device(); 193069bb583SFrediano Ziglio 194b4ba67d9SDavid Gibson dev_bar = qpci_iomap(dev, 0, &barsize); 195069bb583SFrediano Ziglio 196069bb583SFrediano Ziglio qpci_device_enable(dev); 197069bb583SFrediano Ziglio 198069bb583SFrediano Ziglio test_timer(); 199069bb583SFrediano Ziglio } 200069bb583SFrediano Ziglio 20174769fe7SAndreas Färber int main(int argc, char **argv) 20274769fe7SAndreas Färber { 20374769fe7SAndreas Färber int ret; 2045ebecf20SThomas Huth char *v_env = getenv("V"); 2055ebecf20SThomas Huth 2065ebecf20SThomas Huth if (v_env) { 2075ebecf20SThomas Huth verbosity_level = atoi(v_env); 2085ebecf20SThomas Huth } 20974769fe7SAndreas Färber 210ae4b01b3SRichard W.M. Jones g_test_init(&argc, &argv, NULL); 211ae4b01b3SRichard W.M. Jones 212*f5af1dadSThomas Huth if (!qtest_has_device("rtl8139")) { 213*f5af1dadSThomas Huth return 0; 214*f5af1dadSThomas Huth } 215*f5af1dadSThomas Huth 216e5d1730dSEric Blake qtest_start("-device rtl8139"); 217e5d1730dSEric Blake 21874769fe7SAndreas Färber qtest_add_func("/rtl8139/nop", nop); 219069bb583SFrediano Ziglio qtest_add_func("/rtl8139/timer", test_init); 22074769fe7SAndreas Färber 22174769fe7SAndreas Färber ret = g_test_run(); 22274769fe7SAndreas Färber 22374769fe7SAndreas Färber qtest_end(); 22474769fe7SAndreas Färber 22574769fe7SAndreas Färber return ret; 22674769fe7SAndreas Färber } 227