xref: /openbmc/qemu/tests/qtest/libqos/e1000e.c (revision 0caa7eff)
11cf4323eSThomas Huth /*
21cf4323eSThomas Huth  * libqos driver framework
31cf4323eSThomas Huth  *
41cf4323eSThomas Huth  * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
51cf4323eSThomas Huth  *
61cf4323eSThomas Huth  * This library is free software; you can redistribute it and/or
71cf4323eSThomas Huth  * modify it under the terms of the GNU Lesser General Public
8dc0ad02dSThomas Huth  * License version 2.1 as published by the Free Software Foundation.
91cf4323eSThomas Huth  *
101cf4323eSThomas Huth  * This library is distributed in the hope that it will be useful,
111cf4323eSThomas Huth  * but WITHOUT ANY WARRANTY; without even the implied warranty of
121cf4323eSThomas Huth  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
131cf4323eSThomas Huth  * Lesser General Public License for more details.
141cf4323eSThomas Huth  *
151cf4323eSThomas Huth  * You should have received a copy of the GNU Lesser General Public
161cf4323eSThomas Huth  * License along with this library; if not, see <http://www.gnu.org/licenses/>
171cf4323eSThomas Huth  */
181cf4323eSThomas Huth 
191cf4323eSThomas Huth #include "qemu/osdep.h"
200e283d84SAkihiko Odaki #include "hw/net/e1000_regs.h"
21897c0da9SAkihiko Odaki #include "hw/pci/pci_ids.h"
22907b5105SMarc-André Lureau #include "../libqtest.h"
23a2ce7dbdSPaolo Bonzini #include "pci-pc.h"
241cf4323eSThomas Huth #include "qemu/sockets.h"
251cf4323eSThomas Huth #include "qemu/iov.h"
261cf4323eSThomas Huth #include "qemu/module.h"
271cf4323eSThomas Huth #include "qemu/bitops.h"
28b243c73cSXuzhou Cheng #include "libqos-malloc.h"
29a2ce7dbdSPaolo Bonzini #include "qgraph.h"
301cf4323eSThomas Huth #include "e1000e.h"
311cf4323eSThomas Huth 
320e283d84SAkihiko Odaki #define E1000E_IVAR_TEST_CFG \
33624ee20cSAkihiko Odaki     (((E1000E_RX0_MSG_ID | E1000_IVAR_INT_ALLOC_VALID) << E1000_IVAR_RXQ0_SHIFT) | \
34624ee20cSAkihiko Odaki      ((E1000E_TX0_MSG_ID | E1000_IVAR_INT_ALLOC_VALID) << E1000_IVAR_TXQ0_SHIFT) | \
350e283d84SAkihiko Odaki      E1000_IVAR_TX_INT_EVERY_WB)
361cf4323eSThomas Huth 
371cf4323eSThomas Huth #define E1000E_RING_LEN (0x1000)
381cf4323eSThomas Huth 
e1000e_tx_ring_push(QE1000E * d,void * descr)391cf4323eSThomas Huth void e1000e_tx_ring_push(QE1000E *d, void *descr)
401cf4323eSThomas Huth {
411cf4323eSThomas Huth     QE1000E_PCI *d_pci = container_of(d, QE1000E_PCI, e1000e);
42*57b8d8d6SAkihiko Odaki     uint32_t tail = e1000e_macreg_read(d, E1000_TDT);
43*57b8d8d6SAkihiko Odaki     uint32_t len = e1000e_macreg_read(d, E1000_TDLEN) / E1000_RING_DESC_LEN;
441cf4323eSThomas Huth 
450e283d84SAkihiko Odaki     qtest_memwrite(d_pci->pci_dev.bus->qts,
460e283d84SAkihiko Odaki                    d->tx_ring + tail * E1000_RING_DESC_LEN,
470e283d84SAkihiko Odaki                    descr, E1000_RING_DESC_LEN);
48*57b8d8d6SAkihiko Odaki     e1000e_macreg_write(d, E1000_TDT, (tail + 1) % len);
491cf4323eSThomas Huth 
501cf4323eSThomas Huth     /* Read WB data for the packet transmitted */
510e283d84SAkihiko Odaki     qtest_memread(d_pci->pci_dev.bus->qts,
520e283d84SAkihiko Odaki                   d->tx_ring + tail * E1000_RING_DESC_LEN,
530e283d84SAkihiko Odaki                   descr, E1000_RING_DESC_LEN);
541cf4323eSThomas Huth }
551cf4323eSThomas Huth 
e1000e_rx_ring_push(QE1000E * d,void * descr)561cf4323eSThomas Huth void e1000e_rx_ring_push(QE1000E *d, void *descr)
571cf4323eSThomas Huth {
581cf4323eSThomas Huth     QE1000E_PCI *d_pci = container_of(d, QE1000E_PCI, e1000e);
59*57b8d8d6SAkihiko Odaki     uint32_t tail = e1000e_macreg_read(d, E1000_RDT);
60*57b8d8d6SAkihiko Odaki     uint32_t len = e1000e_macreg_read(d, E1000_RDLEN) / E1000_RING_DESC_LEN;
611cf4323eSThomas Huth 
620e283d84SAkihiko Odaki     qtest_memwrite(d_pci->pci_dev.bus->qts,
630e283d84SAkihiko Odaki                    d->rx_ring + tail * E1000_RING_DESC_LEN,
640e283d84SAkihiko Odaki                    descr, E1000_RING_DESC_LEN);
65*57b8d8d6SAkihiko Odaki     e1000e_macreg_write(d, E1000_RDT, (tail + 1) % len);
661cf4323eSThomas Huth 
671cf4323eSThomas Huth     /* Read WB data for the packet received */
680e283d84SAkihiko Odaki     qtest_memread(d_pci->pci_dev.bus->qts,
690e283d84SAkihiko Odaki                   d->rx_ring + tail * E1000_RING_DESC_LEN,
700e283d84SAkihiko Odaki                   descr, E1000_RING_DESC_LEN);
711cf4323eSThomas Huth }
721cf4323eSThomas Huth 
e1000e_foreach_callback(QPCIDevice * dev,int devfn,void * data)731cf4323eSThomas Huth static void e1000e_foreach_callback(QPCIDevice *dev, int devfn, void *data)
741cf4323eSThomas Huth {
751cf4323eSThomas Huth     QPCIDevice *res = data;
761cf4323eSThomas Huth     memcpy(res, dev, sizeof(QPCIDevice));
771cf4323eSThomas Huth     g_free(dev);
781cf4323eSThomas Huth }
791cf4323eSThomas Huth 
e1000e_wait_isr(QE1000E * d,uint16_t msg_id)801cf4323eSThomas Huth void e1000e_wait_isr(QE1000E *d, uint16_t msg_id)
811cf4323eSThomas Huth {
821cf4323eSThomas Huth     QE1000E_PCI *d_pci = container_of(d, QE1000E_PCI, e1000e);
831cf4323eSThomas Huth     guint64 end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
841cf4323eSThomas Huth 
851cf4323eSThomas Huth     do {
861cf4323eSThomas Huth         if (qpci_msix_pending(&d_pci->pci_dev, msg_id)) {
871cf4323eSThomas Huth             return;
881cf4323eSThomas Huth         }
891cf4323eSThomas Huth         qtest_clock_step(d_pci->pci_dev.bus->qts, 10000);
901cf4323eSThomas Huth     } while (g_get_monotonic_time() < end_time);
911cf4323eSThomas Huth 
921cf4323eSThomas Huth     g_error("Timeout expired");
931cf4323eSThomas Huth }
941cf4323eSThomas Huth 
e1000e_pci_destructor(QOSGraphObject * obj)951cf4323eSThomas Huth static void e1000e_pci_destructor(QOSGraphObject *obj)
961cf4323eSThomas Huth {
971cf4323eSThomas Huth     QE1000E_PCI *epci = (QE1000E_PCI *) obj;
981cf4323eSThomas Huth     qpci_iounmap(&epci->pci_dev, epci->mac_regs);
991cf4323eSThomas Huth     qpci_msix_disable(&epci->pci_dev);
1001cf4323eSThomas Huth }
1011cf4323eSThomas Huth 
e1000e_pci_start_hw(QOSGraphObject * obj)1021cf4323eSThomas Huth static void e1000e_pci_start_hw(QOSGraphObject *obj)
1031cf4323eSThomas Huth {
1041cf4323eSThomas Huth     QE1000E_PCI *d = (QE1000E_PCI *) obj;
1051cf4323eSThomas Huth     uint32_t val;
1061cf4323eSThomas Huth 
1071cf4323eSThomas Huth     /* Enable the device */
1081cf4323eSThomas Huth     qpci_device_enable(&d->pci_dev);
1091cf4323eSThomas Huth 
1101cf4323eSThomas Huth     /* Reset the device */
1110e283d84SAkihiko Odaki     val = e1000e_macreg_read(&d->e1000e, E1000_CTRL);
112ff4f4581SAkihiko Odaki     e1000e_macreg_write(&d->e1000e, E1000_CTRL, val | E1000_CTRL_RST | E1000_CTRL_SLU);
1131cf4323eSThomas Huth 
1141cf4323eSThomas Huth     /* Enable and configure MSI-X */
1151cf4323eSThomas Huth     qpci_msix_enable(&d->pci_dev);
1160e283d84SAkihiko Odaki     e1000e_macreg_write(&d->e1000e, E1000_IVAR, E1000E_IVAR_TEST_CFG);
1171cf4323eSThomas Huth 
1181cf4323eSThomas Huth     /* Check the device status - link and speed */
1190e283d84SAkihiko Odaki     val = e1000e_macreg_read(&d->e1000e, E1000_STATUS);
1205ebafa16SAkihiko Odaki     g_assert_cmphex(val & (E1000_STATUS_LU | E1000_STATUS_ASDV_1000),
1215ebafa16SAkihiko Odaki         ==, E1000_STATUS_LU | E1000_STATUS_ASDV_1000);
1221cf4323eSThomas Huth 
1231cf4323eSThomas Huth     /* Initialize TX/RX logic */
1240e283d84SAkihiko Odaki     e1000e_macreg_write(&d->e1000e, E1000_RCTL, 0);
1250e283d84SAkihiko Odaki     e1000e_macreg_write(&d->e1000e, E1000_TCTL, 0);
1261cf4323eSThomas Huth 
1271cf4323eSThomas Huth     /* Notify the device that the driver is ready */
1280e283d84SAkihiko Odaki     val = e1000e_macreg_read(&d->e1000e, E1000_CTRL_EXT);
1290e283d84SAkihiko Odaki     e1000e_macreg_write(&d->e1000e, E1000_CTRL_EXT,
1300e283d84SAkihiko Odaki         val | E1000_CTRL_EXT_DRV_LOAD);
1311cf4323eSThomas Huth 
1320e283d84SAkihiko Odaki     e1000e_macreg_write(&d->e1000e, E1000_TDBAL,
1331cf4323eSThomas Huth                            (uint32_t) d->e1000e.tx_ring);
1340e283d84SAkihiko Odaki     e1000e_macreg_write(&d->e1000e, E1000_TDBAH,
1351cf4323eSThomas Huth                            (uint32_t) (d->e1000e.tx_ring >> 32));
136*57b8d8d6SAkihiko Odaki     e1000e_macreg_write(&d->e1000e, E1000_TDLEN, E1000E_RING_LEN);
137*57b8d8d6SAkihiko Odaki     e1000e_macreg_write(&d->e1000e, E1000_TDT, 0);
1380e283d84SAkihiko Odaki     e1000e_macreg_write(&d->e1000e, E1000_TDH, 0);
1391cf4323eSThomas Huth 
1401cf4323eSThomas Huth     /* Enable transmit */
1410e283d84SAkihiko Odaki     e1000e_macreg_write(&d->e1000e, E1000_TCTL, E1000_TCTL_EN);
14244c397b2SAkihiko Odaki 
1430e283d84SAkihiko Odaki     e1000e_macreg_write(&d->e1000e, E1000_RDBAL,
1441cf4323eSThomas Huth                            (uint32_t)d->e1000e.rx_ring);
1450e283d84SAkihiko Odaki     e1000e_macreg_write(&d->e1000e, E1000_RDBAH,
1461cf4323eSThomas Huth                            (uint32_t)(d->e1000e.rx_ring >> 32));
147*57b8d8d6SAkihiko Odaki     e1000e_macreg_write(&d->e1000e, E1000_RDLEN, E1000E_RING_LEN);
148*57b8d8d6SAkihiko Odaki     e1000e_macreg_write(&d->e1000e, E1000_RDT, 0);
1490e283d84SAkihiko Odaki     e1000e_macreg_write(&d->e1000e, E1000_RDH, 0);
1501cf4323eSThomas Huth 
1511cf4323eSThomas Huth     /* Enable receive */
1520e283d84SAkihiko Odaki     e1000e_macreg_write(&d->e1000e, E1000_RFCTL, E1000_RFCTL_EXTEN);
1530e283d84SAkihiko Odaki     e1000e_macreg_write(&d->e1000e, E1000_RCTL, E1000_RCTL_EN  |
1540e283d84SAkihiko Odaki                                         E1000_RCTL_UPE |
1550e283d84SAkihiko Odaki                                         E1000_RCTL_MPE);
1561cf4323eSThomas Huth 
1571cf4323eSThomas Huth     /* Enable all interrupts */
1580e283d84SAkihiko Odaki     e1000e_macreg_write(&d->e1000e, E1000_IMS, 0xFFFFFFFF);
1591cf4323eSThomas Huth 
1601cf4323eSThomas Huth }
1611cf4323eSThomas Huth 
e1000e_pci_get_driver(void * obj,const char * interface)1621cf4323eSThomas Huth static void *e1000e_pci_get_driver(void *obj, const char *interface)
1631cf4323eSThomas Huth {
1641cf4323eSThomas Huth     QE1000E_PCI *epci = obj;
1651cf4323eSThomas Huth     if (!g_strcmp0(interface, "e1000e-if")) {
1661cf4323eSThomas Huth         return &epci->e1000e;
1671cf4323eSThomas Huth     }
1681cf4323eSThomas Huth 
1691cf4323eSThomas Huth     /* implicit contains */
1701cf4323eSThomas Huth     if (!g_strcmp0(interface, "pci-device")) {
1711cf4323eSThomas Huth         return &epci->pci_dev;
1721cf4323eSThomas Huth     }
1731cf4323eSThomas Huth 
1741cf4323eSThomas Huth     fprintf(stderr, "%s not present in e1000e\n", interface);
1751cf4323eSThomas Huth     g_assert_not_reached();
1761cf4323eSThomas Huth }
1771cf4323eSThomas Huth 
e1000e_pci_create(void * pci_bus,QGuestAllocator * alloc,void * addr)1781cf4323eSThomas Huth static void *e1000e_pci_create(void *pci_bus, QGuestAllocator *alloc,
1791cf4323eSThomas Huth                                void *addr)
1801cf4323eSThomas Huth {
1811cf4323eSThomas Huth     QE1000E_PCI *d = g_new0(QE1000E_PCI, 1);
1821cf4323eSThomas Huth     QPCIBus *bus = pci_bus;
1831cf4323eSThomas Huth     QPCIAddress *address = addr;
1841cf4323eSThomas Huth 
1851cf4323eSThomas Huth     qpci_device_foreach(bus, address->vendor_id, address->device_id,
1861cf4323eSThomas Huth                         e1000e_foreach_callback, &d->pci_dev);
1871cf4323eSThomas Huth 
1881cf4323eSThomas Huth     /* Map BAR0 (mac registers) */
1891cf4323eSThomas Huth     d->mac_regs = qpci_iomap(&d->pci_dev, 0, NULL);
1901cf4323eSThomas Huth 
1911cf4323eSThomas Huth     /* Allocate and setup TX ring */
1921cf4323eSThomas Huth     d->e1000e.tx_ring = guest_alloc(alloc, E1000E_RING_LEN);
1931cf4323eSThomas Huth     g_assert(d->e1000e.tx_ring != 0);
1941cf4323eSThomas Huth 
1951cf4323eSThomas Huth     /* Allocate and setup RX ring */
1961cf4323eSThomas Huth     d->e1000e.rx_ring = guest_alloc(alloc, E1000E_RING_LEN);
1971cf4323eSThomas Huth     g_assert(d->e1000e.rx_ring != 0);
1981cf4323eSThomas Huth 
1991cf4323eSThomas Huth     d->obj.get_driver = e1000e_pci_get_driver;
2001cf4323eSThomas Huth     d->obj.start_hw = e1000e_pci_start_hw;
2011cf4323eSThomas Huth     d->obj.destructor = e1000e_pci_destructor;
2021cf4323eSThomas Huth 
2031cf4323eSThomas Huth     return &d->obj;
2041cf4323eSThomas Huth }
2051cf4323eSThomas Huth 
e1000e_register_nodes(void)2061cf4323eSThomas Huth static void e1000e_register_nodes(void)
2071cf4323eSThomas Huth {
2081cf4323eSThomas Huth     QPCIAddress addr = {
209897c0da9SAkihiko Odaki         .vendor_id = PCI_VENDOR_ID_INTEL,
210897c0da9SAkihiko Odaki         .device_id = E1000_DEV_ID_82574L,
2111cf4323eSThomas Huth     };
2121cf4323eSThomas Huth 
213da994bacSAkihiko Odaki     /*
214da994bacSAkihiko Odaki      * FIXME: every test using this node needs to setup a -netdev socket,id=hs0
215da994bacSAkihiko Odaki      * otherwise QEMU is not going to start
216da994bacSAkihiko Odaki      */
2171cf4323eSThomas Huth     QOSGraphEdgeOptions opts = {
2181cf4323eSThomas Huth         .extra_device_opts = "netdev=hs0",
2191cf4323eSThomas Huth     };
2201cf4323eSThomas Huth     add_qpci_address(&opts, &addr);
2211cf4323eSThomas Huth 
2221cf4323eSThomas Huth     qos_node_create_driver("e1000e", e1000e_pci_create);
2231cf4323eSThomas Huth     qos_node_consumes("e1000e", "pci-bus", &opts);
2241cf4323eSThomas Huth }
2251cf4323eSThomas Huth 
2261cf4323eSThomas Huth libqos_init(e1000e_register_nodes);
227