Skip to content

Commit

Permalink
Merge remote-tracking branch 'mst/tags/for_anthony' into staging
Browse files Browse the repository at this point in the history
virtio,pci infrastructure

This includes infrastructure patches that don't do much by themselves
but should help vfio and q35 make progress.
Also included is rework of virtio-net to use iovec APIs
for vector access - helpful to make it more secure
and in preparation for a new feature that will allow
arbitrary s/g layout for guests.
Also included is a pci bridge bugfix by Avi.

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>

* mst/tags/for_anthony: (25 commits)
  pci: avoid destroying bridge address space windows in a transaction
  virtio-net: enable mrg buf header in tap on linux
  virtio-net: test peer header support at init time
  virtio-net: minor code simplification
  virtio-net: simplify rx code
  virtio-net: switch tx to safe iov functions
  virtio-net: first s/g is always at start of buf
  virtio-net: refactor receive_hdr
  virtio-net: use safe iov operations for rx
  virtio-net: avoid sg copy
  iov: add iov_cpy
  virtio-net: track host/guest header length
  pcie: Convert PCIExpressHost to use the QOM.
  pcie: pass pcie window size to pcie_host_mmcfg_update()
  pci: Add class 0xc05 as 'SMBus'
  pci: introduce pci_swizzle_map_irq_fn() for standardized interrupt pin swizzle
  pci_ids: add intel 82801BA pci-to-pci bridge id
  pci: pci capability must be in PCI space
  pci: make each capability DWORD aligned
  qemu: enable PV EOI for qemu 1.3
  ...

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
  • Loading branch information
Anthony Liguori committed Oct 29, 2012
2 parents b308c82 + 523a59f commit 233926f
Show file tree
Hide file tree
Showing 15 changed files with 266 additions and 146 deletions.
8 changes: 2 additions & 6 deletions hw/kvm/pci-assign.c
Expand Up @@ -882,8 +882,7 @@ static int assign_intx(AssignedDevice *dev)
intx_route = pci_device_route_intx_to_irq(&dev->dev, dev->intpin);
assert(intx_route.mode != PCI_INTX_INVERTED);

if (dev->intx_route.mode == intx_route.mode &&
dev->intx_route.irq == intx_route.irq) {
if (!pci_intx_route_changed(&dev->intx_route, &intx_route)) {
return 0;
}

Expand Down Expand Up @@ -997,12 +996,9 @@ static void assigned_dev_update_msi(PCIDevice *pci_dev)
}

