13a977deeSAkihiko Odaki /* 23a977deeSAkihiko Odaki * QEMU Intel 82576 SR/IOV Ethernet Controller Emulation 33a977deeSAkihiko Odaki * 43a977deeSAkihiko Odaki * Datasheet: 53a977deeSAkihiko Odaki * https://www.intel.com/content/dam/www/public/us/en/documents/datasheets/82576eg-gbe-datasheet.pdf 63a977deeSAkihiko Odaki * 73a977deeSAkihiko Odaki * Copyright (c) 2020-2023 Red Hat, Inc. 83a977deeSAkihiko Odaki * Copyright (c) 2015 Ravello Systems LTD (http://ravellosystems.com) 93a977deeSAkihiko Odaki * Developed by Daynix Computing LTD (http://www.daynix.com) 103a977deeSAkihiko Odaki * 113a977deeSAkihiko Odaki * Authors: 123a977deeSAkihiko Odaki * Akihiko Odaki <akihiko.odaki@daynix.com> 133a977deeSAkihiko Odaki * Gal Hammmer <gal.hammer@sap.com> 143a977deeSAkihiko Odaki * Marcel Apfelbaum <marcel.apfelbaum@gmail.com> 153a977deeSAkihiko Odaki * Dmitry Fleytman <dmitry@daynix.com> 163a977deeSAkihiko Odaki * Leonid Bloch <leonid@daynix.com> 173a977deeSAkihiko Odaki * Yan Vugenfirer <yan@daynix.com> 183a977deeSAkihiko Odaki * 193a977deeSAkihiko Odaki * Based on work done by: 203a977deeSAkihiko Odaki * Nir Peleg, Tutis Systems Ltd. for Qumranet Inc. 213a977deeSAkihiko Odaki * Copyright (c) 2008 Qumranet 223a977deeSAkihiko Odaki * Based on work done by: 233a977deeSAkihiko Odaki * Copyright (c) 2007 Dan Aloni 243a977deeSAkihiko Odaki * Copyright (c) 2004 Antony T Curtis 253a977deeSAkihiko Odaki * 263a977deeSAkihiko Odaki * This library is free software; you can redistribute it and/or 273a977deeSAkihiko Odaki * modify it under the terms of the GNU Lesser General Public 283a977deeSAkihiko Odaki * License as published by the Free Software Foundation; either 293a977deeSAkihiko Odaki * version 2.1 of the License, or (at your option) any later version. 303a977deeSAkihiko Odaki * 313a977deeSAkihiko Odaki * This library is distributed in the hope that it will be useful, 323a977deeSAkihiko Odaki * but WITHOUT ANY WARRANTY; without even the implied warranty of 333a977deeSAkihiko Odaki * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 343a977deeSAkihiko Odaki * Lesser General Public License for more details. 353a977deeSAkihiko Odaki * 363a977deeSAkihiko Odaki * You should have received a copy of the GNU Lesser General Public 373a977deeSAkihiko Odaki * License along with this library; if not, see <http://www.gnu.org/licenses/>. 383a977deeSAkihiko Odaki */ 393a977deeSAkihiko Odaki 403a977deeSAkihiko Odaki #include "qemu/osdep.h" 413a977deeSAkihiko Odaki #include "qemu/units.h" 423a977deeSAkihiko Odaki #include "net/eth.h" 433a977deeSAkihiko Odaki #include "net/net.h" 443a977deeSAkihiko Odaki #include "net/tap.h" 453a977deeSAkihiko Odaki #include "qemu/module.h" 463a977deeSAkihiko Odaki #include "qemu/range.h" 473a977deeSAkihiko Odaki #include "sysemu/sysemu.h" 483a977deeSAkihiko Odaki #include "hw/hw.h" 493a977deeSAkihiko Odaki #include "hw/net/mii.h" 503a977deeSAkihiko Odaki #include "hw/pci/pci.h" 513a977deeSAkihiko Odaki #include "hw/pci/pcie.h" 523a977deeSAkihiko Odaki #include "hw/pci/pcie_sriov.h" 533a977deeSAkihiko Odaki #include "hw/pci/msi.h" 543a977deeSAkihiko Odaki #include "hw/pci/msix.h" 553a977deeSAkihiko Odaki #include "hw/qdev-properties.h" 563a977deeSAkihiko Odaki #include "migration/vmstate.h" 573a977deeSAkihiko Odaki 583a977deeSAkihiko Odaki #include "igb_common.h" 593a977deeSAkihiko Odaki #include "igb_core.h" 603a977deeSAkihiko Odaki 613a977deeSAkihiko Odaki #include "trace.h" 623a977deeSAkihiko Odaki #include "qapi/error.h" 633a977deeSAkihiko Odaki #include "qom/object.h" 643a977deeSAkihiko Odaki 653a977deeSAkihiko Odaki #define TYPE_IGB "igb" 663a977deeSAkihiko Odaki OBJECT_DECLARE_SIMPLE_TYPE(IGBState, IGB) 673a977deeSAkihiko Odaki 683a977deeSAkihiko Odaki struct IGBState { 693a977deeSAkihiko Odaki PCIDevice parent_obj; 703a977deeSAkihiko Odaki NICState *nic; 713a977deeSAkihiko Odaki NICConf conf; 723a977deeSAkihiko Odaki 733a977deeSAkihiko Odaki MemoryRegion mmio; 743a977deeSAkihiko Odaki MemoryRegion flash; 753a977deeSAkihiko Odaki MemoryRegion io; 763a977deeSAkihiko Odaki MemoryRegion msix; 773a977deeSAkihiko Odaki 783a977deeSAkihiko Odaki uint32_t ioaddr; 793a977deeSAkihiko Odaki 803a977deeSAkihiko Odaki IGBCore core; 813a977deeSAkihiko Odaki }; 823a977deeSAkihiko Odaki 833a977deeSAkihiko Odaki #define IGB_CAP_SRIOV_OFFSET (0x160) 843a977deeSAkihiko Odaki #define IGB_VF_OFFSET (0x80) 853a977deeSAkihiko Odaki #define IGB_VF_STRIDE (2) 863a977deeSAkihiko Odaki 873a977deeSAkihiko Odaki #define E1000E_MMIO_IDX 0 883a977deeSAkihiko Odaki #define E1000E_FLASH_IDX 1 893a977deeSAkihiko Odaki #define E1000E_IO_IDX 2 903a977deeSAkihiko Odaki #define E1000E_MSIX_IDX 3 913a977deeSAkihiko Odaki 923a977deeSAkihiko Odaki #define E1000E_MMIO_SIZE (128 * KiB) 933a977deeSAkihiko Odaki #define E1000E_FLASH_SIZE (128 * KiB) 943a977deeSAkihiko Odaki #define E1000E_IO_SIZE (32) 953a977deeSAkihiko Odaki #define E1000E_MSIX_SIZE (16 * KiB) 963a977deeSAkihiko Odaki 973a977deeSAkihiko Odaki static void igb_write_config(PCIDevice *dev, uint32_t addr, 983a977deeSAkihiko Odaki uint32_t val, int len) 993a977deeSAkihiko Odaki { 1003a977deeSAkihiko Odaki IGBState *s = IGB(dev); 1013a977deeSAkihiko Odaki 1023a977deeSAkihiko Odaki trace_igb_write_config(addr, val, len); 1033a977deeSAkihiko Odaki pci_default_write_config(dev, addr, val, len); 1043a977deeSAkihiko Odaki 1053a977deeSAkihiko Odaki if (range_covers_byte(addr, len, PCI_COMMAND) && 1063a977deeSAkihiko Odaki (dev->config[PCI_COMMAND] & PCI_COMMAND_MASTER)) { 1073a977deeSAkihiko Odaki igb_start_recv(&s->core); 1083a977deeSAkihiko Odaki } 1093a977deeSAkihiko Odaki } 1103a977deeSAkihiko Odaki 1113a977deeSAkihiko Odaki uint64_t 1123a977deeSAkihiko Odaki igb_mmio_read(void *opaque, hwaddr addr, unsigned size) 1133a977deeSAkihiko Odaki { 1143a977deeSAkihiko Odaki IGBState *s = opaque; 1153a977deeSAkihiko Odaki return igb_core_read(&s->core, addr, size); 1163a977deeSAkihiko Odaki } 1173a977deeSAkihiko Odaki 1183a977deeSAkihiko Odaki void 1193a977deeSAkihiko Odaki igb_mmio_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) 1203a977deeSAkihiko Odaki { 1213a977deeSAkihiko Odaki IGBState *s = opaque; 1223a977deeSAkihiko Odaki igb_core_write(&s->core, addr, val, size); 1233a977deeSAkihiko Odaki } 1243a977deeSAkihiko Odaki 1253a977deeSAkihiko Odaki static bool 1263a977deeSAkihiko Odaki igb_io_get_reg_index(IGBState *s, uint32_t *idx) 1273a977deeSAkihiko Odaki { 1283a977deeSAkihiko Odaki if (s->ioaddr < 0x1FFFF) { 1293a977deeSAkihiko Odaki *idx = s->ioaddr; 1303a977deeSAkihiko Odaki return true; 1313a977deeSAkihiko Odaki } 1323a977deeSAkihiko Odaki 1333a977deeSAkihiko Odaki if (s->ioaddr < 0x7FFFF) { 1343a977deeSAkihiko Odaki trace_e1000e_wrn_io_addr_undefined(s->ioaddr); 1353a977deeSAkihiko Odaki return false; 1363a977deeSAkihiko Odaki } 1373a977deeSAkihiko Odaki 1383a977deeSAkihiko Odaki if (s->ioaddr < 0xFFFFF) { 1393a977deeSAkihiko Odaki trace_e1000e_wrn_io_addr_flash(s->ioaddr); 1403a977deeSAkihiko Odaki return false; 1413a977deeSAkihiko Odaki } 1423a977deeSAkihiko Odaki 1433a977deeSAkihiko Odaki trace_e1000e_wrn_io_addr_unknown(s->ioaddr); 1443a977deeSAkihiko Odaki return false; 1453a977deeSAkihiko Odaki } 1463a977deeSAkihiko Odaki 1473a977deeSAkihiko Odaki static uint64_t 1483a977deeSAkihiko Odaki igb_io_read(void *opaque, hwaddr addr, unsigned size) 1493a977deeSAkihiko Odaki { 1503a977deeSAkihiko Odaki IGBState *s = opaque; 1513a977deeSAkihiko Odaki uint32_t idx = 0; 1523a977deeSAkihiko Odaki uint64_t val; 1533a977deeSAkihiko Odaki 1543a977deeSAkihiko Odaki switch (addr) { 1553a977deeSAkihiko Odaki case E1000_IOADDR: 1563a977deeSAkihiko Odaki trace_e1000e_io_read_addr(s->ioaddr); 1573a977deeSAkihiko Odaki return s->ioaddr; 1583a977deeSAkihiko Odaki case E1000_IODATA: 1593a977deeSAkihiko Odaki if (igb_io_get_reg_index(s, &idx)) { 1603a977deeSAkihiko Odaki val = igb_core_read(&s->core, idx, sizeof(val)); 1613a977deeSAkihiko Odaki trace_e1000e_io_read_data(idx, val); 1623a977deeSAkihiko Odaki return val; 1633a977deeSAkihiko Odaki } 1643a977deeSAkihiko Odaki return 0; 1653a977deeSAkihiko Odaki default: 1663a977deeSAkihiko Odaki trace_e1000e_wrn_io_read_unknown(addr); 1673a977deeSAkihiko Odaki return 0; 1683a977deeSAkihiko Odaki } 1693a977deeSAkihiko Odaki } 1703a977deeSAkihiko Odaki 1713a977deeSAkihiko Odaki static void 1723a977deeSAkihiko Odaki igb_io_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) 1733a977deeSAkihiko Odaki { 1743a977deeSAkihiko Odaki IGBState *s = opaque; 1753a977deeSAkihiko Odaki uint32_t idx = 0; 1763a977deeSAkihiko Odaki 1773a977deeSAkihiko Odaki switch (addr) { 1783a977deeSAkihiko Odaki case E1000_IOADDR: 1793a977deeSAkihiko Odaki trace_e1000e_io_write_addr(val); 1803a977deeSAkihiko Odaki s->ioaddr = (uint32_t) val; 1813a977deeSAkihiko Odaki return; 1823a977deeSAkihiko Odaki case E1000_IODATA: 1833a977deeSAkihiko Odaki if (igb_io_get_reg_index(s, &idx)) { 1843a977deeSAkihiko Odaki trace_e1000e_io_write_data(idx, val); 1853a977deeSAkihiko Odaki igb_core_write(&s->core, idx, val, sizeof(val)); 1863a977deeSAkihiko Odaki } 1873a977deeSAkihiko Odaki return; 1883a977deeSAkihiko Odaki default: 1893a977deeSAkihiko Odaki trace_e1000e_wrn_io_write_unknown(addr); 1903a977deeSAkihiko Odaki return; 1913a977deeSAkihiko Odaki } 1923a977deeSAkihiko Odaki } 1933a977deeSAkihiko Odaki 1943a977deeSAkihiko Odaki static const MemoryRegionOps mmio_ops = { 1953a977deeSAkihiko Odaki .read = igb_mmio_read, 1963a977deeSAkihiko Odaki .write = igb_mmio_write, 1973a977deeSAkihiko Odaki .endianness = DEVICE_LITTLE_ENDIAN, 1983a977deeSAkihiko Odaki .impl = { 1993a977deeSAkihiko Odaki .min_access_size = 4, 2003a977deeSAkihiko Odaki .max_access_size = 4, 2013a977deeSAkihiko Odaki }, 2023a977deeSAkihiko Odaki }; 2033a977deeSAkihiko Odaki 2043a977deeSAkihiko Odaki static const MemoryRegionOps io_ops = { 2053a977deeSAkihiko Odaki .read = igb_io_read, 2063a977deeSAkihiko Odaki .write = igb_io_write, 2073a977deeSAkihiko Odaki .endianness = DEVICE_LITTLE_ENDIAN, 2083a977deeSAkihiko Odaki .impl = { 2093a977deeSAkihiko Odaki .min_access_size = 4, 2103a977deeSAkihiko Odaki .max_access_size = 4, 2113a977deeSAkihiko Odaki }, 2123a977deeSAkihiko Odaki }; 2133a977deeSAkihiko Odaki 2143a977deeSAkihiko Odaki static bool 2153a977deeSAkihiko Odaki igb_nc_can_receive(NetClientState *nc) 2163a977deeSAkihiko Odaki { 2173a977deeSAkihiko Odaki IGBState *s = qemu_get_nic_opaque(nc); 2183a977deeSAkihiko Odaki return igb_can_receive(&s->core); 2193a977deeSAkihiko Odaki } 2203a977deeSAkihiko Odaki 2213a977deeSAkihiko Odaki static ssize_t 2223a977deeSAkihiko Odaki igb_nc_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt) 2233a977deeSAkihiko Odaki { 2243a977deeSAkihiko Odaki IGBState *s = qemu_get_nic_opaque(nc); 2253a977deeSAkihiko Odaki return igb_receive_iov(&s->core, iov, iovcnt); 2263a977deeSAkihiko Odaki } 2273a977deeSAkihiko Odaki 2283a977deeSAkihiko Odaki static ssize_t 2293a977deeSAkihiko Odaki igb_nc_receive(NetClientState *nc, const uint8_t *buf, size_t size) 2303a977deeSAkihiko Odaki { 2313a977deeSAkihiko Odaki IGBState *s = qemu_get_nic_opaque(nc); 2323a977deeSAkihiko Odaki return igb_receive(&s->core, buf, size); 2333a977deeSAkihiko Odaki } 2343a977deeSAkihiko Odaki 2353a977deeSAkihiko Odaki static void 2363a977deeSAkihiko Odaki igb_set_link_status(NetClientState *nc) 2373a977deeSAkihiko Odaki { 2383a977deeSAkihiko Odaki IGBState *s = qemu_get_nic_opaque(nc); 2393a977deeSAkihiko Odaki igb_core_set_link_status(&s->core); 2403a977deeSAkihiko Odaki } 2413a977deeSAkihiko Odaki 2423a977deeSAkihiko Odaki static NetClientInfo net_igb_info = { 2433a977deeSAkihiko Odaki .type = NET_CLIENT_DRIVER_NIC, 2443a977deeSAkihiko Odaki .size = sizeof(NICState), 2453a977deeSAkihiko Odaki .can_receive = igb_nc_can_receive, 2463a977deeSAkihiko Odaki .receive = igb_nc_receive, 2473a977deeSAkihiko Odaki .receive_iov = igb_nc_receive_iov, 2483a977deeSAkihiko Odaki .link_status_changed = igb_set_link_status, 2493a977deeSAkihiko Odaki }; 2503a977deeSAkihiko Odaki 2513a977deeSAkihiko Odaki /* 2523a977deeSAkihiko Odaki * EEPROM (NVM) contents documented in section 6.1, table 6-1: 2533a977deeSAkihiko Odaki * and in 6.10 Software accessed words. 2543a977deeSAkihiko Odaki */ 2553a977deeSAkihiko Odaki static const uint16_t igb_eeprom_template[] = { 2563a977deeSAkihiko Odaki /* Address |Compat.|OEM sp.| ImRev | OEM sp. */ 2573a977deeSAkihiko Odaki 0x0000, 0x0000, 0x0000, 0x0d34, 0xffff, 0x2010, 0xffff, 0xffff, 2583a977deeSAkihiko Odaki /* PBA |ICtrl1 | SSID | SVID | DevID |-------|ICtrl2 */ 2593a977deeSAkihiko Odaki 0x1040, 0xffff, 0x002b, 0x0000, 0x8086, 0x10c9, 0x0000, 0x70c3, 2603a977deeSAkihiko Odaki /* SwPin0| DevID | EESZ |-------|ICtrl3 |PCI-tc | MSIX | APtr */ 2613a977deeSAkihiko Odaki 0x0004, 0x10c9, 0x5c00, 0x0000, 0x2880, 0x0014, 0x4a40, 0x0060, 2623a977deeSAkihiko Odaki /* PCIe Init. Conf 1,2,3 |PCICtrl| LD1,3 |DDevID |DevRev | LD0,2 */ 2633a977deeSAkihiko Odaki 0x6cfb, 0xc7b0, 0x0abe, 0x0403, 0x0783, 0x10a6, 0x0001, 0x0602, 2643a977deeSAkihiko Odaki /* SwPin1| FunC |LAN-PWR|ManHwC |ICtrl3 | IOVct |VDevID |-------*/ 2653a977deeSAkihiko Odaki 0x0004, 0x0020, 0x0000, 0x004a, 0x2080, 0x00f5, 0x10ca, 0x0000, 2663a977deeSAkihiko Odaki /*---------------| LD1,3 | LD0,2 | ROEnd | ROSta | Wdog | VPD */ 2673a977deeSAkihiko Odaki 0x0000, 0x0000, 0x4784, 0x4602, 0x0000, 0x0000, 0x1000, 0xffff, 2683a977deeSAkihiko Odaki /* PCSet0| Ccfg0 |PXEver |IBAcap |PCSet1 | Ccfg1 |iSCVer | ?? */ 2693a977deeSAkihiko Odaki 0x0100, 0x4000, 0x131f, 0x4013, 0x0100, 0x4000, 0xffff, 0xffff, 2703a977deeSAkihiko Odaki /* PCSet2| Ccfg2 |PCSet3 | Ccfg3 | ?? |AltMacP| ?? |CHKSUM */ 2713a977deeSAkihiko Odaki 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x00e0, 0xffff, 0x0000, 2723a977deeSAkihiko Odaki /* NC-SIC */ 2733a977deeSAkihiko Odaki 0x0003, 2743a977deeSAkihiko Odaki }; 2753a977deeSAkihiko Odaki 2763a977deeSAkihiko Odaki static void igb_core_realize(IGBState *s) 2773a977deeSAkihiko Odaki { 2783a977deeSAkihiko Odaki s->core.owner = &s->parent_obj; 2793a977deeSAkihiko Odaki s->core.owner_nic = s->nic; 2803a977deeSAkihiko Odaki } 2813a977deeSAkihiko Odaki 2823a977deeSAkihiko Odaki static void 2833a977deeSAkihiko Odaki igb_init_msix(IGBState *s) 2843a977deeSAkihiko Odaki { 2853a977deeSAkihiko Odaki int i, res; 2863a977deeSAkihiko Odaki 2873a977deeSAkihiko Odaki res = msix_init(PCI_DEVICE(s), IGB_MSIX_VEC_NUM, 2883a977deeSAkihiko Odaki &s->msix, 2893a977deeSAkihiko Odaki E1000E_MSIX_IDX, 0, 2903a977deeSAkihiko Odaki &s->msix, 2913a977deeSAkihiko Odaki E1000E_MSIX_IDX, 0x2000, 2923a977deeSAkihiko Odaki 0x70, NULL); 2933a977deeSAkihiko Odaki 2943a977deeSAkihiko Odaki if (res < 0) { 2953a977deeSAkihiko Odaki trace_e1000e_msix_init_fail(res); 2963a977deeSAkihiko Odaki } else { 2973a977deeSAkihiko Odaki for (i = 0; i < IGB_MSIX_VEC_NUM; i++) { 2983a977deeSAkihiko Odaki msix_vector_use(PCI_DEVICE(s), i); 2993a977deeSAkihiko Odaki } 3003a977deeSAkihiko Odaki } 3013a977deeSAkihiko Odaki } 3023a977deeSAkihiko Odaki 3033a977deeSAkihiko Odaki static void 3043a977deeSAkihiko Odaki igb_cleanup_msix(IGBState *s) 3053a977deeSAkihiko Odaki { 3063a977deeSAkihiko Odaki msix_unuse_all_vectors(PCI_DEVICE(s)); 3073a977deeSAkihiko Odaki msix_uninit(PCI_DEVICE(s), &s->msix, &s->msix); 3083a977deeSAkihiko Odaki } 3093a977deeSAkihiko Odaki 3103a977deeSAkihiko Odaki static void 3113a977deeSAkihiko Odaki igb_init_net_peer(IGBState *s, PCIDevice *pci_dev, uint8_t *macaddr) 3123a977deeSAkihiko Odaki { 3133a977deeSAkihiko Odaki DeviceState *dev = DEVICE(pci_dev); 3143a977deeSAkihiko Odaki NetClientState *nc; 3153a977deeSAkihiko Odaki int i; 3163a977deeSAkihiko Odaki 3173a977deeSAkihiko Odaki s->nic = qemu_new_nic(&net_igb_info, &s->conf, 3183a977deeSAkihiko Odaki object_get_typename(OBJECT(s)), dev->id, s); 3193a977deeSAkihiko Odaki 3203a977deeSAkihiko Odaki s->core.max_queue_num = s->conf.peers.queues ? s->conf.peers.queues - 1 : 0; 3213a977deeSAkihiko Odaki 3223a977deeSAkihiko Odaki trace_e1000e_mac_set_permanent(MAC_ARG(macaddr)); 3233a977deeSAkihiko Odaki memcpy(s->core.permanent_mac, macaddr, sizeof(s->core.permanent_mac)); 3243a977deeSAkihiko Odaki 3253a977deeSAkihiko Odaki qemu_format_nic_info_str(qemu_get_queue(s->nic), macaddr); 3263a977deeSAkihiko Odaki 3273a977deeSAkihiko Odaki /* Setup virtio headers */ 3283a977deeSAkihiko Odaki for (i = 0; i < s->conf.peers.queues; i++) { 3293a977deeSAkihiko Odaki nc = qemu_get_subqueue(s->nic, i); 3303a977deeSAkihiko Odaki if (!nc->peer || !qemu_has_vnet_hdr(nc->peer)) { 3313a977deeSAkihiko Odaki trace_e1000e_cfg_support_virtio(false); 3323a977deeSAkihiko Odaki return; 3333a977deeSAkihiko Odaki } 3343a977deeSAkihiko Odaki } 3353a977deeSAkihiko Odaki 3363a977deeSAkihiko Odaki trace_e1000e_cfg_support_virtio(true); 3373a977deeSAkihiko Odaki s->core.has_vnet = true; 3383a977deeSAkihiko Odaki 3393a977deeSAkihiko Odaki for (i = 0; i < s->conf.peers.queues; i++) { 3403a977deeSAkihiko Odaki nc = qemu_get_subqueue(s->nic, i); 3413a977deeSAkihiko Odaki qemu_set_vnet_hdr_len(nc->peer, sizeof(struct virtio_net_hdr)); 3423a977deeSAkihiko Odaki qemu_using_vnet_hdr(nc->peer, true); 3433a977deeSAkihiko Odaki } 3443a977deeSAkihiko Odaki } 3453a977deeSAkihiko Odaki 3463a977deeSAkihiko Odaki static int 3473a977deeSAkihiko Odaki igb_add_pm_capability(PCIDevice *pdev, uint8_t offset, uint16_t pmc) 3483a977deeSAkihiko Odaki { 3493a977deeSAkihiko Odaki Error *local_err = NULL; 3503a977deeSAkihiko Odaki int ret = pci_add_capability(pdev, PCI_CAP_ID_PM, offset, 3513a977deeSAkihiko Odaki PCI_PM_SIZEOF, &local_err); 3523a977deeSAkihiko Odaki 3533a977deeSAkihiko Odaki if (local_err) { 3543a977deeSAkihiko Odaki error_report_err(local_err); 3553a977deeSAkihiko Odaki return ret; 3563a977deeSAkihiko Odaki } 3573a977deeSAkihiko Odaki 3583a977deeSAkihiko Odaki pci_set_word(pdev->config + offset + PCI_PM_PMC, 3593a977deeSAkihiko Odaki PCI_PM_CAP_VER_1_1 | 3603a977deeSAkihiko Odaki pmc); 3613a977deeSAkihiko Odaki 3623a977deeSAkihiko Odaki pci_set_word(pdev->wmask + offset + PCI_PM_CTRL, 3633a977deeSAkihiko Odaki PCI_PM_CTRL_STATE_MASK | 3643a977deeSAkihiko Odaki PCI_PM_CTRL_PME_ENABLE | 3653a977deeSAkihiko Odaki PCI_PM_CTRL_DATA_SEL_MASK); 3663a977deeSAkihiko Odaki 3673a977deeSAkihiko Odaki pci_set_word(pdev->w1cmask + offset + PCI_PM_CTRL, 3683a977deeSAkihiko Odaki PCI_PM_CTRL_PME_STATUS); 3693a977deeSAkihiko Odaki 3703a977deeSAkihiko Odaki return ret; 3713a977deeSAkihiko Odaki } 3723a977deeSAkihiko Odaki 3733a977deeSAkihiko Odaki static void igb_pci_realize(PCIDevice *pci_dev, Error **errp) 3743a977deeSAkihiko Odaki { 3753a977deeSAkihiko Odaki IGBState *s = IGB(pci_dev); 3763a977deeSAkihiko Odaki uint8_t *macaddr; 3773a977deeSAkihiko Odaki int ret; 3783a977deeSAkihiko Odaki 3793a977deeSAkihiko Odaki trace_e1000e_cb_pci_realize(); 3803a977deeSAkihiko Odaki 3813a977deeSAkihiko Odaki pci_dev->config_write = igb_write_config; 3823a977deeSAkihiko Odaki 3833a977deeSAkihiko Odaki pci_dev->config[PCI_CACHE_LINE_SIZE] = 0x10; 3843a977deeSAkihiko Odaki pci_dev->config[PCI_INTERRUPT_PIN] = 1; 3853a977deeSAkihiko Odaki 3863a977deeSAkihiko Odaki /* Define IO/MMIO regions */ 3873a977deeSAkihiko Odaki memory_region_init_io(&s->mmio, OBJECT(s), &mmio_ops, s, 3883a977deeSAkihiko Odaki "igb-mmio", E1000E_MMIO_SIZE); 3893a977deeSAkihiko Odaki pci_register_bar(pci_dev, E1000E_MMIO_IDX, 3903a977deeSAkihiko Odaki PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio); 3913a977deeSAkihiko Odaki 3923a977deeSAkihiko Odaki /* 3933a977deeSAkihiko Odaki * We provide a dummy implementation for the flash BAR 3943a977deeSAkihiko Odaki * for drivers that may theoretically probe for its presence. 3953a977deeSAkihiko Odaki */ 3963a977deeSAkihiko Odaki memory_region_init(&s->flash, OBJECT(s), 3973a977deeSAkihiko Odaki "igb-flash", E1000E_FLASH_SIZE); 3983a977deeSAkihiko Odaki pci_register_bar(pci_dev, E1000E_FLASH_IDX, 3993a977deeSAkihiko Odaki PCI_BASE_ADDRESS_SPACE_MEMORY, &s->flash); 4003a977deeSAkihiko Odaki 4013a977deeSAkihiko Odaki memory_region_init_io(&s->io, OBJECT(s), &io_ops, s, 4023a977deeSAkihiko Odaki "igb-io", E1000E_IO_SIZE); 4033a977deeSAkihiko Odaki pci_register_bar(pci_dev, E1000E_IO_IDX, 4043a977deeSAkihiko Odaki PCI_BASE_ADDRESS_SPACE_IO, &s->io); 4053a977deeSAkihiko Odaki 4063a977deeSAkihiko Odaki memory_region_init(&s->msix, OBJECT(s), "igb-msix", 4073a977deeSAkihiko Odaki E1000E_MSIX_SIZE); 4083a977deeSAkihiko Odaki pci_register_bar(pci_dev, E1000E_MSIX_IDX, 4093a977deeSAkihiko Odaki PCI_BASE_ADDRESS_MEM_TYPE_64, &s->msix); 4103a977deeSAkihiko Odaki 4113a977deeSAkihiko Odaki /* Create networking backend */ 4123a977deeSAkihiko Odaki qemu_macaddr_default_if_unset(&s->conf.macaddr); 4133a977deeSAkihiko Odaki macaddr = s->conf.macaddr.a; 4143a977deeSAkihiko Odaki 4153a977deeSAkihiko Odaki /* Add PCI capabilities in reverse order */ 4163a977deeSAkihiko Odaki assert(pcie_endpoint_cap_init(pci_dev, 0xa0) > 0); 4173a977deeSAkihiko Odaki 4183a977deeSAkihiko Odaki igb_init_msix(s); 4193a977deeSAkihiko Odaki 4203a977deeSAkihiko Odaki ret = msi_init(pci_dev, 0x50, 1, true, true, NULL); 4213a977deeSAkihiko Odaki if (ret) { 4223a977deeSAkihiko Odaki trace_e1000e_msi_init_fail(ret); 4233a977deeSAkihiko Odaki } 4243a977deeSAkihiko Odaki 4253a977deeSAkihiko Odaki if (igb_add_pm_capability(pci_dev, 0x40, PCI_PM_CAP_DSI) < 0) { 4263a977deeSAkihiko Odaki hw_error("Failed to initialize PM capability"); 4273a977deeSAkihiko Odaki } 4283a977deeSAkihiko Odaki 4293a977deeSAkihiko Odaki /* PCIe extended capabilities (in order) */ 4303a977deeSAkihiko Odaki if (pcie_aer_init(pci_dev, 1, 0x100, 0x40, errp) < 0) { 4313a977deeSAkihiko Odaki hw_error("Failed to initialize AER capability"); 4323a977deeSAkihiko Odaki } 4333a977deeSAkihiko Odaki 4343a977deeSAkihiko Odaki pcie_ari_init(pci_dev, 0x150, 1); 4353a977deeSAkihiko Odaki 436*ff2b24c8SAkihiko Odaki pcie_sriov_pf_init(pci_dev, IGB_CAP_SRIOV_OFFSET, TYPE_IGBVF, 4373a977deeSAkihiko Odaki IGB_82576_VF_DEV_ID, IGB_MAX_VF_FUNCTIONS, IGB_MAX_VF_FUNCTIONS, 4383a977deeSAkihiko Odaki IGB_VF_OFFSET, IGB_VF_STRIDE); 4393a977deeSAkihiko Odaki 440*ff2b24c8SAkihiko Odaki pcie_sriov_pf_init_vf_bar(pci_dev, IGBVF_MMIO_BAR_IDX, 4413a977deeSAkihiko Odaki PCI_BASE_ADDRESS_MEM_TYPE_64 | PCI_BASE_ADDRESS_MEM_PREFETCH, 442*ff2b24c8SAkihiko Odaki IGBVF_MMIO_SIZE); 443*ff2b24c8SAkihiko Odaki pcie_sriov_pf_init_vf_bar(pci_dev, IGBVF_MSIX_BAR_IDX, 4443a977deeSAkihiko Odaki PCI_BASE_ADDRESS_MEM_TYPE_64 | PCI_BASE_ADDRESS_MEM_PREFETCH, 445*ff2b24c8SAkihiko Odaki IGBVF_MSIX_SIZE); 4463a977deeSAkihiko Odaki 4473a977deeSAkihiko Odaki igb_init_net_peer(s, pci_dev, macaddr); 4483a977deeSAkihiko Odaki 4493a977deeSAkihiko Odaki /* Initialize core */ 4503a977deeSAkihiko Odaki igb_core_realize(s); 4513a977deeSAkihiko Odaki 4523a977deeSAkihiko Odaki igb_core_pci_realize(&s->core, 4533a977deeSAkihiko Odaki igb_eeprom_template, 4543a977deeSAkihiko Odaki sizeof(igb_eeprom_template), 4553a977deeSAkihiko Odaki macaddr); 4563a977deeSAkihiko Odaki } 4573a977deeSAkihiko Odaki 4583a977deeSAkihiko Odaki static void igb_pci_uninit(PCIDevice *pci_dev) 4593a977deeSAkihiko Odaki { 4603a977deeSAkihiko Odaki IGBState *s = IGB(pci_dev); 4613a977deeSAkihiko Odaki 4623a977deeSAkihiko Odaki trace_e1000e_cb_pci_uninit(); 4633a977deeSAkihiko Odaki 4643a977deeSAkihiko Odaki igb_core_pci_uninit(&s->core); 4653a977deeSAkihiko Odaki 4663a977deeSAkihiko Odaki pcie_sriov_pf_exit(pci_dev); 4673a977deeSAkihiko Odaki pcie_cap_exit(pci_dev); 4683a977deeSAkihiko Odaki 4693a977deeSAkihiko Odaki qemu_del_nic(s->nic); 4703a977deeSAkihiko Odaki 4713a977deeSAkihiko Odaki igb_cleanup_msix(s); 4723a977deeSAkihiko Odaki msi_uninit(pci_dev); 4733a977deeSAkihiko Odaki } 4743a977deeSAkihiko Odaki 4753a977deeSAkihiko Odaki static void igb_qdev_reset_hold(Object *obj) 4763a977deeSAkihiko Odaki { 4773a977deeSAkihiko Odaki PCIDevice *d = PCI_DEVICE(obj); 4783a977deeSAkihiko Odaki IGBState *s = IGB(obj); 4793a977deeSAkihiko Odaki 4803a977deeSAkihiko Odaki trace_e1000e_cb_qdev_reset_hold(); 4813a977deeSAkihiko Odaki 4823a977deeSAkihiko Odaki pcie_sriov_pf_disable_vfs(d); 4833a977deeSAkihiko Odaki igb_core_reset(&s->core); 4843a977deeSAkihiko Odaki } 4853a977deeSAkihiko Odaki 4863a977deeSAkihiko Odaki static int igb_pre_save(void *opaque) 4873a977deeSAkihiko Odaki { 4883a977deeSAkihiko Odaki IGBState *s = opaque; 4893a977deeSAkihiko Odaki 4903a977deeSAkihiko Odaki trace_e1000e_cb_pre_save(); 4913a977deeSAkihiko Odaki 4923a977deeSAkihiko Odaki igb_core_pre_save(&s->core); 4933a977deeSAkihiko Odaki 4943a977deeSAkihiko Odaki return 0; 4953a977deeSAkihiko Odaki } 4963a977deeSAkihiko Odaki 4973a977deeSAkihiko Odaki static int igb_post_load(void *opaque, int version_id) 4983a977deeSAkihiko Odaki { 4993a977deeSAkihiko Odaki IGBState *s = opaque; 5003a977deeSAkihiko Odaki 5013a977deeSAkihiko Odaki trace_e1000e_cb_post_load(); 5023a977deeSAkihiko Odaki return igb_core_post_load(&s->core); 5033a977deeSAkihiko Odaki } 5043a977deeSAkihiko Odaki 505212f7b1dSAkihiko Odaki static const VMStateDescription igb_vmstate_tx_ctx = { 506212f7b1dSAkihiko Odaki .name = "igb-tx-ctx", 5073a977deeSAkihiko Odaki .version_id = 1, 5083a977deeSAkihiko Odaki .minimum_version_id = 1, 5093a977deeSAkihiko Odaki .fields = (VMStateField[]) { 510212f7b1dSAkihiko Odaki VMSTATE_UINT32(vlan_macip_lens, struct e1000_adv_tx_context_desc), 511212f7b1dSAkihiko Odaki VMSTATE_UINT32(seqnum_seed, struct e1000_adv_tx_context_desc), 512212f7b1dSAkihiko Odaki VMSTATE_UINT32(type_tucmd_mlhl, struct e1000_adv_tx_context_desc), 513212f7b1dSAkihiko Odaki VMSTATE_UINT32(mss_l4len_idx, struct e1000_adv_tx_context_desc), 514212f7b1dSAkihiko Odaki VMSTATE_END_OF_LIST() 515212f7b1dSAkihiko Odaki } 516212f7b1dSAkihiko Odaki }; 517212f7b1dSAkihiko Odaki 518212f7b1dSAkihiko Odaki static const VMStateDescription igb_vmstate_tx = { 519212f7b1dSAkihiko Odaki .name = "igb-tx", 520212f7b1dSAkihiko Odaki .version_id = 2, 521212f7b1dSAkihiko Odaki .minimum_version_id = 2, 522212f7b1dSAkihiko Odaki .fields = (VMStateField[]) { 523212f7b1dSAkihiko Odaki VMSTATE_STRUCT_ARRAY(ctx, struct igb_tx, 2, 0, igb_vmstate_tx_ctx, 524212f7b1dSAkihiko Odaki struct e1000_adv_tx_context_desc), 525212f7b1dSAkihiko Odaki VMSTATE_UINT32(first_cmd_type_len, struct igb_tx), 526212f7b1dSAkihiko Odaki VMSTATE_UINT32(first_olinfo_status, struct igb_tx), 5273a977deeSAkihiko Odaki VMSTATE_BOOL(first, struct igb_tx), 5283a977deeSAkihiko Odaki VMSTATE_BOOL(skip_cp, struct igb_tx), 5293a977deeSAkihiko Odaki VMSTATE_END_OF_LIST() 5303a977deeSAkihiko Odaki } 5313a977deeSAkihiko Odaki }; 5323a977deeSAkihiko Odaki 5333a977deeSAkihiko Odaki static const VMStateDescription igb_vmstate_intr_timer = { 5343a977deeSAkihiko Odaki .name = "igb-intr-timer", 5353a977deeSAkihiko Odaki .version_id = 1, 5363a977deeSAkihiko Odaki .minimum_version_id = 1, 5373a977deeSAkihiko Odaki .fields = (VMStateField[]) { 5383a977deeSAkihiko Odaki VMSTATE_TIMER_PTR(timer, IGBIntrDelayTimer), 5393a977deeSAkihiko Odaki VMSTATE_BOOL(running, IGBIntrDelayTimer), 5403a977deeSAkihiko Odaki VMSTATE_END_OF_LIST() 5413a977deeSAkihiko Odaki } 5423a977deeSAkihiko Odaki }; 5433a977deeSAkihiko Odaki 5443a977deeSAkihiko Odaki #define VMSTATE_IGB_INTR_DELAY_TIMER(_f, _s) \ 5453a977deeSAkihiko Odaki VMSTATE_STRUCT(_f, _s, 0, \ 5463a977deeSAkihiko Odaki igb_vmstate_intr_timer, IGBIntrDelayTimer) 5473a977deeSAkihiko Odaki 5483a977deeSAkihiko Odaki #define VMSTATE_IGB_INTR_DELAY_TIMER_ARRAY(_f, _s, _num) \ 5493a977deeSAkihiko Odaki VMSTATE_STRUCT_ARRAY(_f, _s, _num, 0, \ 5503a977deeSAkihiko Odaki igb_vmstate_intr_timer, IGBIntrDelayTimer) 5513a977deeSAkihiko Odaki 5523a977deeSAkihiko Odaki static const VMStateDescription igb_vmstate = { 5533a977deeSAkihiko Odaki .name = "igb", 5543a977deeSAkihiko Odaki .version_id = 1, 5553a977deeSAkihiko Odaki .minimum_version_id = 1, 5563a977deeSAkihiko Odaki .pre_save = igb_pre_save, 5573a977deeSAkihiko Odaki .post_load = igb_post_load, 5583a977deeSAkihiko Odaki .fields = (VMStateField[]) { 5593a977deeSAkihiko Odaki VMSTATE_PCI_DEVICE(parent_obj, IGBState), 5603a977deeSAkihiko Odaki VMSTATE_MSIX(parent_obj, IGBState), 5613a977deeSAkihiko Odaki 5623a977deeSAkihiko Odaki VMSTATE_UINT32(ioaddr, IGBState), 5633a977deeSAkihiko Odaki VMSTATE_UINT8(core.rx_desc_len, IGBState), 5643a977deeSAkihiko Odaki VMSTATE_UINT16_ARRAY(core.eeprom, IGBState, IGB_EEPROM_SIZE), 5653a977deeSAkihiko Odaki VMSTATE_UINT16_ARRAY(core.phy, IGBState, MAX_PHY_REG_ADDRESS + 1), 5663a977deeSAkihiko Odaki VMSTATE_UINT32_ARRAY(core.mac, IGBState, E1000E_MAC_SIZE), 5673a977deeSAkihiko Odaki VMSTATE_UINT8_ARRAY(core.permanent_mac, IGBState, ETH_ALEN), 5683a977deeSAkihiko Odaki 5693a977deeSAkihiko Odaki VMSTATE_IGB_INTR_DELAY_TIMER_ARRAY(core.eitr, IGBState, 5703a977deeSAkihiko Odaki IGB_INTR_NUM), 5713a977deeSAkihiko Odaki 5723a977deeSAkihiko Odaki VMSTATE_UINT32_ARRAY(core.eitr_guest_value, IGBState, IGB_INTR_NUM), 5733a977deeSAkihiko Odaki 5743a977deeSAkihiko Odaki VMSTATE_STRUCT_ARRAY(core.tx, IGBState, IGB_NUM_QUEUES, 0, 5753a977deeSAkihiko Odaki igb_vmstate_tx, struct igb_tx), 5763a977deeSAkihiko Odaki 5773a977deeSAkihiko Odaki VMSTATE_INT64(core.timadj, IGBState), 5783a977deeSAkihiko Odaki 5793a977deeSAkihiko Odaki VMSTATE_END_OF_LIST() 5803a977deeSAkihiko Odaki } 5813a977deeSAkihiko Odaki }; 5823a977deeSAkihiko Odaki 5833a977deeSAkihiko Odaki static Property igb_properties[] = { 5843a977deeSAkihiko Odaki DEFINE_NIC_PROPERTIES(IGBState, conf), 5853a977deeSAkihiko Odaki DEFINE_PROP_END_OF_LIST(), 5863a977deeSAkihiko Odaki }; 5873a977deeSAkihiko Odaki 5883a977deeSAkihiko Odaki static void igb_class_init(ObjectClass *class, void *data) 5893a977deeSAkihiko Odaki { 5903a977deeSAkihiko Odaki DeviceClass *dc = DEVICE_CLASS(class); 5913a977deeSAkihiko Odaki ResettableClass *rc = RESETTABLE_CLASS(class); 5923a977deeSAkihiko Odaki PCIDeviceClass *c = PCI_DEVICE_CLASS(class); 5933a977deeSAkihiko Odaki 5943a977deeSAkihiko Odaki c->realize = igb_pci_realize; 5953a977deeSAkihiko Odaki c->exit = igb_pci_uninit; 5963a977deeSAkihiko Odaki c->vendor_id = PCI_VENDOR_ID_INTEL; 5973a977deeSAkihiko Odaki c->device_id = E1000_DEV_ID_82576; 5983a977deeSAkihiko Odaki c->revision = 1; 5993a977deeSAkihiko Odaki c->class_id = PCI_CLASS_NETWORK_ETHERNET; 6003a977deeSAkihiko Odaki 6013a977deeSAkihiko Odaki rc->phases.hold = igb_qdev_reset_hold; 6023a977deeSAkihiko Odaki 6033a977deeSAkihiko Odaki dc->desc = "Intel 82576 Gigabit Ethernet Controller"; 6043a977deeSAkihiko Odaki dc->vmsd = &igb_vmstate; 6053a977deeSAkihiko Odaki 6063a977deeSAkihiko Odaki device_class_set_props(dc, igb_properties); 6073a977deeSAkihiko Odaki set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); 6083a977deeSAkihiko Odaki } 6093a977deeSAkihiko Odaki 6103a977deeSAkihiko Odaki static void igb_instance_init(Object *obj) 6113a977deeSAkihiko Odaki { 6123a977deeSAkihiko Odaki IGBState *s = IGB(obj); 6133a977deeSAkihiko Odaki device_add_bootindex_property(obj, &s->conf.bootindex, 6143a977deeSAkihiko Odaki "bootindex", "/ethernet-phy@0", 6153a977deeSAkihiko Odaki DEVICE(obj)); 6163a977deeSAkihiko Odaki } 6173a977deeSAkihiko Odaki 6183a977deeSAkihiko Odaki static const TypeInfo igb_info = { 6193a977deeSAkihiko Odaki .name = TYPE_IGB, 6203a977deeSAkihiko Odaki .parent = TYPE_PCI_DEVICE, 6213a977deeSAkihiko Odaki .instance_size = sizeof(IGBState), 6223a977deeSAkihiko Odaki .class_init = igb_class_init, 6233a977deeSAkihiko Odaki .instance_init = igb_instance_init, 6243a977deeSAkihiko Odaki .interfaces = (InterfaceInfo[]) { 6253a977deeSAkihiko Odaki { INTERFACE_PCIE_DEVICE }, 6263a977deeSAkihiko Odaki { } 6273a977deeSAkihiko Odaki }, 6283a977deeSAkihiko Odaki }; 6293a977deeSAkihiko Odaki 6303a977deeSAkihiko Odaki static void igb_register_types(void) 6313a977deeSAkihiko Odaki { 6323a977deeSAkihiko Odaki type_register_static(&igb_info); 6333a977deeSAkihiko Odaki } 6343a977deeSAkihiko Odaki 6353a977deeSAkihiko Odaki type_init(igb_register_types) 636