/* default write_config function for PCI-to-PCI bridge */ void pci_bridge_write_config(PCIDevice *d, uint32_t address, uint32_t val, int len) { PCIBridge *s = container_of(d, PCIBridge, dev); uint16_t oldctl = pci_get_word(d->config + PCI_BRIDGE_CONTROL); uint16_t newctl; pci_default_write_config(d, address, val, len); if (ranges_overlap(address, len, PCI_COMMAND, 2) || /* io base/limit */ ranges_overlap(address, len, PCI_IO_BASE, 2) || /* memory base/limit, prefetchable base/limit and io base/limit upper 16 */ ranges_overlap(address, len, PCI_MEMORY_BASE, 20)) { pci_bridge_update_mappings(s); } newctl = pci_get_word(d->config + PCI_BRIDGE_CONTROL); if (~oldctl & newctl & PCI_BRIDGE_CTL_BUS_RESET) { /* Trigger hot reset on 0->1 transition. */ pci_bus_reset(&s->sec_bus); } }
static void pm_write_config(PCIDevice *d, uint32_t address, uint32_t val, int len) { pci_default_write_config(d, address, val, len); if (range_covers_byte(address, len, 0x80)) pm_io_space_update((PIIX4PMState *)d); }
static void xilinx_pcie_root_config_write(PCIDevice *d, uint32_t address, uint32_t val, int len) { XilinxPCIEHost *s = XILINX_PCIE_HOST(OBJECT(d)->parent); switch (address) { case ROOTCFG_INTDEC: xilinx_pcie_update_intr(s, 0, val); break; case ROOTCFG_INTMASK: s->intr_mask = val; xilinx_pcie_update_intr(s, 0, 0); break; case ROOTCFG_RPSCR: s->rpscr &= ~ROOTCFG_RPSCR_BRIDGEEN; s->rpscr |= val & ROOTCFG_RPSCR_BRIDGEEN; memory_region_set_enabled(&s->mmio, val & ROOTCFG_RPSCR_BRIDGEEN); if (val & ROOTCFG_INTMASK_INTX) { s->rpscr &= ~ROOTCFG_INTMASK_INTX; } break; case ROOTCFG_RPIFR1: case ROOTCFG_RPIFR2: if (s->intr_fifo_w == s->intr_fifo_r) { /* FIFO empty */ return; } else { s->intr_fifo_r = (s->intr_fifo_r + 1) % ARRAY_SIZE(s->intr_fifo); } break; default: pci_default_write_config(d, address, val, len); break; } }
static void i6300esb_config_write(PCIDevice *dev, uint32_t addr, uint32_t data, int len) { I6300State *d = DO_UPCAST(I6300State, dev, dev); int old; i6300esb_debug("addr = %x, data = %x, len = %d\n", addr, data, len); if (addr == ESB_CONFIG_REG && len == 2) { d->reboot_enabled = (data & ESB_WDT_REBOOT) == 0; d->clock_scale = (data & ESB_WDT_FREQ) != 0 ? CLOCK_SCALE_1MHZ : CLOCK_SCALE_1KHZ; d->int_type = (data & ESB_WDT_INTTYPE); } else if (addr == ESB_LOCK_REG && len == 1) { if (!d->locked) { d->locked = (data & ESB_WDT_LOCK) != 0; d->free_run = (data & ESB_WDT_FUNC) != 0; old = d->enabled; d->enabled = (data & ESB_WDT_ENABLE) != 0; if (!old && d->enabled) /* Enabled transitioned from 0 -> 1 */ i6300esb_restart_timer(d, 1); else if (!d->enabled) i6300esb_disable_timer(d); } } else { pci_default_write_config(dev, addr, data, len); } }
static void assigned_dev_pci_write_config(PCIDevice *d, uint32_t address, uint32_t val, int len) { int fd; ssize_t ret; AssignedDevice *pci_dev = container_of(d, AssignedDevice, dev); DEBUG("(%x.%x): address=%04x val=0x%08x len=%d\n", ((d->devfn >> 3) & 0x1F), (d->devfn & 0x7), (uint16_t) address, val, len); if (address == 0x4) { pci_default_write_config(d, address, val, len); /* Continue to program the card */ } if ((address >= 0x10 && address <= 0x24) || address == 0x34 || address == 0x3c || address == 0x3d || pci_access_cap_config(d, address, len)) { /* used for update-mappings (BAR emulation) */ pci_default_write_config(d, address, val, len); return; } DEBUG("NON BAR (%x.%x): address=%04x val=0x%08x len=%d\n", ((d->devfn >> 3) & 0x1F), (d->devfn & 0x7), (uint16_t) address, val, len); fd = pci_dev->real_device.config_fd; again: ret = pwrite(fd, &val, len, address); if (ret != len) { if ((ret < 0) && (errno == EINTR || errno == EAGAIN)) goto again; fprintf(stderr, "%s: pwrite failed, ret = %zd errno = %d\n", __func__, ret, errno); exit(1); } }
void igd_pci_write(PCIDevice *pci_dev, uint32_t config_addr, uint32_t val, int len) { assert(pci_dev->devfn == 0x00); if ( !igd_passthru ) { pci_default_write_config(pci_dev, config_addr, val, len); return; } switch (config_addr) { case 0x58: // PAVPC Offset pt_pci_host_write(0, 0, 0, config_addr, val, len); PT_LOG("pci_config_write: %x:%x.%x: addr=%x len=%x val=%x\n", pci_bus_num(pci_dev->bus), PCI_SLOT(pci_dev->devfn), PCI_FUNC(pci_dev->devfn), config_addr, len, val); break; default: pci_default_write_config(pci_dev, config_addr, val, len); } }
static void e1000e_write_config(PCIDevice *pci_dev, uint32_t address, uint32_t val, int len) { E1000EState *s = E1000E(pci_dev); pci_default_write_config(pci_dev, address, val, len); if (range_covers_byte(address, len, PCI_COMMAND) && (pci_dev->config[PCI_COMMAND] & PCI_COMMAND_MASTER)) { e1000e_start_recv(&s->core); } }
static void e1000e_write_config(PCIDevice *pci_dev, uint32_t address, uint32_t val, int len) { E1000EState *s = E1000E(pci_dev); pci_default_write_config(pci_dev, address, val, len); if (range_covers_byte(address, len, PCI_COMMAND) && (pci_dev->config[PCI_COMMAND] & PCI_COMMAND_MASTER)) { qemu_flush_queued_packets(qemu_get_queue(s->nic)); } }
static void pm_write_config(PCIDevice *d, uint32_t address, uint32_t val, int len) { pci_default_write_config(d, address, val, len); if (range_covers_byte(address, len, 0x80) || ranges_overlap(address, len, 0x40, 4)) { pm_io_space_update((PIIX4PMState *)d); } if (range_covers_byte(address, len, 0xd2) || ranges_overlap(address, len, 0x90, 4)) { smbus_io_space_update((PIIX4PMState *)d); } }
static void usb_ehci_pci_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int l) { EHCIPCIState *i = DO_UPCAST(EHCIPCIState, pcidev, dev); bool busmaster; pci_default_write_config(dev, addr, val, l); if (!range_covers_byte(addr, l, PCI_COMMAND)) { return; } busmaster = pci_get_word(dev->config + PCI_COMMAND) & PCI_COMMAND_MASTER; i->ehci.dma = busmaster ? pci_dma_context(dev) : NULL; }
static void ivshmem_write_config(PCIDevice *pdev, uint32_t address, uint32_t val, int len) { IVShmemState *s = IVSHMEM_COMMON(pdev); int is_enabled, was_enabled = msix_enabled(pdev); pci_default_write_config(pdev, address, val, len); is_enabled = msix_enabled(pdev); if (kvm_msi_via_irqfd_enabled()) { if (!was_enabled && is_enabled) { ivshmem_enable_irqfd(s); } else if (was_enabled && !is_enabled) { ivshmem_disable_irqfd(s); } } }
static void mch_write_config(PCIDevice *d, uint32_t address, uint32_t val, int len) { MCHPCIState *mch = MCH_PCI_DEVICE(d); pci_default_write_config(d, address, val, len); if (ranges_overlap(address, len, MCH_HOST_BRIDGE_PAM0, MCH_HOST_BRIDGE_PAM_SIZE)) { mch_update_pam(mch); } if (ranges_overlap(address, len, MCH_HOST_BRIDGE_PCIEXBAR, MCH_HOST_BRIDGE_PCIEXBAR_SIZE)) { mch_update_pciexbar(mch); } if (ranges_overlap(address, len, MCH_HOST_BRIDGE_SMRAM, MCH_HOST_BRIDGE_SMRAM_SIZE)) { mch_update_smram(mch); } }
static void ivshmem_write_config(PCIDevice *pci_dev, uint32_t address, uint32_t val, int len) { pci_default_write_config(pci_dev, address, val, len); msix_write_config(pci_dev, address, val, len); }
static void xen_pt_pci_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int len) { XenPCIPassthroughState *s = DO_UPCAST(XenPCIPassthroughState, dev, d); int index = 0; XenPTRegGroup *reg_grp_entry = NULL; int rc = 0; uint32_t read_val = 0; int emul_len = 0; XenPTReg *reg_entry = NULL; uint32_t find_addr = addr; XenPTRegInfo *reg = NULL; if (xen_pt_pci_config_access_check(d, addr, len)) { return; } XEN_PT_LOG_CONFIG(d, addr, val, len); /* check unused BAR register */ index = xen_pt_bar_offset_to_index(addr); if ((index >= 0) && (val > 0 && val < XEN_PT_BAR_ALLF) && (s->bases[index].bar_flag == XEN_PT_BAR_FLAG_UNUSED)) { XEN_PT_WARN(d, "Guest attempt to set address to unused Base Address " "Register. (addr: 0x%02x, len: %d)\n", addr, len); } /* find register group entry */ reg_grp_entry = xen_pt_find_reg_grp(s, addr); if (reg_grp_entry) { /* check 0-Hardwired register group */ if (reg_grp_entry->reg_grp->grp_type == XEN_PT_GRP_TYPE_HARDWIRED) { /* ignore silently */ XEN_PT_WARN(d, "Access to 0-Hardwired register. " "(addr: 0x%02x, len: %d)\n", addr, len); return; } } rc = xen_host_pci_get_block(&s->real_device, addr, (uint8_t *)&read_val, len); if (rc < 0) { XEN_PT_ERR(d, "pci_read_block failed. return value: %d.\n", rc); memset(&read_val, 0xff, len); } /* pass directly to the real device for passthrough type register group */ if (reg_grp_entry == NULL) { goto out; } memory_region_transaction_begin(); pci_default_write_config(d, addr, val, len); /* adjust the read and write value to appropriate CFC-CFF window */ read_val <<= (addr & 3) << 3; val <<= (addr & 3) << 3; emul_len = len; /* loop around the guest requested size */ while (emul_len > 0) { /* find register entry to be emulated */ reg_entry = xen_pt_find_reg(reg_grp_entry, find_addr); if (reg_entry) { reg = reg_entry->reg; uint32_t real_offset = reg_grp_entry->base_offset + reg->offset; uint32_t valid_mask = 0xFFFFFFFF >> ((4 - emul_len) << 3); uint8_t *ptr_val = NULL; valid_mask <<= (find_addr - real_offset) << 3; ptr_val = (uint8_t *)&val + (real_offset & 3); /* do emulation based on register size */ switch (reg->size) { case 1: if (reg->u.b.write) { rc = reg->u.b.write(s, reg_entry, ptr_val, read_val >> ((real_offset & 3) << 3), valid_mask); } break; case 2: if (reg->u.w.write) { rc = reg->u.w.write(s, reg_entry, (uint16_t *)ptr_val, (read_val >> ((real_offset & 3) << 3)), valid_mask); } break; case 4: if (reg->u.dw.write) { rc = reg->u.dw.write(s, reg_entry, (uint32_t *)ptr_val, (read_val >> ((real_offset & 3) << 3)), valid_mask); } break; }
static void pci_ich9_write_config(PCIDevice *pci, uint32_t addr, uint32_t val, int len) { pci_default_write_config(pci, addr, val, len); msi_write_config(pci, addr, val, len); }