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 1074769fe7SAndreas Färber #include <glib.h> 1174769fe7SAndreas Färber #include <string.h> 1274769fe7SAndreas Färber #include "libqtest.h" 13069bb583SFrediano Ziglio #include "libqos/pci-pc.h" 1474769fe7SAndreas Färber #include "qemu/osdep.h" 15*e0cf11f3SAlberto Garcia #include "qemu/timer.h" 16069bb583SFrediano Ziglio #include "qemu-common.h" 1774769fe7SAndreas Färber 1874769fe7SAndreas Färber /* Tests only initialization so far. TODO: Replace with functional tests */ 1974769fe7SAndreas Färber static void nop(void) 2074769fe7SAndreas Färber { 2174769fe7SAndreas Färber } 2274769fe7SAndreas Färber 23069bb583SFrediano Ziglio #define CLK 33000000 24069bb583SFrediano Ziglio 25069bb583SFrediano Ziglio static QPCIBus *pcibus; 26069bb583SFrediano Ziglio static QPCIDevice *dev; 27069bb583SFrediano Ziglio static void *dev_base; 28069bb583SFrediano Ziglio 29069bb583SFrediano Ziglio static void save_fn(QPCIDevice *dev, int devfn, void *data) 30069bb583SFrediano Ziglio { 31069bb583SFrediano Ziglio QPCIDevice **pdev = (QPCIDevice **) data; 32069bb583SFrediano Ziglio 33069bb583SFrediano Ziglio *pdev = dev; 34069bb583SFrediano Ziglio } 35069bb583SFrediano Ziglio 36069bb583SFrediano Ziglio static QPCIDevice *get_device(void) 37069bb583SFrediano Ziglio { 38069bb583SFrediano Ziglio QPCIDevice *dev; 39069bb583SFrediano Ziglio 40069bb583SFrediano Ziglio pcibus = qpci_init_pc(); 41069bb583SFrediano Ziglio qpci_device_foreach(pcibus, 0x10ec, 0x8139, save_fn, &dev); 42069bb583SFrediano Ziglio g_assert(dev != NULL); 43069bb583SFrediano Ziglio 44069bb583SFrediano Ziglio return dev; 45069bb583SFrediano Ziglio } 46069bb583SFrediano Ziglio 47069bb583SFrediano Ziglio #define PORT(name, len, val) \ 48069bb583SFrediano Ziglio static unsigned __attribute__((unused)) in_##name(void) \ 49069bb583SFrediano Ziglio { \ 50069bb583SFrediano Ziglio unsigned res = qpci_io_read##len(dev, dev_base+(val)); \ 51069bb583SFrediano Ziglio g_test_message("*%s -> %x\n", #name, res); \ 52069bb583SFrediano Ziglio return res; \ 53069bb583SFrediano Ziglio } \ 54069bb583SFrediano Ziglio static void out_##name(unsigned v) \ 55069bb583SFrediano Ziglio { \ 56069bb583SFrediano Ziglio g_test_message("%x -> *%s\n", v, #name); \ 57069bb583SFrediano Ziglio qpci_io_write##len(dev, dev_base+(val), v); \ 58069bb583SFrediano Ziglio } 59069bb583SFrediano Ziglio 60069bb583SFrediano Ziglio PORT(Timer, l, 0x48) 61069bb583SFrediano Ziglio PORT(IntrMask, w, 0x3c) 62069bb583SFrediano Ziglio PORT(IntrStatus, w, 0x3E) 63069bb583SFrediano Ziglio PORT(TimerInt, l, 0x54) 64069bb583SFrediano Ziglio 65069bb583SFrediano Ziglio #define fatal(...) do { g_test_message(__VA_ARGS__); g_assert(0); } while (0) 66069bb583SFrediano Ziglio 67069bb583SFrediano Ziglio static void test_timer(void) 68069bb583SFrediano Ziglio { 69069bb583SFrediano Ziglio const unsigned from = 0.95 * CLK; 70069bb583SFrediano Ziglio const unsigned to = 1.6 * CLK; 71069bb583SFrediano Ziglio unsigned prev, curr, next; 72069bb583SFrediano Ziglio unsigned cnt, diff; 73069bb583SFrediano Ziglio 74069bb583SFrediano Ziglio out_IntrMask(0); 75069bb583SFrediano Ziglio 76069bb583SFrediano Ziglio in_IntrStatus(); 77069bb583SFrediano Ziglio in_Timer(); 78069bb583SFrediano Ziglio in_Timer(); 79069bb583SFrediano Ziglio 80069bb583SFrediano Ziglio /* Test 1. test counter continue and continue */ 81069bb583SFrediano Ziglio out_TimerInt(0); /* disable timer */ 82069bb583SFrediano Ziglio out_IntrStatus(0x4000); 83069bb583SFrediano Ziglio out_Timer(12345); /* reset timer to 0 */ 84069bb583SFrediano Ziglio curr = in_Timer(); 85069bb583SFrediano Ziglio if (curr > 0.1 * CLK) { 86069bb583SFrediano Ziglio fatal("time too big %u\n", curr); 87069bb583SFrediano Ziglio } 88069bb583SFrediano Ziglio for (cnt = 0; ; ) { 89*e0cf11f3SAlberto Garcia clock_step(1 * NSEC_PER_SEC); 90069bb583SFrediano Ziglio prev = curr; 91069bb583SFrediano Ziglio curr = in_Timer(); 92069bb583SFrediano Ziglio 93069bb583SFrediano Ziglio /* test skip is in a specific range */ 94069bb583SFrediano Ziglio diff = (curr-prev) & 0xffffffffu; 95069bb583SFrediano Ziglio if (diff < from || diff > to) { 96069bb583SFrediano Ziglio fatal("Invalid diff %u (%u-%u)\n", diff, from, to); 97069bb583SFrediano Ziglio } 98069bb583SFrediano Ziglio if (curr < prev && ++cnt == 3) { 99069bb583SFrediano Ziglio break; 100069bb583SFrediano Ziglio } 101069bb583SFrediano Ziglio } 102069bb583SFrediano Ziglio 103069bb583SFrediano Ziglio /* Test 2. Check we didn't get an interrupt with TimerInt == 0 */ 104069bb583SFrediano Ziglio if (in_IntrStatus() & 0x4000) { 105069bb583SFrediano Ziglio fatal("got an interrupt\n"); 106069bb583SFrediano Ziglio } 107069bb583SFrediano Ziglio 108069bb583SFrediano Ziglio /* Test 3. Setting TimerInt to 1 and Timer to 0 get interrupt */ 109069bb583SFrediano Ziglio out_TimerInt(1); 110069bb583SFrediano Ziglio out_Timer(0); 111069bb583SFrediano Ziglio clock_step(40); 112069bb583SFrediano Ziglio if ((in_IntrStatus() & 0x4000) == 0) { 113069bb583SFrediano Ziglio fatal("we should have an interrupt here!\n"); 114069bb583SFrediano Ziglio } 115069bb583SFrediano Ziglio 116069bb583SFrediano Ziglio /* Test 3. Check acknowledge */ 117069bb583SFrediano Ziglio out_IntrStatus(0x4000); 118069bb583SFrediano Ziglio if (in_IntrStatus() & 0x4000) { 119069bb583SFrediano Ziglio fatal("got an interrupt\n"); 120069bb583SFrediano Ziglio } 121069bb583SFrediano Ziglio 122069bb583SFrediano Ziglio /* Test. Status set after Timer reset */ 123069bb583SFrediano Ziglio out_Timer(0); 124069bb583SFrediano Ziglio out_TimerInt(0); 125069bb583SFrediano Ziglio out_IntrStatus(0x4000); 126069bb583SFrediano Ziglio curr = in_Timer(); 127069bb583SFrediano Ziglio out_TimerInt(curr + 0.5 * CLK); 128*e0cf11f3SAlberto Garcia clock_step(1 * NSEC_PER_SEC); 129069bb583SFrediano Ziglio out_Timer(0); 130069bb583SFrediano Ziglio if ((in_IntrStatus() & 0x4000) == 0) { 131069bb583SFrediano Ziglio fatal("we should have an interrupt here!\n"); 132069bb583SFrediano Ziglio } 133069bb583SFrediano Ziglio 134069bb583SFrediano Ziglio /* Test. Status set after TimerInt reset */ 135069bb583SFrediano Ziglio out_Timer(0); 136069bb583SFrediano Ziglio out_TimerInt(0); 137069bb583SFrediano Ziglio out_IntrStatus(0x4000); 138069bb583SFrediano Ziglio curr = in_Timer(); 139069bb583SFrediano Ziglio out_TimerInt(curr + 0.5 * CLK); 140*e0cf11f3SAlberto Garcia clock_step(1 * NSEC_PER_SEC); 141069bb583SFrediano Ziglio out_TimerInt(0); 142069bb583SFrediano Ziglio if ((in_IntrStatus() & 0x4000) == 0) { 143069bb583SFrediano Ziglio fatal("we should have an interrupt here!\n"); 144069bb583SFrediano Ziglio } 145069bb583SFrediano Ziglio 146069bb583SFrediano Ziglio /* Test 4. Increment TimerInt we should see an interrupt */ 147069bb583SFrediano Ziglio curr = in_Timer(); 148069bb583SFrediano Ziglio next = curr + 5.0 * CLK; 149069bb583SFrediano Ziglio out_TimerInt(next); 150069bb583SFrediano Ziglio for (cnt = 0; ; ) { 151*e0cf11f3SAlberto Garcia clock_step(1 * NSEC_PER_SEC); 152069bb583SFrediano Ziglio prev = curr; 153069bb583SFrediano Ziglio curr = in_Timer(); 154069bb583SFrediano Ziglio diff = (curr-prev) & 0xffffffffu; 155069bb583SFrediano Ziglio if (diff < from || diff > to) { 156069bb583SFrediano Ziglio fatal("Invalid diff %u (%u-%u)\n", diff, from, to); 157069bb583SFrediano Ziglio } 158069bb583SFrediano Ziglio if (cnt < 3 && curr > next) { 159069bb583SFrediano Ziglio if ((in_IntrStatus() & 0x4000) == 0) { 160069bb583SFrediano Ziglio fatal("we should have an interrupt here!\n"); 161069bb583SFrediano Ziglio } 162069bb583SFrediano Ziglio out_IntrStatus(0x4000); 163069bb583SFrediano Ziglio next = curr + 5.0 * CLK; 164069bb583SFrediano Ziglio out_TimerInt(next); 165069bb583SFrediano Ziglio if (++cnt == 3) { 166069bb583SFrediano Ziglio out_TimerInt(1); 167069bb583SFrediano Ziglio } 168069bb583SFrediano Ziglio /* Test 5. Second time we pass from 0 should see an interrupt */ 169069bb583SFrediano Ziglio } else if (cnt >= 3 && curr < prev) { 170069bb583SFrediano Ziglio /* here we should have an interrupt */ 171069bb583SFrediano Ziglio if ((in_IntrStatus() & 0x4000) == 0) { 172069bb583SFrediano Ziglio fatal("we should have an interrupt here!\n"); 173069bb583SFrediano Ziglio } 174069bb583SFrediano Ziglio out_IntrStatus(0x4000); 175069bb583SFrediano Ziglio if (++cnt == 5) { 176069bb583SFrediano Ziglio break; 177069bb583SFrediano Ziglio } 178069bb583SFrediano Ziglio } 179069bb583SFrediano Ziglio } 180069bb583SFrediano Ziglio 181069bb583SFrediano Ziglio g_test_message("Everythink is ok!\n"); 182069bb583SFrediano Ziglio } 183069bb583SFrediano Ziglio 184069bb583SFrediano Ziglio 185069bb583SFrediano Ziglio static void test_init(void) 186069bb583SFrediano Ziglio { 187069bb583SFrediano Ziglio uint64_t barsize; 188069bb583SFrediano Ziglio 189069bb583SFrediano Ziglio dev = get_device(); 190069bb583SFrediano Ziglio 191069bb583SFrediano Ziglio dev_base = qpci_iomap(dev, 0, &barsize); 192069bb583SFrediano Ziglio 193069bb583SFrediano Ziglio g_assert(dev_base != NULL); 194069bb583SFrediano Ziglio 195069bb583SFrediano Ziglio qpci_device_enable(dev); 196069bb583SFrediano Ziglio 197069bb583SFrediano Ziglio test_timer(); 198069bb583SFrediano Ziglio } 199069bb583SFrediano Ziglio 20074769fe7SAndreas Färber int main(int argc, char **argv) 20174769fe7SAndreas Färber { 20274769fe7SAndreas Färber int ret; 20374769fe7SAndreas Färber 20474769fe7SAndreas Färber g_test_init(&argc, &argv, NULL); 20574769fe7SAndreas Färber qtest_add_func("/rtl8139/nop", nop); 206069bb583SFrediano Ziglio qtest_add_func("/rtl8139/timer", test_init); 20774769fe7SAndreas Färber 20874769fe7SAndreas Färber qtest_start("-device rtl8139"); 20974769fe7SAndreas Färber ret = g_test_run(); 21074769fe7SAndreas Färber 21174769fe7SAndreas Färber qtest_end(); 21274769fe7SAndreas Färber 21374769fe7SAndreas Färber return ret; 21474769fe7SAndreas Färber } 215