qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

rtl8139-test.c (5213B)


      1 /*
      2  * QTest testcase for Realtek 8139 NIC
      3  *
      4  * Copyright (c) 2013-2014 SUSE LINUX Products GmbH
      5  *
      6  * This work is licensed under the terms of the GNU GPL, version 2 or later.
      7  * See the COPYING file in the top-level directory.
      8  */
      9 
     10 #include "qemu/osdep.h"
     11 #include "libqtest-single.h"
     12 #include "libqos/pci-pc.h"
     13 #include "qemu/timer.h"
     14 
     15 /* Tests only initialization so far. TODO: Replace with functional tests */
     16 static void nop(void)
     17 {
     18 }
     19 
     20 #define CLK 33333333
     21 
     22 static QPCIBus *pcibus;
     23 static QPCIDevice *dev;
     24 static QPCIBar dev_bar;
     25 
     26 static void save_fn(QPCIDevice *dev, int devfn, void *data)
     27 {
     28     QPCIDevice **pdev = (QPCIDevice **) data;
     29 
     30     *pdev = dev;
     31 }
     32 
     33 static QPCIDevice *get_device(void)
     34 {
     35     QPCIDevice *dev;
     36 
     37     pcibus = qpci_new_pc(global_qtest, NULL);
     38     qpci_device_foreach(pcibus, 0x10ec, 0x8139, save_fn, &dev);
     39     g_assert(dev != NULL);
     40 
     41     return dev;
     42 }
     43 
     44 #define PORT(name, len, val) \
     45 static unsigned __attribute__((unused)) in_##name(void) \
     46 { \
     47     unsigned res = qpci_io_read##len(dev, dev_bar, (val));     \
     48     g_test_message("*%s -> %x", #name, res); \
     49     return res; \
     50 } \
     51 static void out_##name(unsigned v) \
     52 { \
     53     g_test_message("%x -> *%s", v, #name); \
     54     qpci_io_write##len(dev, dev_bar, (val), v);        \
     55 }
     56 
     57 PORT(Timer, l, 0x48)
     58 PORT(IntrMask, w, 0x3c)
     59 PORT(IntrStatus, w, 0x3E)
     60 PORT(TimerInt, l, 0x54)
     61 
     62 #define fatal(...) do { g_test_message(__VA_ARGS__); g_assert(0); } while (0)
     63 
     64 static void test_timer(void)
     65 {
     66     const unsigned from = 0.95 * CLK;
     67     const unsigned to = 1.6 * CLK;
     68     unsigned prev, curr, next;
     69     unsigned cnt, diff;
     70 
     71     out_IntrMask(0);
     72 
     73     in_IntrStatus();
     74     in_Timer();
     75     in_Timer();
     76 
     77     /* Test 1. test counter continue and continue */
     78     out_TimerInt(0); /* disable timer */
     79     out_IntrStatus(0x4000);
     80     out_Timer(12345); /* reset timer to 0 */
     81     curr = in_Timer();
     82     if (curr > 0.1 * CLK) {
     83         fatal("time too big %u\n", curr);
     84     }
     85     for (cnt = 0; ; ) {
     86         clock_step(1 * NANOSECONDS_PER_SECOND);
     87         prev = curr;
     88         curr = in_Timer();
     89 
     90         /* test skip is in a specific range */
     91         diff = (curr-prev) & 0xffffffffu;
     92         if (diff < from || diff > to) {
     93             fatal("Invalid diff %u (%u-%u)\n", diff, from, to);
     94         }
     95         if (curr < prev && ++cnt == 3) {
     96             break;
     97         }
     98     }
     99 
    100     /* Test 2. Check we didn't get an interrupt with TimerInt == 0 */
    101     if (in_IntrStatus() & 0x4000) {
    102         fatal("got an interrupt\n");
    103     }
    104 
    105     /* Test 3. Setting TimerInt to 1 and Timer to 0 get interrupt */
    106     out_TimerInt(1);
    107     out_Timer(0);
    108     clock_step(40);
    109     if ((in_IntrStatus() & 0x4000) == 0) {
    110         fatal("we should have an interrupt here!\n");
    111     }
    112 
    113     /* Test 3. Check acknowledge */
    114     out_IntrStatus(0x4000);
    115     if (in_IntrStatus() & 0x4000) {
    116         fatal("got an interrupt\n");
    117     }
    118 
    119     /* Test. Status set after Timer reset */
    120     out_Timer(0);
    121     out_TimerInt(0);
    122     out_IntrStatus(0x4000);
    123     curr = in_Timer();
    124     out_TimerInt(curr + 0.5 * CLK);
    125     clock_step(1 * NANOSECONDS_PER_SECOND);
    126     out_Timer(0);
    127     if ((in_IntrStatus() & 0x4000) == 0) {
    128         fatal("we should have an interrupt here!\n");
    129     }
    130 
    131     /* Test. Status set after TimerInt reset */
    132     out_Timer(0);
    133     out_TimerInt(0);
    134     out_IntrStatus(0x4000);
    135     curr = in_Timer();
    136     out_TimerInt(curr + 0.5 * CLK);
    137     clock_step(1 * NANOSECONDS_PER_SECOND);
    138     out_TimerInt(0);
    139     if ((in_IntrStatus() & 0x4000) == 0) {
    140         fatal("we should have an interrupt here!\n");
    141     }
    142 
    143     /* Test 4. Increment TimerInt we should see an interrupt */
    144     curr = in_Timer();
    145     next = curr + 5.0 * CLK;
    146     out_TimerInt(next);
    147     for (cnt = 0; ; ) {
    148         clock_step(1 * NANOSECONDS_PER_SECOND);
    149         prev = curr;
    150         curr = in_Timer();
    151         diff = (curr-prev) & 0xffffffffu;
    152         if (diff < from || diff > to) {
    153             fatal("Invalid diff %u (%u-%u)\n", diff, from, to);
    154         }
    155         if (cnt < 3 && curr > next) {
    156             if ((in_IntrStatus() & 0x4000) == 0) {
    157                 fatal("we should have an interrupt here!\n");
    158             }
    159             out_IntrStatus(0x4000);
    160             next = curr + 5.0 * CLK;
    161             out_TimerInt(next);
    162             if (++cnt == 3) {
    163                 out_TimerInt(1);
    164             }
    165         /* Test 5. Second time we pass from 0 should see an interrupt */
    166         } else if (cnt >= 3 && curr < prev) {
    167             /* here we should have an interrupt */
    168             if ((in_IntrStatus() & 0x4000) == 0) {
    169                 fatal("we should have an interrupt here!\n");
    170             }
    171             out_IntrStatus(0x4000);
    172             if (++cnt == 5) {
    173                 break;
    174             }
    175         }
    176     }
    177 
    178     g_test_message("Everythink is ok!");
    179 }
    180 
    181 
    182 static void test_init(void)
    183 {
    184     uint64_t barsize;
    185 
    186     dev = get_device();
    187 
    188     dev_bar = qpci_iomap(dev, 0, &barsize);
    189 
    190     qpci_device_enable(dev);
    191 
    192     test_timer();
    193 }
    194 
    195 int main(int argc, char **argv)
    196 {
    197     int ret;
    198 
    199     qtest_start("-device rtl8139");
    200 
    201     g_test_init(&argc, &argv, NULL);
    202     qtest_add_func("/rtl8139/nop", nop);
    203     qtest_add_func("/rtl8139/timer", test_init);
    204 
    205     ret = g_test_run();
    206 
    207     qtest_end();
    208 
    209     return ret;
    210 }