if (ctrl_byte & PCI_MSI_FLAGS_ENABLE) {
uint8_t *pos = pci_dev->config + pci_dev->msi_cap;
MSIMessage msg;
MSIMessage msg = msi_get_message(pci_dev, 0);
int virq;

msg.address = pci_get_long(pos + PCI_MSI_ADDRESS_LO);
msg.data = pci_get_word(pos + PCI_MSI_DATA_32);
virq = kvm_irqchip_add_msi_route(kvm_state, msg);
if (virq < 0) {
perror("assigned_dev_update_msi: kvm_irqchip_add_msi_route");
Expand Down
45 changes: 29 additions & 16 deletions hw/msi.c
Expand Up @@ -122,6 +122,31 @@ void msi_set_message(PCIDevice *dev, MSIMessage msg)
pci_set_word(dev->config + msi_data_off(dev, msi64bit), msg.data);
}

MSIMessage msi_get_message(PCIDevice *dev, unsigned int vector)
{
uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
bool msi64bit = flags & PCI_MSI_FLAGS_64BIT;
unsigned int nr_vectors = msi_nr_vectors(flags);
MSIMessage msg;

assert(vector < nr_vectors);

if (msi64bit) {
msg.address = pci_get_quad(dev->config + msi_address_lo_off(dev));
} else {
msg.address = pci_get_long(dev->config + msi_address_lo_off(dev));
}

/* upper bit 31:16 is zero */
msg.data = pci_get_word(dev->config + msi_data_off(dev, msi64bit));
if (nr_vectors > 1) {
msg.data &= ~(nr_vectors - 1);
msg.data |= vector;
}

return msg;
}

bool msi_enabled(const PCIDevice *dev)
{
return msi_present(dev) &&
Expand Down Expand Up @@ -249,8 +274,7 @@ void msi_notify(PCIDevice *dev, unsigned int vector)
uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
bool msi64bit = flags & PCI_MSI_FLAGS_64BIT;
unsigned int nr_vectors = msi_nr_vectors(flags);
uint64_t address;
uint32_t data;
MSIMessage msg;

assert(vector < nr_vectors);
if (msi_is_masked(dev, vector)) {
Expand All @@ -261,24 +285,13 @@ void msi_notify(PCIDevice *dev, unsigned int vector)
return;
}

if (msi64bit) {
address = pci_get_quad(dev->config + msi_address_lo_off(dev));
} else {
address = pci_get_long(dev->config + msi_address_lo_off(dev));
}

/* upper bit 31:16 is zero */
data = pci_get_word(dev->config + msi_data_off(dev, msi64bit));
if (nr_vectors > 1) {
data &= ~(nr_vectors - 1);
data |= vector;
}
msg = msi_get_message(dev, vector);

MSI_DEV_PRINTF(dev,
"notify vector 0x%x"
" address: 0x%"PRIx64" data: 0x%"PRIx32"\n",
vector, address, data);
stl_le_phys(address, data);
vector, msg.address, msg.data);
stl_le_phys(msg.address, msg.data);
}

/* Normally called by pci_default_write_config(). */
Expand Down
1 change: 1 addition & 0 deletions hw/msi.h
Expand Up @@ -32,6 +32,7 @@ struct MSIMessage {
extern bool msi_supported;

void msi_set_message(PCIDevice *dev, MSIMessage msg);
MSIMessage msi_get_message(PCIDevice *dev, unsigned int vector);
bool msi_enabled(const PCIDevice *dev);
int msi_init(struct PCIDevice *dev, uint8_t offset,
unsigned int nr_vectors, bool msi64bit, bool msi_per_vector_mask);
Expand Down
9 changes: 8 additions & 1 deletion hw/pc_piix.c
Expand Up @@ -43,6 +43,7 @@
#include "xen.h"
#include "memory.h"
#include "exec-memory.h"
#include "cpu.h"
#ifdef CONFIG_XEN
# include <xen/hvm/hvm_info_table.h>
#endif
Expand Down Expand Up @@ -302,6 +303,12 @@ static void pc_init_pci(QEMUMachineInitArgs *args)
initrd_filename, cpu_model, 1, 1);
}

static void pc_init_pci_1_3(QEMUMachineInitArgs *args)
{
enable_kvm_pv_eoi();
pc_init_pci(args);
}

static void pc_init_pci_no_kvmclock(QEMUMachineInitArgs *args)
{
ram_addr_t ram_size = args->ram_size;
Expand Down Expand Up @@ -349,7 +356,7 @@ static QEMUMachine pc_machine_v1_3 = {
.name = "pc-1.3",
.alias = "pc",
.desc = "Standard PC",
.init = pc_init_pci,
.init = pc_init_pci_1_3,
.max_cpus = 255,
.is_default = 1,
};
Expand Down
42 changes: 36 additions & 6 deletions hw/pci.c
Expand Up @@ -1117,10 +1117,21 @@ PCIINTxRoute pci_device_route_intx_to_irq(PCIDevice *dev, int pin)
pin = bus->map_irq(dev, pin);
dev = bus->parent_dev;
} while (dev);
assert(bus->route_intx_to_irq);

if (!bus->route_intx_to_irq) {
error_report("PCI: Bug - unimplemented PCI INTx routing (%s)\n",
object_get_typename(OBJECT(bus->qbus.parent)));
return (PCIINTxRoute) { PCI_INTX_DISABLED, -1 };
}

