From d0d311338391c78ce45a4986c3fc757d25f8054e Mon Sep 17 00:00:00 2001 From: Vladimir Koshelev Date: Mon, 26 Sep 2011 13:45:06 +0400 Subject: [PATCH 15/32] PCI-2-PCI Bridge support --- palacios/include/devices/pci.h | 2 +- palacios/include/devices/pci_types.h | 6 ++ palacios/src/devices/pci.c | 79 ++++++++++++++++++++++++++++--- palacios/src/devices/pci_passthrough.c | 46 +++++++++++++++---- 4 files changed, 115 insertions(+), 18 deletions(-) diff --git a/palacios/include/devices/pci.h b/palacios/include/devices/pci.h index 92a20d6..ac20885 100644 --- a/palacios/include/devices/pci.h +++ b/palacios/include/devices/pci.h @@ -115,7 +115,7 @@ struct pci_device { struct { struct pci_config_header config_header; - uint8_t config_data[192]; + uint8_t config_data[256 - sizeof(struct pci_config_header)]; } __attribute__((packed)); } __attribute__((packed)); diff --git a/palacios/include/devices/pci_types.h b/palacios/include/devices/pci_types.h index c3cd4cb..931c0f8 100644 --- a/palacios/include/devices/pci_types.h +++ b/palacios/include/devices/pci_types.h @@ -63,6 +63,12 @@ struct pci_config_header { } __attribute__((packed)); +#define PCI_HEADER_PCI_DEVICE 0x0 +#define PCI_HEADER_PCI_TO_PCI_BRIGDE 0x1 +#define PCI_HEADER_PCI_MULTIFUNCTION 0x80 + + + typedef enum { PCI_CLASS_PRE2 = 0x00, PCI_CLASS_STORAGE = 0x01, PCI_CLASS_NETWORK = 0x02, diff --git a/palacios/src/devices/pci.c b/palacios/src/devices/pci.c index 355ea09..118cd7e 100644 --- a/palacios/src/devices/pci.c +++ b/palacios/src/devices/pci.c @@ -398,6 +398,25 @@ static inline int is_cfg_reg_writable(uchar_t header_type, int reg_num) { return 1; } + } else if (header_type == 0x01) { + switch (reg_num) { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0e: + case 0x1b: + case 0x3d: + return 0; + + default: + return 1; + + } } else { // PCI to PCI Bridge = 0x01 // CardBus Bridge = 0x02 @@ -574,8 +593,20 @@ static int data_port_write(struct guest_info * core, ushort_t port, void * src, } // Scan for BAR updated + int count; + switch (pci_dev->config_header.header_type & (~((uint8_t)PCI_HEADER_PCI_MULTIFUNCTION))) { + case PCI_HEADER_PCI_DEVICE : + count = 6; + break; + case PCI_HEADER_PCI_TO_PCI_BRIGDE : + count = 2; + break; + default : + PrintError("Wrong pci_dev->config_header.header_type %d!\n", pci_dev->config_header.header_type); + return -1; + } if (pci_dev->bar_update_flag) { - for (i = 0; i < 6; i++) { + for (i = 0; i < count; i++) { if (pci_dev->bar[i].updated) { int bar_offset = 0x10 + 4 * i; @@ -715,8 +746,23 @@ device_register("PCI", pci_init) static inline int init_bars(struct v3_vm_info * vm, struct pci_device * pci_dev) { int i = 0; - - for (i = 0; i < 6; i++) { + // Scan for BAR updated + int count; + switch (pci_dev->config_header.header_type & (~((uint8_t)PCI_HEADER_PCI_MULTIFUNCTION))) { + case PCI_HEADER_PCI_DEVICE : + count = 6; + break; + case PCI_HEADER_PCI_TO_PCI_BRIGDE : + count = 2; + break; + default : + PrintError("Wrong pci_dev->config_header.header_type %d!\n", pci_dev->config_header.header_type); + return -1; + } + PrintDebug("%d:%d header type %d, count = %d\n", + pci_dev->config_header.vendor_id, pci_dev->config_header.device_id, + pci_dev->config_header.header_type, count); + for (i = 0; i < count; i++) { int bar_offset = 0x10 + (4 * i); if (pci_dev->bar[i].type == PCI_BAR_IO) { @@ -1031,17 +1077,18 @@ struct pci_device * v3_pci_register_passthrough_device(struct vm_device * pci, pci_dev->type = dev_type; - switch (pci_dev->type) { - case PCI_STD_DEVICE: + switch (pci_dev->type & ~((uint8_t)(PCI_HEADER_PCI_MULTIFUNCTION))) { + case 0x0: pci_dev->config_header.header_type = 0x00; break; - case PCI_MULTIFUNCTION: - pci_dev->config_header.header_type = 0x80; + case 0x1: + pci_dev->config_header.header_type = 0x01; break; default: PrintError("Unhandled PCI Device Type: %d\n", dev_type); return NULL; } + PrintDebug("dev_type is %d, setting pci_dev->config_header.header_type to %d\n", dev_type, pci_dev->config_header.header_type); @@ -1060,7 +1107,23 @@ struct pci_device * v3_pci_register_passthrough_device(struct vm_device * pci, pci_dev->irq_type = PCI_IRQ_INTX; //copy bars - for (i = 0; i < 6; i ++) { + // Scan for BAR updated + int count; + + //TODO change PCI_HEADER_PCI_DEV to PCI_STD_DEVICE + switch (pci_dev->config_header.header_type & (~((uint8_t)PCI_HEADER_PCI_MULTIFUNCTION))) { + case PCI_HEADER_PCI_DEVICE : + count = 6; + break; + case PCI_HEADER_PCI_TO_PCI_BRIGDE : + count = 2; + break; + default : + PrintError("Wrong pci_dev->config_header.header_type %d!\n", pci_dev->config_header.header_type); + return NULL; + } + + for (i = 0; i < count; i ++) { pci_dev->bar[i].type = bars[i].type; pci_dev->bar[i].private_data = bars[i].private_data; diff --git a/palacios/src/devices/pci_passthrough.c b/palacios/src/devices/pci_passthrough.c index a6e5bdf..ca2ee7b 100644 --- a/palacios/src/devices/pci_passthrough.c +++ b/palacios/src/devices/pci_passthrough.c @@ -1728,11 +1728,27 @@ static int setup_virt_pci_dev(struct v3_vm_info * vm_info, struct vm_device * de int bus_num = 0; int i; - for (i = 0; i < 6; i++) { - bars[i].type = PCI_BAR_PASSTHROUGH; - bars[i].private_data = dev; - bars[i].bar_init = pci_bar_init; - bars[i].bar_write = pci_bar_write; + + + // Scan for BAR updated + int count; + switch (state->real_hdr.header_type & (~((uint8_t)PCI_HEADER_PCI_MULTIFUNCTION))) { + case PCI_HEADER_PCI_DEVICE : + count = 6; + break; + case PCI_HEADER_PCI_TO_PCI_BRIGDE : + count = 2; + break; + default : + PrintError("Wrong pci_dev->config_header.header_type %d!\n", pci_dev->config_header.header_type); + return -1; + } + + for (i = 0; i < count; i++) { + bars[i].type = PCI_BAR_PASSTHROUGH; + bars[i].private_data = dev; + bars[i].bar_init = pci_bar_init; + bars[i].bar_write = pci_bar_write; } int fn = 0, devno = -1; @@ -1747,7 +1763,7 @@ static int setup_virt_pci_dev(struct v3_vm_info * vm_info, struct vm_device * de pci_dev = v3_pci_register_passthrough_device(state->pci_bus, - PCI_STD_DEVICE, + state->real_hdr.header_type, bus_num, devno, fn, state->name, bars, pt_config_update, @@ -1765,9 +1781,21 @@ static int setup_virt_pci_dev(struct v3_vm_info * vm_info, struct vm_device * de INIT_LIST_HEAD(&state->cfg_virtual_ranges); int status = 0; // do not passthrough accesses to the following registers. - status |= cfg_range_hook_add(0x0, 0x4, cfg_range_read_virtual, cfg_range_noop, state); // device and vendor IDs - status |= cfg_range_hook_add(0x8, 0x4, cfg_range_read_virtual, cfg_range_noop, state); // revision ID and class code - status |= cfg_range_hook_add(0x10, 0x30, cfg_range_read_virtual, cfg_range_noop, state); // BARs etc. + switch (pci_dev->config_header.header_type & (~((uint8_t)PCI_HEADER_PCI_MULTIFUNCTION))) { + case PCI_HEADER_PCI_DEVICE : { + status |= cfg_range_hook_add(0x0, 0x4, cfg_range_read_virtual, cfg_range_noop, state); // device and vendor IDs + status |= cfg_range_hook_add(0x8, 0x4, cfg_range_read_virtual, cfg_range_noop, state); // revision ID and class code + status |= cfg_range_hook_add(0x10, 0x30, cfg_range_read_virtual, cfg_range_noop, state); // BARs etc. + } break; + case PCI_HEADER_PCI_TO_PCI_BRIGDE : { + status |= cfg_range_hook_add(0x0, 0x4, cfg_range_read_virtual, cfg_range_noop, state); // device and vendor IDs + status |= cfg_range_hook_add(0x8, 0x4, cfg_range_read_virtual, cfg_range_noop, state); // revision ID and class code + //status |= cfg_range_hook_add(0x10, 0x18, cfg_range_read_virtual, cfg_range_noop, state); // BARs etc. + } break; + default : + PrintError("Wrong PCI header type %d\n", pci_dev->config_header.header_type); + return -1; + } if(status) return -1; cfg = v3_cfg_subtree(cfg, "exclude_cap"); -- 1.7.5.4