qemu

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

pcnet-pci.c (9003B)


      1 /*
      2  * QEMU AMD PC-Net II (Am79C970A) PCI emulation
      3  *
      4  * Copyright (c) 2004 Antony T Curtis
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a copy
      7  * of this software and associated documentation files (the "Software"), to deal
      8  * in the Software without restriction, including without limitation the rights
      9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     10  * copies of the Software, and to permit persons to whom the Software is
     11  * furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included in
     14  * all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     22  * THE SOFTWARE.
     23  */
     24 
     25 /* This software was written to be compatible with the specification:
     26  * AMD Am79C970A PCnet-PCI II Ethernet Controller Data-Sheet
     27  * AMD Publication# 19436  Rev:E  Amendment/0  Issue Date: June 2000
     28  */
     29 
     30 #include "qemu/osdep.h"
     31 #include "hw/irq.h"
     32 #include "hw/pci/pci.h"
     33 #include "hw/qdev-properties.h"
     34 #include "migration/vmstate.h"
     35 #include "net/net.h"
     36 #include "qemu/module.h"
     37 #include "qemu/timer.h"
     38 #include "sysemu/dma.h"
     39 #include "sysemu/sysemu.h"
     40 #include "trace.h"
     41 
     42 #include "pcnet.h"
     43 #include "qom/object.h"
     44 
     45 //#define PCNET_DEBUG
     46 //#define PCNET_DEBUG_IO
     47 //#define PCNET_DEBUG_BCR
     48 //#define PCNET_DEBUG_CSR
     49 //#define PCNET_DEBUG_RMD
     50 //#define PCNET_DEBUG_TMD
     51 //#define PCNET_DEBUG_MATCH
     52 
     53 #define TYPE_PCI_PCNET "pcnet"
     54 
     55 OBJECT_DECLARE_SIMPLE_TYPE(PCIPCNetState, PCI_PCNET)
     56 
     57 struct PCIPCNetState {
     58     /*< private >*/
     59     PCIDevice parent_obj;
     60     /*< public >*/
     61 
     62     PCNetState state;
     63     MemoryRegion io_bar;
     64 };
     65 
     66 static void pcnet_aprom_writeb(void *opaque, uint32_t addr, uint32_t val)
     67 {
     68     PCNetState *s = opaque;
     69 
     70     trace_pcnet_aprom_writeb(opaque, addr, val);
     71     if (BCR_APROMWE(s)) {
     72         s->prom[addr & 15] = val;
     73     }
     74 }
     75 
     76 static uint32_t pcnet_aprom_readb(void *opaque, uint32_t addr)
     77 {
     78     PCNetState *s = opaque;
     79     uint32_t val = s->prom[addr & 15];
     80 
     81     trace_pcnet_aprom_readb(opaque, addr, val);
     82     return val;
     83 }
     84 
     85 static uint64_t pcnet_ioport_read(void *opaque, hwaddr addr,
     86                                   unsigned size)
     87 {
     88     PCNetState *d = opaque;
     89 
     90     trace_pcnet_ioport_read(opaque, addr, size);
     91     if (addr < 0x10) {
     92         if (!BCR_DWIO(d) && size == 1) {
     93             return pcnet_aprom_readb(d, addr);
     94         } else if (!BCR_DWIO(d) && (addr & 1) == 0 && size == 2) {
     95             return pcnet_aprom_readb(d, addr) |
     96                    (pcnet_aprom_readb(d, addr + 1) << 8);
     97         } else if (BCR_DWIO(d) && (addr & 3) == 0 && size == 4) {
     98             return pcnet_aprom_readb(d, addr) |
     99                    (pcnet_aprom_readb(d, addr + 1) << 8) |
    100                    (pcnet_aprom_readb(d, addr + 2) << 16) |
    101                    (pcnet_aprom_readb(d, addr + 3) << 24);
    102         }
    103     } else {
    104         if (size == 2) {
    105             return pcnet_ioport_readw(d, addr);
    106         } else if (size == 4) {
    107             return pcnet_ioport_readl(d, addr);
    108         }
    109     }
    110     return ((uint64_t)1 << (size * 8)) - 1;
    111 }
    112 
    113 static void pcnet_ioport_write(void *opaque, hwaddr addr,
    114                                uint64_t data, unsigned size)
    115 {
    116     PCNetState *d = opaque;
    117 
    118     trace_pcnet_ioport_write(opaque, addr, data, size);
    119     if (addr < 0x10) {
    120         if (!BCR_DWIO(d) && size == 1) {
    121             pcnet_aprom_writeb(d, addr, data);
    122         } else if (!BCR_DWIO(d) && (addr & 1) == 0 && size == 2) {
    123             pcnet_aprom_writeb(d, addr, data & 0xff);
    124             pcnet_aprom_writeb(d, addr + 1, data >> 8);
    125         } else if (BCR_DWIO(d) && (addr & 3) == 0 && size == 4) {
    126             pcnet_aprom_writeb(d, addr, data & 0xff);
    127             pcnet_aprom_writeb(d, addr + 1, (data >> 8) & 0xff);
    128             pcnet_aprom_writeb(d, addr + 2, (data >> 16) & 0xff);
    129             pcnet_aprom_writeb(d, addr + 3, data >> 24);
    130         }
    131     } else {
    132         if (size == 2) {
    133             pcnet_ioport_writew(d, addr, data);
    134         } else if (size == 4) {
    135             pcnet_ioport_writel(d, addr, data);
    136         }
    137     }
    138 }
    139 
    140 static const MemoryRegionOps pcnet_io_ops = {
    141     .read = pcnet_ioport_read,
    142     .write = pcnet_ioport_write,
    143     .endianness = DEVICE_LITTLE_ENDIAN,
    144 };
    145 
    146 static const VMStateDescription vmstate_pci_pcnet = {
    147     .name = "pcnet",
    148     .version_id = 3,
    149     .minimum_version_id = 2,
    150     .fields = (VMStateField[]) {
    151         VMSTATE_PCI_DEVICE(parent_obj, PCIPCNetState),
    152         VMSTATE_STRUCT(state, PCIPCNetState, 0, vmstate_pcnet, PCNetState),
    153         VMSTATE_END_OF_LIST()
    154     }
    155 };
    156 
    157 /* PCI interface */
    158 
    159 static const MemoryRegionOps pcnet_mmio_ops = {
    160     .read = pcnet_ioport_read,
    161     .write = pcnet_ioport_write,
    162     .valid.min_access_size = 1,
    163     .valid.max_access_size = 4,
    164     .impl.min_access_size = 1,
    165     .impl.max_access_size = 4,
    166     .endianness = DEVICE_LITTLE_ENDIAN,
    167 };
    168 
    169 static void pci_physical_memory_write(void *dma_opaque, hwaddr addr,
    170                                       uint8_t *buf, int len, int do_bswap)
    171 {
    172     pci_dma_write(dma_opaque, addr, buf, len);
    173 }
    174 
    175 static void pci_physical_memory_read(void *dma_opaque, hwaddr addr,
    176                                      uint8_t *buf, int len, int do_bswap)
    177 {
    178     pci_dma_read(dma_opaque, addr, buf, len);
    179 }
    180 
    181 static void pci_pcnet_uninit(PCIDevice *dev)
    182 {
    183     PCIPCNetState *d = PCI_PCNET(dev);
    184 
    185     qemu_free_irq(d->state.irq);
    186     timer_free(d->state.poll_timer);
    187     qemu_del_nic(d->state.nic);
    188 }
    189 
    190 static NetClientInfo net_pci_pcnet_info = {
    191     .type = NET_CLIENT_DRIVER_NIC,
    192     .size = sizeof(NICState),
    193     .receive = pcnet_receive,
    194     .link_status_changed = pcnet_set_link_status,
    195 };
    196 
    197 static void pci_pcnet_realize(PCIDevice *pci_dev, Error **errp)
    198 {
    199     PCIPCNetState *d = PCI_PCNET(pci_dev);
    200     PCNetState *s = &d->state;
    201     uint8_t *pci_conf;
    202 
    203 #if 0
    204     printf("sizeof(RMD)=%d, sizeof(TMD)=%d\n",
    205         sizeof(struct pcnet_RMD), sizeof(struct pcnet_TMD));
    206 #endif
    207 
    208     pci_conf = pci_dev->config;
    209 
    210     pci_set_word(pci_conf + PCI_STATUS,
    211                  PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM);
    212 
    213     pci_set_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID, 0x0);
    214     pci_set_word(pci_conf + PCI_SUBSYSTEM_ID, 0x0);
    215 
    216     pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */
    217     pci_conf[PCI_MIN_GNT] = 0x06;
    218     pci_conf[PCI_MAX_LAT] = 0xff;
    219 
    220     /* Handler for memory-mapped I/O */
    221     memory_region_init_io(&d->state.mmio, OBJECT(d), &pcnet_mmio_ops, s,
    222                           "pcnet-mmio", PCNET_PNPMMIO_SIZE);
    223 
    224     memory_region_init_io(&d->io_bar, OBJECT(d), &pcnet_io_ops, s, "pcnet-io",
    225                           PCNET_IOPORT_SIZE);
    226     pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &d->io_bar);
    227 
    228     pci_register_bar(pci_dev, 1, 0, &s->mmio);
    229 
    230     s->irq = pci_allocate_irq(pci_dev);
    231     s->phys_mem_read = pci_physical_memory_read;
    232     s->phys_mem_write = pci_physical_memory_write;
    233     s->dma_opaque = DEVICE(pci_dev);
    234 
    235     pcnet_common_init(DEVICE(pci_dev), s, &net_pci_pcnet_info);
    236 }
    237 
    238 static void pci_reset(DeviceState *dev)
    239 {
    240     PCIPCNetState *d = PCI_PCNET(dev);
    241 
    242     pcnet_h_reset(&d->state);
    243 }
    244 
    245 static void pcnet_instance_init(Object *obj)
    246 {
    247     PCIPCNetState *d = PCI_PCNET(obj);
    248     PCNetState *s = &d->state;
    249 
    250     device_add_bootindex_property(obj, &s->conf.bootindex,
    251                                   "bootindex", "/ethernet-phy@0",
    252                                   DEVICE(obj));
    253 }
    254 
    255 static Property pcnet_properties[] = {
    256     DEFINE_NIC_PROPERTIES(PCIPCNetState, state.conf),
    257     DEFINE_PROP_END_OF_LIST(),
    258 };
    259 
    260 static void pcnet_class_init(ObjectClass *klass, void *data)
    261 {
    262     DeviceClass *dc = DEVICE_CLASS(klass);
    263     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
    264 
    265     k->realize = pci_pcnet_realize;
    266     k->exit = pci_pcnet_uninit;
    267     k->romfile = "efi-pcnet.rom",
    268     k->vendor_id = PCI_VENDOR_ID_AMD;
    269     k->device_id = PCI_DEVICE_ID_AMD_LANCE;
    270     k->revision = 0x10;
    271     k->class_id = PCI_CLASS_NETWORK_ETHERNET;
    272     dc->reset = pci_reset;
    273     dc->vmsd = &vmstate_pci_pcnet;
    274     device_class_set_props(dc, pcnet_properties);
    275     set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
    276 }
    277 
    278 static const TypeInfo pcnet_info = {
    279     .name          = TYPE_PCI_PCNET,
    280     .parent        = TYPE_PCI_DEVICE,
    281     .instance_size = sizeof(PCIPCNetState),
    282     .class_init    = pcnet_class_init,
    283     .instance_init = pcnet_instance_init,
    284     .interfaces = (InterfaceInfo[]) {
    285         { INTERFACE_CONVENTIONAL_PCI_DEVICE },
    286         { },
    287     },
    288 };
    289 
    290 static void pci_pcnet_register_types(void)
    291 {
    292     type_register_static(&pcnet_info);
    293 }
    294 
    295 type_init(pci_pcnet_register_types)