return bus->route_intx_to_irq(bus->irq_opaque, pin);
}

bool pci_intx_route_changed(PCIINTxRoute *old, PCIINTxRoute *new)
{
return old->mode != new->mode || old->irq != new->irq;
}

void pci_bus_fire_intx_routing_notifier(PCIBus *bus)
{
PCIDevice *dev;
Expand All @@ -1144,6 +1155,24 @@ void pci_device_set_intx_routing_notifier(PCIDevice *dev,
dev->intx_routing_notifier = notifier;
}

/*
* PCI-to-PCI bridge specification
* 9.1: Interrupt routing. Table 9-1
*
* the PCI Express Base Specification, Revision 2.1
* 2.2.8.1: INTx interrutp signaling - Rules
* the Implementation Note
* Table 2-20
*/
/*
* 0 <= pin <= 3 0 = INTA, 1 = INTB, 2 = INTC, 3 = INTD
* 0-origin unlike PCI interrupt pin register.
*/
int pci_swizzle_map_irq_fn(PCIDevice *pci_dev, int pin)
{
return (pin + PCI_SLOT(pci_dev->devfn)) % PCI_NUM_PINS;
}

/***********************************************************/
/* monitor info on PCI */

Expand Down Expand Up @@ -1208,6 +1237,7 @@ static const pci_class_desc pci_class_descriptions[] =
{ 0x0c02, "SSA controller", "ssa"},
{ 0x0c03, "USB controller", "usb"},
{ 0x0c04, "Fibre channel controller", "fibre-channel"},
{ 0x0c05, "SMBus"},
{ 0, NULL}
};

Expand Down Expand Up @@ -1667,16 +1697,16 @@ PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name)
return pci_create_simple_multifunction(bus, devfn, false, name);
}

static int pci_find_space(PCIDevice *pdev, uint8_t size)
static uint8_t pci_find_space(PCIDevice *pdev, uint8_t size)
{
int config_size = pci_config_size(pdev);
int offset = PCI_CONFIG_HEADER_SIZE;
int i;
for (i = PCI_CONFIG_HEADER_SIZE; i < config_size; ++i)
for (i = PCI_CONFIG_HEADER_SIZE; i < PCI_CONFIG_SPACE_SIZE; ++i) {
if (pdev->used[i])
offset = i + 1;
else if (i - offset + 1 == size)
return offset;
}
return 0;
}

Expand Down Expand Up @@ -1895,7 +1925,7 @@ int pci_add_capability(PCIDevice *pdev, uint8_t cap_id,
config[PCI_CAP_LIST_NEXT] = pdev->config[PCI_CAPABILITY_LIST];
pdev->config[PCI_CAPABILITY_LIST] = offset;
pdev->config[PCI_STATUS] |= PCI_STATUS_CAP_LIST;
memset(pdev->used + offset, 0xFF, size);
memset(pdev->used + offset, 0xFF, QEMU_ALIGN_UP(size, 4));
/* Make capability read-only by default */
memset(pdev->wmask + offset, 0, size);
/* Check capability by default */
Expand All @@ -1915,7 +1945,7 @@ void pci_del_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size)
memset(pdev->w1cmask + offset, 0, size);
/* Clear cmask as device-specific registers can't be checked */
memset(pdev->cmask + offset, 0, size);
memset(pdev->used + offset, 0, size);
memset(pdev->used + offset, 0, QEMU_ALIGN_UP(size, 4));

if (!pdev->config[PCI_CAPABILITY_LIST])
pdev->config[PCI_STATUS] &= ~PCI_STATUS_CAP_LIST;
Expand Down
3 changes: 3 additions & 0 deletions hw/pci.h
Expand Up @@ -318,6 +318,8 @@ void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
void *irq_opaque, int nirq);
int pci_bus_get_irq_level(PCIBus *bus, int irq_num);
void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *dev);
/* 0 <= pin <= 3 0 = INTA, 1 = INTB, 2 = INTC, 3 = INTD */
int pci_swizzle_map_irq_fn(PCIDevice *pci_dev, int pin);
PCIBus *pci_register_bus(DeviceState *parent, const char *name,
pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
void *irq_opaque,
Expand All @@ -326,6 +328,7 @@ PCIBus *pci_register_bus(DeviceState *parent, const char *name,
uint8_t devfn_min, int nirq);
void pci_bus_set_route_irq_fn(PCIBus *, pci_route_irq_fn);
PCIINTxRoute pci_device_route_intx_to_irq(PCIDevice *dev, int pin);
bool pci_intx_route_changed(PCIINTxRoute *old, PCIINTxRoute *new);
void pci_bus_fire_intx_routing_notifier(PCIBus *bus);
void pci_device_set_intx_routing_notifier(PCIDevice *dev,
PCIINTxRoutingNotifier notifier);
Expand Down
2 changes: 2 additions & 0 deletions hw/pci_ids.h
Expand Up @@ -31,6 +31,7 @@
#define PCI_CLASS_SYSTEM_OTHER 0x0880

#define PCI_CLASS_SERIAL_USB 0x0c03
#define PCI_CLASS_SERIAL_SMBUS 0x0c05

#define PCI_CLASS_BRIDGE_HOST 0x0600
#define PCI_CLASS_BRIDGE_ISA 0x0601
Expand Down Expand Up @@ -105,6 +106,7 @@
#define PCI_DEVICE_ID_INTEL_82378 0x0484
#define PCI_DEVICE_ID_INTEL_82441 0x1237
#define PCI_DEVICE_ID_INTEL_82801AA_5 0x2415
#define PCI_DEVICE_ID_INTEL_82801BA_11 0x244e
#define PCI_DEVICE_ID_INTEL_82801D 0x24CD
#define PCI_DEVICE_ID_INTEL_ESB_9 0x25ab
#define PCI_DEVICE_ID_INTEL_82371SB_0 0x7000
Expand Down
35 changes: 26 additions & 9 deletions hw/pcie_host.c
Expand Up @@ -107,14 +107,9 @@ static const MemoryRegionOps pcie_mmcfg_ops = {
/* pcie_host::base_addr == PCIE_BASE_ADDR_UNMAPPED when it isn't mapped. */
#define PCIE_BASE_ADDR_UNMAPPED ((hwaddr)-1ULL)

int pcie_host_init(PCIExpressHost *e, uint32_t size)
int pcie_host_init(PCIExpressHost *e)
{
assert(!(size & (size - 1))); /* power of 2 */
assert(size >= PCIE_MMCFG_SIZE_MIN);
assert(size <= PCIE_MMCFG_SIZE_MAX);
e->base_addr = PCIE_BASE_ADDR_UNMAPPED;
e->size = size;
memory_region_init_io(&e->mmio, &pcie_mmcfg_ops, e, "pcie-mmcfg", e->size);

return 0;
}
Expand All @@ -123,22 +118,44 @@ void pcie_host_mmcfg_unmap(PCIExpressHost *e)
{
if (e->base_addr != PCIE_BASE_ADDR_UNMAPPED) {
memory_region_del_subregion(get_system_memory(), &e->mmio);
memory_region_destroy(&e->mmio);
e->base_addr = PCIE_BASE_ADDR_UNMAPPED;
}
}

void pcie_host_mmcfg_map(PCIExpressHost *e, hwaddr addr)
void pcie_host_mmcfg_map(PCIExpressHost *e, hwaddr addr,
uint32_t size)
{
assert(!(size & (size - 1))); /* power of 2 */
assert(size >= PCIE_MMCFG_SIZE_MIN);
assert(size <= PCIE_MMCFG_SIZE_MAX);
e->size = size;
memory_region_init_io(&e->mmio, &pcie_mmcfg_ops, e, "pcie-mmcfg", e->size);
e->base_addr = addr;
memory_region_add_subregion(get_system_memory(), e->base_addr, &e->mmio);
}

void pcie_host_mmcfg_update(PCIExpressHost *e,
int enable,
hwaddr addr)
hwaddr addr,
uint32_t size)
{
pcie_host_mmcfg_unmap(e);
if (enable) {
pcie_host_mmcfg_map(e, addr);
pcie_host_mmcfg_map(e, addr, size);
}
}

static const TypeInfo pcie_host_type_info = {
.name = TYPE_PCIE_HOST_BRIDGE,
.parent = TYPE_PCI_HOST_BRIDGE,
.abstract = true,
.instance_size = sizeof(PCIExpressHost),
};

static void pcie_host_register_types(void)
{
type_register_static(&pcie_host_type_info);
}

type_init(pcie_host_register_types)
11 changes: 8 additions & 3 deletions hw/pcie_host.h
Expand Up @@ -24,6 +24,10 @@
#include "pci_host.h"
#include "memory.h"

#define TYPE_PCIE_HOST_BRIDGE "pcie-host-bridge"
#define PCIE_HOST_BRIDGE(obj) \
OBJECT_CHECK(PCIExpressHost, (obj), TYPE_PCIE_HOST_BRIDGE)

struct PCIExpressHost {
PCIHostState pci;

Expand All @@ -39,11 +43,12 @@ struct PCIExpressHost {
MemoryRegion mmio;
};

int pcie_host_init(PCIExpressHost *e, uint32_t size);
int pcie_host_init(PCIExpressHost *e);
void pcie_host_mmcfg_unmap(PCIExpressHost *e);
void pcie_host_mmcfg_map(PCIExpressHost *e, hwaddr addr);
void pcie_host_mmcfg_map(PCIExpressHost *e, hwaddr addr, uint32_t size);
void pcie_host_mmcfg_update(PCIExpressHost *e,
int enable,
hwaddr addr);
hwaddr addr,
uint32_t size);

#endif /* PCIE_HOST_H */
13 changes: 0 additions & 13 deletions hw/vhost_net.c
Expand Up @@ -150,10 +150,6 @@ int vhost_net_start(struct vhost_net *net,
if (r < 0) {
goto fail_notifiers;
}
if (net->dev.acked_features & (1 << VIRTIO_NET_F_MRG_RXBUF)) {
tap_set_vnet_hdr_len(net->nc,
sizeof(struct virtio_net_hdr_mrg_rxbuf));
}

r = vhost_dev_start(&net->dev, dev);
if (r < 0) {
Expand All @@ -179,9 +175,6 @@ int vhost_net_start(struct vhost_net *net,
}
net->nc->info->poll(net->nc, true);
vhost_dev_stop(&net->dev, dev);
if (net->dev.acked_features & (1 << VIRTIO_NET_F_MRG_RXBUF)) {
tap_set_vnet_hdr_len(net->nc, sizeof(struct virtio_net_hdr));
}
fail_start:
vhost_dev_disable_notifiers(&net->dev, dev);
fail_notifiers:
Expand All @@ -199,18 +192,12 @@ void vhost_net_stop(struct vhost_net *net,
}
net->nc->info->poll(net->nc, true);
vhost_dev_stop(&net->dev, dev);
if (net->dev.acked_features & (1 << VIRTIO_NET_F_MRG_RXBUF)) {
tap_set_vnet_hdr_len(net->nc, sizeof(struct virtio_net_hdr));
}
vhost_dev_disable_notifiers(&net->dev, dev);
}

void vhost_net_cleanup(struct vhost_net *net)
{
vhost_dev_cleanup(&net->dev);
if (net->dev.acked_features & (1 << VIRTIO_NET_F_MRG_RXBUF)) {
tap_set_vnet_hdr_len(net->nc, sizeof(struct virtio_net_hdr));
}
g_free(net);
}
#else
Expand Down

0 comments on commit 233926f

Please sign in to comment.