debuggers.hg
changeset 17094:c6eeb71a85cf
Enable HVM guest VT-d device hotplug via a simple ACPI hotplug device model.
** Currently only 2 virtual hotplug pci slots(6~7) are created so more
than 2 vtd dev can't be hotplugged, but we can easily extend it in
future.
Three new commands are added:
"xm pci-list domid" show the current assigned vtd device, like:
VSlt domain bus slot func
0x6 0x0 0x02 0x00 0x0
"xm pci-detach" hot remove the specified vtd device by the virtual
slot, like:
xm pci-detach EdwinHVMDomainVtd 6
"xm pci-attach DomainID dom bus dev func [vslot]" hot add a new vtd
device in the vslot. If no vslot specified, a free slot will be picked
up. e.g. to insert '0000:03:00.0':
xm pci-attach EdwinHVMDomainVtd 0 3 0 0
** guest pci hotplug
linux: pls. use 2.6.X and enable ACPI PCI hotplug ( Bus options=> PCI
hotplug => ACPI PCI hotplug driver )
windows: 2000/xp/2003/vista are all okay
Signed-off-by: Zhai Edwin <edwin.zhai@intel.com>
** Currently only 2 virtual hotplug pci slots(6~7) are created so more
than 2 vtd dev can't be hotplugged, but we can easily extend it in
future.
Three new commands are added:
"xm pci-list domid" show the current assigned vtd device, like:
VSlt domain bus slot func
0x6 0x0 0x02 0x00 0x0
"xm pci-detach" hot remove the specified vtd device by the virtual
slot, like:
xm pci-detach EdwinHVMDomainVtd 6
"xm pci-attach DomainID dom bus dev func [vslot]" hot add a new vtd
device in the vslot. If no vslot specified, a free slot will be picked
up. e.g. to insert '0000:03:00.0':
xm pci-attach EdwinHVMDomainVtd 0 3 0 0
** guest pci hotplug
linux: pls. use 2.6.X and enable ACPI PCI hotplug ( Bus options=> PCI
hotplug => ACPI PCI hotplug driver )
windows: 2000/xp/2003/vista are all okay
Signed-off-by: Zhai Edwin <edwin.zhai@intel.com>
line diff
1.1 --- a/tools/firmware/hvmloader/acpi/dsdt.asl Fri Feb 15 12:50:55 2008 +0000 1.2 +++ b/tools/firmware/hvmloader/acpi/dsdt.asl Fri Feb 15 14:13:17 2008 +0000 1.3 @@ -86,7 +86,7 @@ DefinitionBlock ("DSDT.aml", "DSDT", 2, 1.4 Name (_UID, 0x00) 1.5 Name (_ADR, 0x00) 1.6 Name (_BBN, 0x00) 1.7 - 1.8 + 1.9 Method (_CRS, 0, NotSerialized) 1.10 { 1.11 Name (PRT0, ResourceTemplate () 1.12 @@ -720,6 +720,121 @@ DefinitionBlock ("DSDT.aml", "DSDT", 2, 1.13 }) 1.14 } 1.15 } 1.16 + 1.17 + /****************************************************************** 1.18 + * Each PCI hotplug slot needs at least two methods to handle 1.19 + * the ACPI event: 1.20 + * _EJ0: eject a device 1.21 + * _STA: return a device's status, e.g. enabled or removed 1.22 + * Other methods are optional: 1.23 + * _PS0/3: put them here for debug purpose 1.24 + * 1.25 + * Eject button would generate a general-purpose event, then the 1.26 + * control method for this event uses Notify() to inform OSPM which 1.27 + * action happened and on which device. 1.28 + * 1.29 + * Pls. refer "6.3 Device Insertion, Removal, and Status Objects" 1.30 + * in ACPI spec 3.0b for details. 1.31 + * 1.32 + * QEMU provides a simple hotplug controller with some I/O to 1.33 + * handle the hotplug action and status, which is beyond the ACPI 1.34 + * scope. 1.35 + */ 1.36 + 1.37 + Device (S1F0) 1.38 + { 1.39 + Name (_ADR, 0x00060000) /* Dev 6, Func 0 */ 1.40 + Name (_SUN, 0x00000001) 1.41 + 1.42 + Method (_PS0, 0) 1.43 + { 1.44 + Store (0x80, \_GPE.DPT2) 1.45 + } 1.46 + 1.47 + Method (_PS3, 0) 1.48 + { 1.49 + Store (0x83, \_GPE.DPT2) 1.50 + } 1.51 + 1.52 + Method (_EJ0, 1) 1.53 + { 1.54 + Store (0x88, \_GPE.DPT2) 1.55 + Store (0x1, \_GPE.PHP1) /* eject php slot 1*/ 1.56 + } 1.57 + 1.58 + Method (_STA, 0) 1.59 + { 1.60 + Store (0x89, \_GPE.DPT2) 1.61 + Return ( \_GPE.PHP1 ) /* IN status as the _STA */ 1.62 + } 1.63 + } 1.64 + 1.65 + Device (S2F0) 1.66 + { 1.67 + Name (_ADR, 0x00070000) /* Dev 7, Func 0 */ 1.68 + Name (_SUN, 0x00000002) 1.69 + 1.70 + Method (_PS0, 0) 1.71 + { 1.72 + Store (0x90, \_GPE.DPT2) 1.73 + } 1.74 + 1.75 + Method (_PS3, 0) 1.76 + { 1.77 + Store (0x93, \_GPE.DPT2) 1.78 + } 1.79 + 1.80 + Method (_EJ0, 1) 1.81 + { 1.82 + Store (0x98, \_GPE.DPT2) 1.83 + Store (0x1, \_GPE.PHP2) /* eject php slot 1*/ 1.84 + } 1.85 + 1.86 + Method (_STA, 0) 1.87 + { 1.88 + Store (0x99, \_GPE.DPT2) 1.89 + Return ( \_GPE.PHP2 ) /* IN status as the _STA */ 1.90 + } 1.91 + } 1.92 + } 1.93 + } 1.94 + 1.95 + Scope (\_GPE) 1.96 + { 1.97 + OperationRegion (PHP, SystemIO, 0x10c0, 0x03) 1.98 + Field (PHP, ByteAcc, NoLock, Preserve) 1.99 + { 1.100 + PSTA, 8, /* hotplug controller status reg */ 1.101 + PHP1, 8, /* hotplug slot 1 control reg */ 1.102 + PHP2, 8 /* hotplug slot 2 control reg */ 1.103 + } 1.104 + OperationRegion (DG1, SystemIO, 0xb044, 0x04) 1.105 + Field (DG1, ByteAcc, NoLock, Preserve) 1.106 + { 1.107 + DPT1, 8, 1.108 + DPT2, 8 1.109 + } 1.110 + Method (_L03, 0, NotSerialized) 1.111 + { 1.112 + /* detect slot and event(remove/add) */ 1.113 + Name (SLT, 0x0) 1.114 + Name (EVT, 0x0) 1.115 + Store (PSTA, Local1) 1.116 + ShiftRight (Local1, 0x4, SLT) 1.117 + And (Local1, 0xf, EVT) 1.118 + 1.119 + /* debug */ 1.120 + Store (SLT, DPT1) 1.121 + Store (EVT, DPT2) 1.122 + 1.123 + If ( LEqual(SLT, 0x1) ) 1.124 + { 1.125 + Notify (\_SB.PCI0.S1F0, EVT) 1.126 + } 1.127 + ElseIf ( LEqual(SLT, 0x2) ) 1.128 + { 1.129 + Notify (\_SB.PCI0.S2F0, EVT) 1.130 + } 1.131 } 1.132 } 1.133 }
2.1 --- a/tools/firmware/hvmloader/acpi/dsdt.c Fri Feb 15 12:50:55 2008 +0000 2.2 +++ b/tools/firmware/hvmloader/acpi/dsdt.c Fri Feb 15 14:13:17 2008 +0000 2.3 @@ -5,15 +5,15 @@ 2.4 * Copyright (C) 2000 - 2006 Intel Corporation 2.5 * Supports ACPI Specification Revision 3.0a 2.6 * 2.7 - * Compilation of "dsdt.asl" - Fri Feb 15 12:48:58 2008 2.8 + * Compilation of "dsdt.asl" - Fri Feb 15 14:07:57 2008 2.9 * 2.10 * C source code output 2.11 * 2.12 */ 2.13 unsigned char AmlCode[] = 2.14 { 2.15 - 0x44,0x53,0x44,0x54,0x9C,0x0E,0x00,0x00, /* 00000000 "DSDT...." */ 2.16 - 0x02,0xD5,0x58,0x65,0x6E,0x00,0x00,0x00, /* 00000008 "..Xen..." */ 2.17 + 0x44,0x53,0x44,0x54,0x5A,0x10,0x00,0x00, /* 00000000 "DSDTZ..." */ 2.18 + 0x02,0xCC,0x58,0x65,0x6E,0x00,0x00,0x00, /* 00000008 "..Xen..." */ 2.19 0x48,0x56,0x4D,0x00,0x00,0x00,0x00,0x00, /* 00000010 "HVM....." */ 2.20 0x00,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ 2.21 0x07,0x07,0x06,0x20,0x08,0x50,0x4D,0x42, /* 00000020 "... .PMB" */ 2.22 @@ -29,7 +29,7 @@ unsigned char AmlCode[] = 2.23 0x07,0x0A,0x07,0x00,0x00,0x08,0x50,0x49, /* 00000070 "......PI" */ 2.24 0x43,0x44,0x00,0x14,0x0C,0x5F,0x50,0x49, /* 00000078 "CD..._PI" */ 2.25 0x43,0x01,0x70,0x68,0x50,0x49,0x43,0x44, /* 00000080 "C.phPICD" */ 2.26 - 0x10,0x43,0xE1,0x5F,0x53,0x42,0x5F,0x5B, /* 00000088 ".C._SB_[" */ 2.27 + 0x10,0x42,0xF1,0x5F,0x53,0x42,0x5F,0x5B, /* 00000088 ".B._SB_[" */ 2.28 0x80,0x42,0x49,0x4F,0x53,0x00,0x0C,0x00, /* 00000090 ".BIOS..." */ 2.29 0xA0,0x0E,0x00,0x0A,0x10,0x5B,0x81,0x21, /* 00000098 ".....[.!" */ 2.30 0x42,0x49,0x4F,0x53,0x01,0x55,0x41,0x52, /* 000000A0 "BIOS.UAR" */ 2.31 @@ -45,7 +45,7 @@ unsigned char AmlCode[] = 2.32 0x00,0xFF,0xFF,0x09,0x00,0x00,0x00,0x00, /* 000000F0 "........" */ 2.33 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 000000F8 "........" */ 2.34 0x00,0x00,0x00,0x0A,0x00,0x00,0x00,0x00, /* 00000100 "........" */ 2.35 - 0x00,0x79,0x00,0x5B,0x82,0x4F,0xD8,0x50, /* 00000108 ".y.[.O.P" */ 2.36 + 0x00,0x79,0x00,0x5B,0x82,0x4E,0xE8,0x50, /* 00000108 ".y.[.N.P" */ 2.37 0x43,0x49,0x30,0x08,0x5F,0x48,0x49,0x44, /* 00000110 "CI0._HID" */ 2.38 0x0C,0x41,0xD0,0x0A,0x03,0x08,0x5F,0x55, /* 00000118 ".A...._U" */ 2.39 0x49,0x44,0x00,0x08,0x5F,0x41,0x44,0x52, /* 00000120 "ID.._ADR" */ 2.40 @@ -479,6 +479,62 @@ unsigned char AmlCode[] = 2.41 0x54,0x41,0x00,0xA4,0x0A,0x0F,0x08,0x5F, /* 00000E80 "TA....._" */ 2.42 0x43,0x52,0x53,0x11,0x10,0x0A,0x0D,0x47, /* 00000E88 "CRS....G" */ 2.43 0x01,0x78,0x03,0x78,0x03,0x08,0x08,0x22, /* 00000E90 ".x.x..."" */ 2.44 - 0x80,0x00,0x79,0x00, 2.45 + 0x80,0x00,0x79,0x00,0x5B,0x82,0x4D,0x07, /* 00000E98 "..y.[.M." */ 2.46 + 0x53,0x31,0x46,0x30,0x08,0x5F,0x41,0x44, /* 00000EA0 "S1F0._AD" */ 2.47 + 0x52,0x0C,0x00,0x00,0x06,0x00,0x08,0x5F, /* 00000EA8 "R......_" */ 2.48 + 0x53,0x55,0x4E,0x01,0x14,0x13,0x5F,0x50, /* 00000EB0 "SUN..._P" */ 2.49 + 0x53,0x30,0x00,0x70,0x0A,0x80,0x5C,0x2E, /* 00000EB8 "S0.p..\." */ 2.50 + 0x5F,0x47,0x50,0x45,0x44,0x50,0x54,0x32, /* 00000EC0 "_GPEDPT2" */ 2.51 + 0x14,0x13,0x5F,0x50,0x53,0x33,0x00,0x70, /* 00000EC8 ".._PS3.p" */ 2.52 + 0x0A,0x83,0x5C,0x2E,0x5F,0x47,0x50,0x45, /* 00000ED0 "..\._GPE" */ 2.53 + 0x44,0x50,0x54,0x32,0x14,0x1F,0x5F,0x45, /* 00000ED8 "DPT2.._E" */ 2.54 + 0x4A,0x30,0x01,0x70,0x0A,0x88,0x5C,0x2E, /* 00000EE0 "J0.p..\." */ 2.55 + 0x5F,0x47,0x50,0x45,0x44,0x50,0x54,0x32, /* 00000EE8 "_GPEDPT2" */ 2.56 + 0x70,0x01,0x5C,0x2E,0x5F,0x47,0x50,0x45, /* 00000EF0 "p.\._GPE" */ 2.57 + 0x50,0x48,0x50,0x31,0x14,0x1E,0x5F,0x53, /* 00000EF8 "PHP1.._S" */ 2.58 + 0x54,0x41,0x00,0x70,0x0A,0x89,0x5C,0x2E, /* 00000F00 "TA.p..\." */ 2.59 + 0x5F,0x47,0x50,0x45,0x44,0x50,0x54,0x32, /* 00000F08 "_GPEDPT2" */ 2.60 + 0xA4,0x5C,0x2E,0x5F,0x47,0x50,0x45,0x50, /* 00000F10 ".\._GPEP" */ 2.61 + 0x48,0x50,0x31,0x5B,0x82,0x4E,0x07,0x53, /* 00000F18 "HP1[.N.S" */ 2.62 + 0x32,0x46,0x30,0x08,0x5F,0x41,0x44,0x52, /* 00000F20 "2F0._ADR" */ 2.63 + 0x0C,0x00,0x00,0x07,0x00,0x08,0x5F,0x53, /* 00000F28 "......_S" */ 2.64 + 0x55,0x4E,0x0A,0x02,0x14,0x13,0x5F,0x50, /* 00000F30 "UN...._P" */ 2.65 + 0x53,0x30,0x00,0x70,0x0A,0x90,0x5C,0x2E, /* 00000F38 "S0.p..\." */ 2.66 + 0x5F,0x47,0x50,0x45,0x44,0x50,0x54,0x32, /* 00000F40 "_GPEDPT2" */ 2.67 + 0x14,0x13,0x5F,0x50,0x53,0x33,0x00,0x70, /* 00000F48 ".._PS3.p" */ 2.68 + 0x0A,0x93,0x5C,0x2E,0x5F,0x47,0x50,0x45, /* 00000F50 "..\._GPE" */ 2.69 + 0x44,0x50,0x54,0x32,0x14,0x1F,0x5F,0x45, /* 00000F58 "DPT2.._E" */ 2.70 + 0x4A,0x30,0x01,0x70,0x0A,0x98,0x5C,0x2E, /* 00000F60 "J0.p..\." */ 2.71 + 0x5F,0x47,0x50,0x45,0x44,0x50,0x54,0x32, /* 00000F68 "_GPEDPT2" */ 2.72 + 0x70,0x01,0x5C,0x2E,0x5F,0x47,0x50,0x45, /* 00000F70 "p.\._GPE" */ 2.73 + 0x50,0x48,0x50,0x32,0x14,0x1E,0x5F,0x53, /* 00000F78 "PHP2.._S" */ 2.74 + 0x54,0x41,0x00,0x70,0x0A,0x99,0x5C,0x2E, /* 00000F80 "TA.p..\." */ 2.75 + 0x5F,0x47,0x50,0x45,0x44,0x50,0x54,0x32, /* 00000F88 "_GPEDPT2" */ 2.76 + 0xA4,0x5C,0x2E,0x5F,0x47,0x50,0x45,0x50, /* 00000F90 ".\._GPEP" */ 2.77 + 0x48,0x50,0x32,0x10,0x4E,0x0B,0x5F,0x47, /* 00000F98 "HP2.N._G" */ 2.78 + 0x50,0x45,0x5B,0x80,0x50,0x48,0x50,0x5F, /* 00000FA0 "PE[.PHP_" */ 2.79 + 0x01,0x0B,0xC0,0x10,0x0A,0x03,0x5B,0x81, /* 00000FA8 "......[." */ 2.80 + 0x15,0x50,0x48,0x50,0x5F,0x01,0x50,0x53, /* 00000FB0 ".PHP_.PS" */ 2.81 + 0x54,0x41,0x08,0x50,0x48,0x50,0x31,0x08, /* 00000FB8 "TA.PHP1." */ 2.82 + 0x50,0x48,0x50,0x32,0x08,0x5B,0x80,0x44, /* 00000FC0 "PHP2.[.D" */ 2.83 + 0x47,0x31,0x5F,0x01,0x0B,0x44,0xB0,0x0A, /* 00000FC8 "G1_..D.." */ 2.84 + 0x04,0x5B,0x81,0x10,0x44,0x47,0x31,0x5F, /* 00000FD0 ".[..DG1_" */ 2.85 + 0x01,0x44,0x50,0x54,0x31,0x08,0x44,0x50, /* 00000FD8 ".DPT1.DP" */ 2.86 + 0x54,0x32,0x08,0x14,0x46,0x07,0x5F,0x4C, /* 00000FE0 "T2..F._L" */ 2.87 + 0x30,0x33,0x00,0x08,0x53,0x4C,0x54,0x5F, /* 00000FE8 "03..SLT_" */ 2.88 + 0x00,0x08,0x45,0x56,0x54,0x5F,0x00,0x70, /* 00000FF0 "..EVT_.p" */ 2.89 + 0x50,0x53,0x54,0x41,0x61,0x7A,0x61,0x0A, /* 00000FF8 "PSTAaza." */ 2.90 + 0x04,0x53,0x4C,0x54,0x5F,0x7B,0x61,0x0A, /* 00001000 ".SLT_{a." */ 2.91 + 0x0F,0x45,0x56,0x54,0x5F,0x70,0x53,0x4C, /* 00001008 ".EVT_pSL" */ 2.92 + 0x54,0x5F,0x44,0x50,0x54,0x31,0x70,0x45, /* 00001010 "T_DPT1pE" */ 2.93 + 0x56,0x54,0x5F,0x44,0x50,0x54,0x32,0xA0, /* 00001018 "VT_DPT2." */ 2.94 + 0x1B,0x93,0x53,0x4C,0x54,0x5F,0x01,0x86, /* 00001020 "..SLT_.." */ 2.95 + 0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50, /* 00001028 "\/._SB_P" */ 2.96 + 0x43,0x49,0x30,0x53,0x31,0x46,0x30,0x45, /* 00001030 "CI0S1F0E" */ 2.97 + 0x56,0x54,0x5F,0xA1,0x1E,0xA0,0x1C,0x93, /* 00001038 "VT_....." */ 2.98 + 0x53,0x4C,0x54,0x5F,0x0A,0x02,0x86,0x5C, /* 00001040 "SLT_...\" */ 2.99 + 0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43, /* 00001048 "/._SB_PC" */ 2.100 + 0x49,0x30,0x53,0x32,0x46,0x30,0x45,0x56, /* 00001050 "I0S2F0EV" */ 2.101 + 0x54,0x5F, 2.102 }; 2.103 int DsdtLen=sizeof(AmlCode);
3.1 --- a/tools/firmware/hvmloader/acpi/static_tables.c Fri Feb 15 12:50:55 2008 +0000 3.2 +++ b/tools/firmware/hvmloader/acpi/static_tables.c Fri Feb 15 14:13:17 2008 +0000 3.3 @@ -59,9 +59,11 @@ struct acpi_20_fadt Fadt = { 3.4 .pm1a_evt_blk = ACPI_PM1A_EVT_BLK_ADDRESS, 3.5 .pm1a_cnt_blk = ACPI_PM1A_CNT_BLK_ADDRESS, 3.6 .pm_tmr_blk = ACPI_PM_TMR_BLK_ADDRESS, 3.7 + .gpe0_blk = ACPI_GPE0_BLK_ADDRESS, 3.8 .pm1_evt_len = ACPI_PM1A_EVT_BLK_BIT_WIDTH / 8, 3.9 .pm1_cnt_len = ACPI_PM1A_CNT_BLK_BIT_WIDTH / 8, 3.10 .pm_tmr_len = ACPI_PM_TMR_BLK_BIT_WIDTH / 8, 3.11 + .gpe0_blk_len = ACPI_GPE0_BLK_LEN, 3.12 3.13 .p_lvl2_lat = 0x0fff, /* >100, means we do not support C2 state */ 3.14 .p_lvl3_lat = 0x0fff, /* >1000, means we do not support C3 state */
4.1 --- a/tools/ioemu/hw/pass-through.c Fri Feb 15 12:50:55 2008 +0000 4.2 +++ b/tools/ioemu/hw/pass-through.c Fri Feb 15 14:13:17 2008 +0000 4.3 @@ -29,33 +29,161 @@ 4.4 4.5 extern FILE *logfile; 4.6 4.7 +struct php_dev { 4.8 + struct pt_dev *pt_dev; 4.9 + uint8_t valid; 4.10 + uint8_t r_bus; 4.11 + uint8_t r_dev; 4.12 + uint8_t r_func; 4.13 +}; 4.14 +struct dpci_infos { 4.15 + 4.16 + struct php_dev php_devs[PHP_SLOT_LEN]; 4.17 + 4.18 + PCIBus *e_bus; 4.19 + struct pci_access *pci_access; 4.20 + 4.21 +} dpci_infos; 4.22 + 4.23 static int token_value(char *token) 4.24 { 4.25 - token = strchr(token, 'x') + 1; 4.26 return strtol(token, NULL, 16); 4.27 } 4.28 4.29 static int next_bdf(char **str, int *seg, int *bus, int *dev, int *func) 4.30 { 4.31 - char *token; 4.32 + char *token, *delim = ":.-"; 4.33 4.34 - if ( !(*str) || !strchr(*str, ',') ) 4.35 + if ( !(*str) || 4.36 + ( !strchr(*str, ':') && !strchr(*str, '.')) ) 4.37 return 0; 4.38 4.39 - token = *str; 4.40 - *seg = token_value(token); 4.41 - token = strchr(token, ',') + 1; 4.42 + token = strsep(str, delim); 4.43 + *seg = token_value(token); 4.44 + 4.45 + token = strsep(str, delim); 4.46 *bus = token_value(token); 4.47 - token = strchr(token, ',') + 1; 4.48 + 4.49 + token = strsep(str, delim); 4.50 *dev = token_value(token); 4.51 - token = strchr(token, ',') + 1; 4.52 + 4.53 + token = strsep(str, delim); 4.54 *func = token_value(token); 4.55 - token = strchr(token, ','); 4.56 - *str = token ? token + 1 : NULL; 4.57 4.58 return 1; 4.59 } 4.60 4.61 +/* Insert a new pass-through device into a specific pci slot. 4.62 + * input dom:bus:dev.func@slot, chose free one if slot == 0 4.63 + * return -1: required slot not available 4.64 + * 0: no free hotplug slots, but normal slot should okay 4.65 + * >0: the new hotplug slot 4.66 + */ 4.67 +static int __insert_to_pci_slot(int bus, int dev, int func, int slot) 4.68 +{ 4.69 + int i, php_slot; 4.70 + 4.71 + /* preferred virt pci slot */ 4.72 + if ( slot >= PHP_SLOT_START && slot < PHP_SLOT_END ) 4.73 + { 4.74 + php_slot = PCI_TO_PHP_SLOT(slot); 4.75 + if ( !dpci_infos.php_devs[php_slot].valid ) 4.76 + { 4.77 + goto found; 4.78 + } 4.79 + else 4.80 + return -1; 4.81 + } 4.82 + 4.83 + if ( slot != 0 ) 4.84 + return -1; 4.85 + 4.86 + /* slot == 0, pick up a free one */ 4.87 + for ( i = 0; i < PHP_SLOT_LEN; i++ ) 4.88 + { 4.89 + if ( !dpci_infos.php_devs[i].valid ) 4.90 + { 4.91 + php_slot = i; 4.92 + goto found; 4.93 + } 4.94 + } 4.95 + 4.96 + /* not found */ 4.97 + return 0; 4.98 + 4.99 +found: 4.100 + dpci_infos.php_devs[php_slot].valid = 1; 4.101 + dpci_infos.php_devs[php_slot].r_bus = bus; 4.102 + dpci_infos.php_devs[php_slot].r_dev = dev; 4.103 + dpci_infos.php_devs[php_slot].r_func = func; 4.104 + return PHP_TO_PCI_SLOT(php_slot); 4.105 +} 4.106 + 4.107 +/* Insert a new pass-through device into a specific pci slot. 4.108 + * input dom:bus:dev.func@slot 4.109 + */ 4.110 +int insert_to_pci_slot(char *bdf_slt) 4.111 +{ 4.112 + int seg, bus, dev, func, slot; 4.113 + char *bdf_str, *slt_str, *delim="@"; 4.114 + 4.115 + bdf_str = strsep(&bdf_slt, delim); 4.116 + slt_str = bdf_slt; 4.117 + slot = token_value(slt_str); 4.118 + 4.119 + if ( !next_bdf(&bdf_str, &seg, &bus, &dev, &func)) 4.120 + { 4.121 + return -1; 4.122 + } 4.123 + 4.124 + return __insert_to_pci_slot(bus, dev, func, slot); 4.125 + 4.126 +} 4.127 + 4.128 +/* Test if a pci slot has a device 4.129 + * 1: present 4.130 + * 0: not present 4.131 + * -1: invalide pci slot input 4.132 + */ 4.133 +int test_pci_slot(int slot) 4.134 +{ 4.135 + int php_slot; 4.136 + 4.137 + if ( slot < PHP_SLOT_START || slot >= PHP_SLOT_END ) 4.138 + return -1; 4.139 + 4.140 + php_slot = PCI_TO_PHP_SLOT(slot); 4.141 + if ( dpci_infos.php_devs[php_slot].valid ) 4.142 + return 1; 4.143 + else 4.144 + return 0; 4.145 +} 4.146 + 4.147 +/* find the pci slot for pass-through dev with specified BDF */ 4.148 +int bdf_to_slot(char *bdf_str) 4.149 +{ 4.150 + int seg, bus, dev, func, i; 4.151 + 4.152 + if ( !next_bdf(&bdf_str, &seg, &bus, &dev, &func)) 4.153 + { 4.154 + return -1; 4.155 + } 4.156 + 4.157 + /* locate the virtual pci slot for this VTd device */ 4.158 + for ( i = 0; i < PHP_SLOT_LEN; i++ ) 4.159 + { 4.160 + if ( dpci_infos.php_devs[i].valid && 4.161 + dpci_infos.php_devs[i].r_bus == bus && 4.162 + dpci_infos.php_devs[i].r_dev == dev && 4.163 + dpci_infos.php_devs[i].r_func == func ) 4.164 + { 4.165 + return PHP_TO_PCI_SLOT(i); 4.166 + } 4.167 + } 4.168 + 4.169 + return -1; 4.170 +} 4.171 + 4.172 /* Being called each time a mmio region has been updated */ 4.173 void pt_iomem_map(PCIDevice *d, int i, uint32_t e_phys, uint32_t e_size, 4.174 int type) 4.175 @@ -269,15 +397,64 @@ static int pt_register_regions(struct pt 4.176 return 0; 4.177 } 4.178 4.179 +static int pt_unregister_regions(struct pt_dev *assigned_device) 4.180 +{ 4.181 + int i, type, ret; 4.182 + uint32_t e_size; 4.183 + PCIDevice *d = (PCIDevice*)assigned_device; 4.184 + 4.185 + for ( i = 0; i < PCI_NUM_REGIONS; i++ ) 4.186 + { 4.187 + e_size = assigned_device->bases[i].e_size; 4.188 + if ( e_size == 0 ) 4.189 + continue; 4.190 + 4.191 + type = d->io_regions[i].type; 4.192 + 4.193 + if ( type == PCI_ADDRESS_SPACE_MEM || 4.194 + type == PCI_ADDRESS_SPACE_MEM_PREFETCH ) 4.195 + { 4.196 + ret = xc_domain_memory_mapping(xc_handle, domid, 4.197 + assigned_device->bases[i].e_physbase >> XC_PAGE_SHIFT, 4.198 + assigned_device->bases[i].access.maddr >> XC_PAGE_SHIFT, 4.199 + (e_size+XC_PAGE_SIZE-1) >> XC_PAGE_SHIFT, 4.200 + DPCI_REMOVE_MAPPING); 4.201 + if ( ret != 0 ) 4.202 + { 4.203 + PT_LOG("Error: remove old mem mapping failed!\n"); 4.204 + continue; 4.205 + } 4.206 + 4.207 + } 4.208 + else if ( type == PCI_ADDRESS_SPACE_IO ) 4.209 + { 4.210 + ret = xc_domain_ioport_mapping(xc_handle, domid, 4.211 + assigned_device->bases[i].e_physbase, 4.212 + assigned_device->bases[i].access.pio_base, 4.213 + e_size, 4.214 + DPCI_REMOVE_MAPPING); 4.215 + if ( ret != 0 ) 4.216 + { 4.217 + PT_LOG("Error: remove old io mapping failed!\n"); 4.218 + continue; 4.219 + } 4.220 + 4.221 + } 4.222 + 4.223 + } 4.224 + 4.225 +} 4.226 + 4.227 struct pt_dev * register_real_device(PCIBus *e_bus, 4.228 const char *e_dev_name, int e_devfn, uint8_t r_bus, uint8_t r_dev, 4.229 uint8_t r_func, uint32_t machine_irq, struct pci_access *pci_access) 4.230 { 4.231 - int rc, i; 4.232 + int rc = -1, i; 4.233 struct pt_dev *assigned_device = NULL; 4.234 struct pci_dev *pci_dev; 4.235 uint8_t e_device, e_intx; 4.236 struct pci_config_cf8 machine_bdf; 4.237 + int free_pci_slot = -1; 4.238 4.239 PT_LOG("Assigning real physical device %02x:%02x.%x ...\n", 4.240 r_bus, r_dev, r_func); 4.241 @@ -296,6 +473,15 @@ struct pt_dev * register_real_device(PCI 4.242 return NULL; 4.243 } 4.244 4.245 + if ( e_devfn == PT_VIRT_DEVFN_AUTO ) { 4.246 + /*indicate a static assignment(not hotplug), so find a free PCI hot plug slot */ 4.247 + free_pci_slot = __insert_to_pci_slot(r_bus, r_dev, r_func, 0); 4.248 + if ( free_pci_slot > 0 ) 4.249 + e_devfn = free_pci_slot << 3; 4.250 + else 4.251 + PT_LOG("Error: no free virtual PCI hot plug slot, thus no live migration.\n"); 4.252 + } 4.253 + 4.254 /* Register device */ 4.255 assigned_device = (struct pt_dev *) pci_register_device(e_bus, e_dev_name, 4.256 sizeof(struct pt_dev), e_devfn, 4.257 @@ -306,8 +492,12 @@ struct pt_dev * register_real_device(PCI 4.258 return NULL; 4.259 } 4.260 4.261 + if ( free_pci_slot > 0 ) 4.262 + dpci_infos.php_devs[PCI_TO_PHP_SLOT(free_pci_slot)].pt_dev = assigned_device; 4.263 + 4.264 assigned_device->pci_dev = pci_dev; 4.265 4.266 + 4.267 /* Assign device */ 4.268 machine_bdf.reg = 0; 4.269 machine_bdf.bus = r_bus; 4.270 @@ -355,11 +545,96 @@ struct pt_dev * register_real_device(PCI 4.271 return assigned_device; 4.272 } 4.273 4.274 +int unregister_real_device(int php_slot) 4.275 +{ 4.276 + struct php_dev *php_dev; 4.277 + struct pci_dev *pci_dev; 4.278 + uint8_t e_device, e_intx; 4.279 + struct pt_dev *assigned_device = NULL; 4.280 + uint32_t machine_irq; 4.281 + uint32_t bdf = 0; 4.282 + int rc = -1; 4.283 + 4.284 + if ( php_slot < 0 || php_slot >= PHP_SLOT_LEN ) 4.285 + return -1; 4.286 + 4.287 + php_dev = &dpci_infos.php_devs[php_slot]; 4.288 + assigned_device = php_dev->pt_dev; 4.289 + 4.290 + if ( !assigned_device || !php_dev->valid ) 4.291 + return -1; 4.292 + 4.293 + pci_dev = assigned_device->pci_dev; 4.294 + 4.295 + /* hide pci dev from qemu */ 4.296 + pci_hide_device((PCIDevice*)assigned_device); 4.297 + 4.298 + /* Unbind interrupt */ 4.299 + e_device = (assigned_device->dev.devfn >> 3) & 0x1f; 4.300 + e_intx = assigned_device->dev.config[0x3d]-1; 4.301 + machine_irq = pci_dev->irq; 4.302 + 4.303 + if ( machine_irq != 0 ) { 4.304 + rc = xc_domain_unbind_pt_irq(xc_handle, domid, machine_irq, PT_IRQ_TYPE_PCI, 0, 4.305 + e_device, e_intx, 0); 4.306 + if ( rc < 0 ) 4.307 + { 4.308 + /* TBD: unregister device in case of an error */ 4.309 + PT_LOG("Error: Unbinding of interrupt failed! rc=%d\n", rc); 4.310 + } 4.311 + } 4.312 + 4.313 + /* unregister real device's MMIO/PIO BARs */ 4.314 + pt_unregister_regions(assigned_device); 4.315 + 4.316 + /* deassign the dev to dom0 */ 4.317 + bdf |= (pci_dev->bus & 0xff) << 16; 4.318 + bdf |= (pci_dev->dev & 0x1f) << 11; 4.319 + bdf |= (pci_dev->func & 0x1f) << 8; 4.320 + if ( (rc = xc_deassign_device(xc_handle, domid, bdf)) != 0) 4.321 + PT_LOG("Error: Revoking the device failed! rc=%d\n", rc); 4.322 + 4.323 + /* mark this slot as free */ 4.324 + php_dev->valid = 0; 4.325 + php_dev->pt_dev = NULL; 4.326 + qemu_free(assigned_device); 4.327 + 4.328 + return 0; 4.329 +} 4.330 + 4.331 +int power_on_php_slot(int php_slot) 4.332 +{ 4.333 + struct php_dev *php_dev = &dpci_infos.php_devs[php_slot]; 4.334 + int pci_slot = php_slot + PHP_SLOT_START; 4.335 + struct pt_dev *pt_dev; 4.336 + pt_dev = 4.337 + register_real_device(dpci_infos.e_bus, 4.338 + "DIRECT PCI", 4.339 + pci_slot << 3, 4.340 + php_dev->r_bus, 4.341 + php_dev->r_dev, 4.342 + php_dev->r_func, 4.343 + PT_MACHINE_IRQ_AUTO, 4.344 + dpci_infos.pci_access); 4.345 + 4.346 + php_dev->pt_dev = pt_dev; 4.347 + 4.348 + return 0; 4.349 + 4.350 +} 4.351 + 4.352 +int power_off_php_slot(int php_slot) 4.353 +{ 4.354 + return unregister_real_device(php_slot); 4.355 +} 4.356 + 4.357 int pt_init(PCIBus *e_bus, char *direct_pci) 4.358 { 4.359 - int seg, b, d, f; 4.360 + int seg, b, d, f, php_slot = 0; 4.361 struct pt_dev *pt_dev; 4.362 struct pci_access *pci_access; 4.363 + char *vslots; 4.364 + char slot_str[8]; 4.365 4.366 /* Initialize libpci */ 4.367 pci_access = pci_alloc(); 4.368 @@ -371,6 +646,19 @@ int pt_init(PCIBus *e_bus, char *direct_ 4.369 pci_init(pci_access); 4.370 pci_scan_bus(pci_access); 4.371 4.372 + memset(&dpci_infos, 0, sizeof(struct dpci_infos)); 4.373 + dpci_infos.pci_access = pci_access; 4.374 + dpci_infos.e_bus = e_bus; 4.375 + 4.376 + if ( strlen(direct_pci) == 0 ) { 4.377 + return 0; 4.378 + } 4.379 + 4.380 + /* the virtual pci slots of all pass-through devs 4.381 + * with hex format: xx;xx...; 4.382 + */ 4.383 + vslots = qemu_mallocz ( strlen(direct_pci) / 3 ); 4.384 + 4.385 /* Assign given devices to guest */ 4.386 while ( next_bdf(&direct_pci, &seg, &b, &d, &f) ) 4.387 { 4.388 @@ -382,8 +670,37 @@ int pt_init(PCIBus *e_bus, char *direct_ 4.389 PT_LOG("Error: Registration failed (%02x:%02x.%x)\n", b, d, f); 4.390 return -1; 4.391 } 4.392 + 4.393 + /* Record the virtual slot info */ 4.394 + if ( php_slot < PHP_SLOT_LEN && 4.395 + dpci_infos.php_devs[php_slot].pt_dev == pt_dev ) 4.396 + { 4.397 + sprintf(slot_str, "0x%x;", PHP_TO_PCI_SLOT(php_slot)); 4.398 + } 4.399 + else 4.400 + sprintf(slot_str, "0x%x;", 0); 4.401 + 4.402 + strcat(vslots, slot_str); 4.403 + php_slot++; 4.404 } 4.405 4.406 + /* Write virtual slots info to xenstore for Control panel use */ 4.407 + xenstore_write_vslots(vslots); 4.408 + 4.409 + qemu_free(vslots); 4.410 + 4.411 /* Success */ 4.412 return 0; 4.413 } 4.414 + 4.415 +void pt_uninit(void) 4.416 +{ 4.417 + struct pci_access *access; 4.418 + 4.419 + /* clean up the libpci */ 4.420 + access = dpci_infos.pci_access; 4.421 + if ( access ) { 4.422 + pci_cleanup(access); 4.423 + } 4.424 + 4.425 +}
5.1 --- a/tools/ioemu/hw/pc.c Fri Feb 15 12:50:55 2008 +0000 5.2 +++ b/tools/ioemu/hw/pc.c Fri Feb 15 14:13:17 2008 +0000 5.3 @@ -945,8 +945,10 @@ static void pc_init1(uint64_t ram_size, 5.4 } 5.5 5.6 #ifdef CONFIG_PASSTHROUGH 5.7 - /* Pass-through Initialization */ 5.8 - if ( pci_enabled && direct_pci ) 5.9 + /* Pass-through Initialization 5.10 + * init libpci even direct_pci is null, as can hotplug a dev runtime 5.11 + */ 5.12 + if ( pci_enabled ) 5.13 { 5.14 rc = pt_init(pci_bus, direct_pci); 5.15 if ( rc < 0 )
6.1 --- a/tools/ioemu/hw/pci.c Fri Feb 15 12:50:55 2008 +0000 6.2 +++ b/tools/ioemu/hw/pci.c Fri Feb 15 14:13:17 2008 +0000 6.3 @@ -107,7 +107,8 @@ PCIDevice *pci_register_device(PCIBus *b 6.4 6.5 if (devfn < 0) { 6.6 for(devfn = bus->devfn_min ; devfn < 256; devfn += 8) { 6.7 - if (!bus->devices[devfn]) 6.8 + if ( !bus->devices[devfn] && 6.9 + !( devfn >= PHP_DEVFN_START && devfn < PHP_DEVFN_END ) ) 6.10 goto found; 6.11 } 6.12 return NULL; 6.13 @@ -132,6 +133,12 @@ PCIDevice *pci_register_device(PCIBus *b 6.14 return pci_dev; 6.15 } 6.16 6.17 +void pci_hide_device(PCIDevice *pci_dev) 6.18 +{ 6.19 + PCIBus *bus = pci_dev->bus; 6.20 + bus->devices[pci_dev->devfn] = NULL; 6.21 +} 6.22 + 6.23 void pci_register_io_region(PCIDevice *pci_dev, int region_num, 6.24 uint32_t size, int type, 6.25 PCIMapIORegionFunc *map_func)
7.1 --- a/tools/ioemu/hw/piix4acpi.c Fri Feb 15 12:50:55 2008 +0000 7.2 +++ b/tools/ioemu/hw/piix4acpi.c Fri Feb 15 14:13:17 2008 +0000 7.3 @@ -24,6 +24,7 @@ 7.4 */ 7.5 7.6 #include "vl.h" 7.7 +#include <xen/hvm/ioreq.h> 7.8 7.9 /* PM1a_CNT bits, as defined in the ACPI specification. */ 7.10 #define SCI_EN (1 << 0) 7.11 @@ -36,6 +37,19 @@ 7.12 #define SLP_TYP_S4 (6 << 10) 7.13 #define SLP_TYP_S5 (7 << 10) 7.14 7.15 +#define ACPI_DBG_IO_ADDR 0xb044 7.16 +#define ACPI_PHP_IO_ADDR 0x10c0 7.17 + 7.18 +#define PHP_EVT_ADD 0x0 7.19 +#define PHP_EVT_REMOVE 0x3 7.20 + 7.21 +#define ACPI_SCI_IRQ 9 7.22 + 7.23 +/* The bit in GPE0_STS/EN to notify the pci hotplug event */ 7.24 +#define ACPI_PHP_GPE_BIT 3 7.25 + 7.26 +#define ACPI_PHP_SLOT_NUM PHP_SLOT_LEN 7.27 + 7.28 typedef struct AcpiDeviceState AcpiDeviceState; 7.29 AcpiDeviceState *acpi_device_table; 7.30 7.31 @@ -44,6 +58,27 @@ typedef struct PCIAcpiState { 7.32 uint16_t pm1_control; /* pm1a_ECNT_BLK */ 7.33 } PCIAcpiState; 7.34 7.35 +typedef struct GPEState { 7.36 + /* GPE0 block */ 7.37 + uint8_t gpe0_sts[ACPI_GPE0_BLK_LEN / 2]; 7.38 + uint8_t gpe0_en[ACPI_GPE0_BLK_LEN / 2]; 7.39 + 7.40 + /* SCI IRQ level */ 7.41 + uint8_t sci_asserted; 7.42 + 7.43 +} GPEState; 7.44 + 7.45 +GPEState gpe_state; 7.46 + 7.47 +typedef struct PHPSlots { 7.48 + struct { 7.49 + uint8_t status; /* Apaptor stats */ 7.50 + } slot[ACPI_PHP_SLOT_NUM]; 7.51 + uint8_t plug_evt; /* slot|event slot:0-no event;1-1st. event:0-remove;1-add */ 7.52 +} PHPSlots; 7.53 + 7.54 +PHPSlots php_slots; 7.55 + 7.56 static void piix4acpi_save(QEMUFile *f, void *opaque) 7.57 { 7.58 PCIAcpiState *s = opaque; 7.59 @@ -142,6 +177,318 @@ static void acpi_map(PCIDevice *pci_dev, 7.60 register_ioport_read(addr + 4, 2, 2, acpiPm1Control_readw, d); 7.61 } 7.62 7.63 +static inline int test_bit(uint8_t *map, int bit) 7.64 +{ 7.65 + return ( map[bit / 8] & (1 << (bit % 8)) ); 7.66 +} 7.67 + 7.68 +static inline void set_bit(uint8_t *map, int bit) 7.69 +{ 7.70 + map[bit / 8] |= (1 << (bit % 8)); 7.71 +} 7.72 + 7.73 +static inline void clear_bit(uint8_t *map, int bit) 7.74 +{ 7.75 + map[bit / 8] &= ~(1 << (bit % 8)); 7.76 +} 7.77 + 7.78 +extern FILE *logfile; 7.79 +static void acpi_dbg_writel(void *opaque, uint32_t addr, uint32_t val) 7.80 +{ 7.81 +#if defined(DEBUG) 7.82 + printf("ACPI: DBG: 0x%08x\n", val); 7.83 +#endif 7.84 + fprintf(logfile, "ACPI:debug: write addr=0x%x, val=0x%x.\n", addr, val); 7.85 +} 7.86 + 7.87 +/* 7.88 + * simple PCI hotplug controller IO 7.89 + * ACPI_PHP_IO_ADDR + : 7.90 + * 0 - the hotplug description: slot(|event(remove/add); 7.91 + * 1 - 1st php slot ctr/sts reg 7.92 + * 2 - 2nd php slot ctr/sts reg 7.93 + * ...... 7.94 + */ 7.95 +static uint32_t acpi_php_readb(void *opaque, uint32_t addr) 7.96 +{ 7.97 + PHPSlots *hotplug_slots = opaque; 7.98 + int num; 7.99 + uint32_t val; 7.100 + 7.101 + switch (addr) 7.102 + { 7.103 + case ACPI_PHP_IO_ADDR: 7.104 + val = hotplug_slots->plug_evt; 7.105 + break; 7.106 + default: 7.107 + num = addr - ACPI_PHP_IO_ADDR - 1; 7.108 + val = hotplug_slots->slot[num].status; 7.109 + } 7.110 + 7.111 + fprintf(logfile, "ACPI PCI hotplug: read addr=0x%x, val=0x%x.\n", addr, val); 7.112 + return val; 7.113 +} 7.114 + 7.115 +static void acpi_php_writeb(void *opaque, uint32_t addr, uint32_t val) 7.116 +{ 7.117 + PHPSlots *hotplug_slots = opaque; 7.118 + int php_slot; 7.119 + fprintf(logfile, "ACPI PCI hotplug: write addr=0x%x, val=0x%x.\n", addr, val); 7.120 + 7.121 + switch (addr) 7.122 + { 7.123 + case ACPI_PHP_IO_ADDR: 7.124 + break; 7.125 + default: 7.126 + php_slot = addr - ACPI_PHP_IO_ADDR - 1; 7.127 + if ( val == 0x1 ) { /* Eject command */ 7.128 + /* make _STA of the slot 0 */ 7.129 + hotplug_slots->slot[php_slot].status = 0; 7.130 + 7.131 + /* clear the hotplug event */ 7.132 + hotplug_slots->plug_evt = 0; 7.133 + 7.134 + /* power off the slot */ 7.135 + power_off_php_slot(php_slot); 7.136 + 7.137 + /* signal the CP ACPI hot remove done. */ 7.138 + xenstore_record_dm_state("pci-removed"); 7.139 + } 7.140 + } 7.141 +} 7.142 + 7.143 +static void pcislots_save(QEMUFile* f, void* opaque) 7.144 +{ 7.145 + PHPSlots *s = (PHPSlots*)opaque; 7.146 + int i; 7.147 + for ( i = 0; i < ACPI_PHP_SLOT_NUM; i++ ) { 7.148 + qemu_put_8s( f, &s->slot[i].status); 7.149 + } 7.150 + qemu_put_8s(f, &s->plug_evt); 7.151 +} 7.152 + 7.153 +static int pcislots_load(QEMUFile* f, void* opaque, int version_id) 7.154 +{ 7.155 + PHPSlots *s = (PHPSlots*)opaque; 7.156 + int i; 7.157 + if (version_id != 1) 7.158 + return -EINVAL; 7.159 + for ( i = 0; i < ACPI_PHP_SLOT_NUM; i++ ) { 7.160 + qemu_get_8s( f, &s->slot[i].status); 7.161 + } 7.162 + qemu_get_8s(f, &s->plug_evt); 7.163 + return 0; 7.164 +} 7.165 + 7.166 +static void php_slots_init(void) 7.167 +{ 7.168 + PHPSlots *slots = &php_slots; 7.169 + int i; 7.170 + memset(slots, 0, sizeof(PHPSlots)); 7.171 + 7.172 + /* update the pci slot status */ 7.173 + for ( i = 0; i < PHP_SLOT_LEN; i++ ) { 7.174 + if ( test_pci_slot( PHP_TO_PCI_SLOT(i) ) == 1 ) 7.175 + slots->slot[i].status = 0xf; 7.176 + } 7.177 + 7.178 + 7.179 + /* ACPI PCI hotplug controller */ 7.180 + register_ioport_read(ACPI_PHP_IO_ADDR, ACPI_PHP_SLOT_NUM + 1, 1, acpi_php_readb, slots); 7.181 + register_ioport_write(ACPI_PHP_IO_ADDR, ACPI_PHP_SLOT_NUM + 1, 1, acpi_php_writeb, slots); 7.182 + register_savevm("pcislots", 0, 1, pcislots_save, pcislots_load, slots); 7.183 +} 7.184 + 7.185 +/* GPEx_STS occupy 1st half of the block, while GPEx_EN 2nd half */ 7.186 +static uint32_t gpe_sts_read(void *opaque, uint32_t addr) 7.187 +{ 7.188 + GPEState *s = opaque; 7.189 + 7.190 + return s->gpe0_sts[addr - ACPI_GPE0_BLK_ADDRESS]; 7.191 +} 7.192 + 7.193 +/* write 1 to clear specific GPE bits */ 7.194 +static void gpe_sts_write(void *opaque, uint32_t addr, uint32_t val) 7.195 +{ 7.196 + GPEState *s = opaque; 7.197 + int hotplugged = 0; 7.198 + 7.199 + fprintf(logfile, "gpe_sts_write: addr=0x%x, val=0x%x.\n", addr, val); 7.200 + 7.201 + hotplugged = test_bit(&s->gpe0_sts[0], ACPI_PHP_GPE_BIT); 7.202 + s->gpe0_sts[addr - ACPI_GPE0_BLK_ADDRESS] &= ~val; 7.203 + if ( s->sci_asserted && 7.204 + hotplugged && 7.205 + !test_bit(&s->gpe0_sts[0], ACPI_PHP_GPE_BIT)) { 7.206 + fprintf(logfile, "Clear the GPE0_STS bit for ACPI hotplug & deassert the IRQ.\n"); 7.207 + pic_set_irq(ACPI_SCI_IRQ, 0); 7.208 + } 7.209 + 7.210 +} 7.211 + 7.212 +static uint32_t gpe_en_read(void *opaque, uint32_t addr) 7.213 +{ 7.214 + GPEState *s = opaque; 7.215 + 7.216 + return s->gpe0_en[addr - (ACPI_GPE0_BLK_ADDRESS + ACPI_GPE0_BLK_LEN / 2)]; 7.217 +} 7.218 + 7.219 +/* write 0 to clear en bit */ 7.220 +static void gpe_en_write(void *opaque, uint32_t addr, uint32_t val) 7.221 +{ 7.222 + GPEState *s = opaque; 7.223 + int reg_count; 7.224 + 7.225 + fprintf(logfile, "gpe_en_write: addr=0x%x, val=0x%x.\n", addr, val); 7.226 + reg_count = addr - (ACPI_GPE0_BLK_ADDRESS + ACPI_GPE0_BLK_LEN / 2); 7.227 + s->gpe0_en[reg_count] = val; 7.228 + /* If disable GPE bit right after generating SCI on it, 7.229 + * need deassert the intr to avoid redundant intrs 7.230 + */ 7.231 + if ( s->sci_asserted && 7.232 + reg_count == (ACPI_PHP_GPE_BIT / 8) && 7.233 + !(val & (1 << (ACPI_PHP_GPE_BIT % 8))) ) { 7.234 + fprintf(logfile, "deassert due to disable GPE bit.\n"); 7.235 + s->sci_asserted = 0; 7.236 + pic_set_irq(ACPI_SCI_IRQ, 0); 7.237 + } 7.238 + 7.239 +} 7.240 + 7.241 +static void gpe_save(QEMUFile* f, void* opaque) 7.242 +{ 7.243 + GPEState *s = (GPEState*)opaque; 7.244 + int i; 7.245 + 7.246 + for ( i = 0; i < ACPI_GPE0_BLK_LEN / 2; i++ ) { 7.247 + qemu_put_8s(f, &s->gpe0_sts[i]); 7.248 + qemu_put_8s(f, &s->gpe0_en[i]); 7.249 + } 7.250 + 7.251 + qemu_put_8s(f, &s->sci_asserted); 7.252 + if ( s->sci_asserted ) { 7.253 + fprintf(logfile, "gpe_save with sci asserted!\n"); 7.254 + } 7.255 +} 7.256 + 7.257 +static int gpe_load(QEMUFile* f, void* opaque, int version_id) 7.258 +{ 7.259 + GPEState *s = (GPEState*)opaque; 7.260 + int i; 7.261 + if (version_id != 1) 7.262 + return -EINVAL; 7.263 + 7.264 + for ( i = 0; i < ACPI_GPE0_BLK_LEN / 2; i++ ) { 7.265 + qemu_get_8s(f, &s->gpe0_sts[i]); 7.266 + qemu_get_8s(f, &s->gpe0_en[i]); 7.267 + } 7.268 + 7.269 + qemu_get_8s(f, &s->sci_asserted); 7.270 + return 0; 7.271 +} 7.272 + 7.273 +static void gpe_acpi_init(void) 7.274 +{ 7.275 + GPEState *s = &gpe_state; 7.276 + memset(s, 0, sizeof(GPEState)); 7.277 + 7.278 + register_ioport_read(ACPI_GPE0_BLK_ADDRESS, 7.279 + ACPI_GPE0_BLK_LEN / 2, 7.280 + 1, 7.281 + gpe_sts_read, 7.282 + s); 7.283 + register_ioport_read(ACPI_GPE0_BLK_ADDRESS + ACPI_GPE0_BLK_LEN / 2, 7.284 + ACPI_GPE0_BLK_LEN / 2, 7.285 + 1, 7.286 + gpe_en_read, 7.287 + s); 7.288 + 7.289 + register_ioport_write(ACPI_GPE0_BLK_ADDRESS, 7.290 + ACPI_GPE0_BLK_LEN / 2, 7.291 + 1, 7.292 + gpe_sts_write, 7.293 + s); 7.294 + register_ioport_write(ACPI_GPE0_BLK_ADDRESS + ACPI_GPE0_BLK_LEN / 2, 7.295 + ACPI_GPE0_BLK_LEN / 2, 7.296 + 1, 7.297 + gpe_en_write, 7.298 + s); 7.299 + 7.300 + register_savevm("gpe", 0, 1, gpe_save, gpe_load, s); 7.301 +} 7.302 + 7.303 +static void acpi_sci_intr(GPEState *s) 7.304 +{ 7.305 + if ( !test_bit(&s->gpe0_sts[0], ACPI_PHP_GPE_BIT) && 7.306 + test_bit(&s->gpe0_en[0], ACPI_PHP_GPE_BIT) ) { 7.307 + 7.308 + set_bit(&s->gpe0_sts[0], ACPI_PHP_GPE_BIT); 7.309 + s->sci_asserted = 1; 7.310 + pic_set_irq(ACPI_SCI_IRQ, 1); 7.311 + fprintf(logfile, "generate a sci for PHP.\n"); 7.312 + } 7.313 +} 7.314 + 7.315 +void acpi_php_del(int pci_slot) 7.316 +{ 7.317 + GPEState *s = &gpe_state; 7.318 + PHPSlots *hotplug_slots = &php_slots; 7.319 + int php_slot = PCI_TO_PHP_SLOT(pci_slot); 7.320 + 7.321 + if ( pci_slot < PHP_SLOT_START || pci_slot >= PHP_SLOT_END ) { 7.322 + fprintf(logfile, "not find the pci slot %d when hot remove.\n", pci_slot); 7.323 + 7.324 + return; 7.325 + } 7.326 + 7.327 + /* update the php controller status */ 7.328 + hotplug_slots->plug_evt = (((php_slot+1) << 4) | PHP_EVT_REMOVE); 7.329 + 7.330 + /* generate a SCI interrupt */ 7.331 + acpi_sci_intr(s); 7.332 +} 7.333 + 7.334 +void acpi_php_add(int pci_slot) 7.335 +{ 7.336 + GPEState *s = &gpe_state; 7.337 + PHPSlots *hotplug_slots = &php_slots; 7.338 + int php_slot = PCI_TO_PHP_SLOT(pci_slot); 7.339 + char ret_str[30]; 7.340 + 7.341 + if ( pci_slot < PHP_SLOT_START || pci_slot >= PHP_SLOT_END ) { 7.342 + fprintf(logfile, "hot add pci slot %d exceed.\n", pci_slot); 7.343 + 7.344 + if ( pci_slot == 0 ) 7.345 + sprintf(ret_str, "no free hotplug slots"); 7.346 + else if ( pci_slot == -1 ) 7.347 + sprintf(ret_str, "wrong bdf or vslot"); 7.348 + 7.349 + if ( strlen(ret_str) > 0 ) 7.350 + xenstore_record_dm("parameter", ret_str); 7.351 + 7.352 + return; 7.353 + } 7.354 + 7.355 + /* update the php controller status */ 7.356 + hotplug_slots->plug_evt = (((php_slot+1) << 4) | PHP_EVT_ADD); 7.357 + 7.358 + /* update the slot status as present */ 7.359 + hotplug_slots->slot[php_slot].status = 0xf; 7.360 + 7.361 + /* power on the slot */ 7.362 + power_on_php_slot(php_slot); 7.363 + 7.364 + /* tell Control panel which slot for the new pass-throgh dev */ 7.365 + sprintf(ret_str, "0x%x", pci_slot); 7.366 + xenstore_record_dm("parameter", ret_str); 7.367 + 7.368 + /* signal the CP ACPI hot insert done */ 7.369 + xenstore_record_dm_state("pci-inserted"); 7.370 + 7.371 + /* generate a SCI interrupt */ 7.372 + acpi_sci_intr(s); 7.373 +} 7.374 + 7.375 /* PIIX4 acpi pci configuration space, func 2 */ 7.376 void pci_piix4_acpi_init(PCIBus *bus, int devfn) 7.377 { 7.378 @@ -181,5 +528,12 @@ void pci_piix4_acpi_init(PCIBus *bus, in 7.379 7.380 acpi_map((PCIDevice *)d, 0, 0x1f40, 0x10, PCI_ADDRESS_SPACE_IO); 7.381 7.382 + gpe_acpi_init(); 7.383 + 7.384 + php_slots_init(); 7.385 + 7.386 + /* for ACPI debug */ 7.387 + register_ioport_write(ACPI_DBG_IO_ADDR, 4, 4, acpi_dbg_writel, d); 7.388 + 7.389 register_savevm("piix4acpi", 0, 1, piix4acpi_save, piix4acpi_load, d); 7.390 }
8.1 --- a/tools/ioemu/monitor.c Fri Feb 15 12:50:55 2008 +0000 8.2 +++ b/tools/ioemu/monitor.c Fri Feb 15 14:13:17 2008 +0000 8.3 @@ -1280,6 +1280,12 @@ static term_cmd_t term_cmds[] = { 8.4 "device", "add USB device (e.g. 'host:bus.addr' or 'host:vendor_id:product_id')" }, 8.5 { "usb_del", "s", do_usb_del, 8.6 "device", "remove USB device 'bus.addr'" }, 8.7 +#ifdef CONFIG_PHP_DEBUG 8.8 + { "pci_add", "s", do_pci_add, 8.9 + "device", "insert PCI pass-through device by BDF,e.g. (dom, bus, dev, func) by hex '0x0, 0x3, 0x0, 0x0'" }, 8.10 + { "pci_del", "s", do_pci_del, 8.11 + "device", "remove PCI pass-through device by BDF,e.g. (dom, bus, dev, func) by hex '0x0, 0x3, 0x0, 0x0'" }, 8.12 +#endif 8.13 #ifndef CONFIG_DM 8.14 { "cpu", "i", do_cpu_set, 8.15 "index", "set the default CPU" },
9.1 --- a/tools/ioemu/vl.c Fri Feb 15 12:50:55 2008 +0000 9.2 +++ b/tools/ioemu/vl.c Fri Feb 15 14:13:17 2008 +0000 9.3 @@ -4382,6 +4382,24 @@ void usb_info(void) 9.4 } 9.5 } 9.6 9.7 +void do_pci_del(char *devname) 9.8 +{ 9.9 + int pci_slot; 9.10 + pci_slot = bdf_to_slot(devname); 9.11 + 9.12 + acpi_php_del(pci_slot); 9.13 +} 9.14 + 9.15 +void do_pci_add(char *devname) 9.16 +{ 9.17 + int pci_slot; 9.18 + 9.19 + pci_slot = insert_to_pci_slot(devname); 9.20 + 9.21 + acpi_php_add(pci_slot); 9.22 +} 9.23 + 9.24 + 9.25 /***********************************************************/ 9.26 /* pid file */ 9.27 9.28 @@ -7067,7 +7085,7 @@ int main(int argc, char **argv) 9.29 #endif 9.30 sigset_t set; 9.31 char qemu_dm_logfilename[128]; 9.32 - const char *direct_pci = NULL; 9.33 + const char *direct_pci = direct_pci_str; 9.34 9.35 #if !defined(__sun__) && !defined(CONFIG_STUBDOM) 9.36 /* Maximise rlimits. Needed where default constraints are tight (*BSD). */ 9.37 @@ -7590,9 +7608,6 @@ int main(int argc, char **argv) 9.38 case QEMU_OPTION_vncunused: 9.39 vncunused++; 9.40 break; 9.41 - case QEMU_OPTION_pci: 9.42 - direct_pci = optarg; 9.43 - break; 9.44 } 9.45 } 9.46 } 9.47 @@ -7970,5 +7985,6 @@ int main(int argc, char **argv) 9.48 9.49 main_loop(); 9.50 quit_timers(); 9.51 + pt_uninit(); 9.52 return 0; 9.53 }
10.1 --- a/tools/ioemu/vl.h Fri Feb 15 12:50:55 2008 +0000 10.2 +++ b/tools/ioemu/vl.h Fri Feb 15 14:13:17 2008 +0000 10.3 @@ -817,11 +817,15 @@ struct PCIDevice { 10.4 int irq_state[4]; 10.5 }; 10.6 10.7 +extern char direct_pci_str[]; 10.8 + 10.9 PCIDevice *pci_register_device(PCIBus *bus, const char *name, 10.10 int instance_size, int devfn, 10.11 PCIConfigReadFunc *config_read, 10.12 PCIConfigWriteFunc *config_write); 10.13 10.14 +void pci_hide_device(PCIDevice *pci_dev); 10.15 + 10.16 void pci_register_io_region(PCIDevice *pci_dev, int region_num, 10.17 uint32_t size, int type, 10.18 PCIMapIORegionFunc *map_func); 10.19 @@ -850,6 +854,22 @@ void pci_info(void); 10.20 PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint32_t id, 10.21 pci_map_irq_fn map_irq, const char *name); 10.22 10.23 +/* PCI slot 6~7 support ACPI PCI hot plug */ 10.24 +#define PHP_SLOT_START (6) 10.25 +#define PHP_SLOT_END (8) 10.26 +#define PHP_SLOT_LEN (PHP_SLOT_END - PHP_SLOT_START) 10.27 +#define PHP_TO_PCI_SLOT(x) (x + PHP_SLOT_START) 10.28 +#define PCI_TO_PHP_SLOT(x) (x - PHP_SLOT_START) 10.29 +#define PHP_DEVFN_START (PHP_SLOT_START << 3) 10.30 +#define PHP_DEVFN_END (PHP_SLOT_END << 3) 10.31 + 10.32 +int insert_to_pci_slot(char*); 10.33 +int test_pci_slot(int); 10.34 +int bdf_to_slot(char*); 10.35 +int power_on_php_slot(int); 10.36 +int power_off_php_slot(int); 10.37 +void pt_uninit(void); 10.38 + 10.39 /* prep_pci.c */ 10.40 PCIBus *pci_prep_init(void); 10.41 10.42 @@ -1120,6 +1140,9 @@ void tpm_tis_init(SetIRQFunc *set_irq, v 10.43 10.44 /* piix4acpi.c */ 10.45 extern void pci_piix4_acpi_init(PCIBus *bus, int devfn); 10.46 +void acpi_php_add(int); 10.47 +void acpi_php_del(int); 10.48 + 10.49 10.50 /* pc.c */ 10.51 extern QEMUMachine pc_machine; 10.52 @@ -1320,6 +1343,9 @@ void do_usb_add(const char *devname); 10.53 void do_usb_del(const char *devname); 10.54 void usb_info(void); 10.55 10.56 +void do_pci_add(char *devname); 10.57 +void do_pci_del(char *devname); 10.58 + 10.59 /* scsi-disk.c */ 10.60 enum scsi_reason { 10.61 SCSI_REASON_DONE, /* Command complete. */ 10.62 @@ -1466,10 +1492,12 @@ void readline_start(const char *prompt, 10.63 void xenstore_parse_domain_config(int domid); 10.64 int xenstore_fd(void); 10.65 void xenstore_process_event(void *opaque); 10.66 +void xenstore_record_dm(char *subpath, char *state); 10.67 void xenstore_record_dm_state(char *state); 10.68 void xenstore_check_new_media_present(int timeout); 10.69 void xenstore_write_vncport(int vnc_display); 10.70 void xenstore_read_vncpasswd(int domid, char *pwbuf, size_t pwbuflen); 10.71 +void xenstore_write_vslots(char *vslots); 10.72 10.73 int xenstore_domain_has_devtype(struct xs_handle *handle, 10.74 const char *devtype);
11.1 --- a/tools/ioemu/xenstore.c Fri Feb 15 12:50:55 2008 +0000 11.2 +++ b/tools/ioemu/xenstore.c Fri Feb 15 14:13:17 2008 +0000 11.3 @@ -79,6 +79,8 @@ static void waitForDevice(char *fn) 11.4 return; 11.5 } 11.6 11.7 +#define DIRECT_PCI_STR_LEN 160 11.8 +char direct_pci_str[DIRECT_PCI_STR_LEN]; 11.9 void xenstore_parse_domain_config(int domid) 11.10 { 11.11 char **e = NULL; 11.12 @@ -86,7 +88,7 @@ void xenstore_parse_domain_config(int do 11.13 char *fpath = NULL, *bpath = NULL, 11.14 *dev = NULL, *params = NULL, *type = NULL, *drv = NULL; 11.15 int i, is_scsi, is_hdN = 0; 11.16 - unsigned int len, num, hd_index; 11.17 + unsigned int len, num, hd_index, pci_devid = 0; 11.18 BlockDriverState *bs; 11.19 11.20 for(i = 0; i < MAX_DISKS + MAX_SCSI_DISKS; i++) 11.21 @@ -250,6 +252,38 @@ void xenstore_parse_domain_config(int do 11.22 fprintf(logfile, "Watching %s\n", buf); 11.23 } 11.24 11.25 + /* get the pci pass-through parameter */ 11.26 + if (pasprintf(&buf, "/local/domain/0/backend/pci/%u/%u/num_devs", 11.27 + domid, pci_devid) == -1) 11.28 + goto out; 11.29 + 11.30 + free(params); 11.31 + params = xs_read(xsh, XBT_NULL, buf, &len); 11.32 + if (params == NULL) 11.33 + goto out; 11.34 + num = atoi(params); 11.35 + 11.36 + for ( i = 0; i < num; i++ ) { 11.37 + if (pasprintf(&buf, "/local/domain/0/backend/pci/%u/%u/dev-%d", 11.38 + domid, pci_devid, i) != -1) { 11.39 + free(dev); 11.40 + dev = xs_read(xsh, XBT_NULL, buf, &len); 11.41 + 11.42 + if ( strlen(dev) + strlen(direct_pci_str) > DIRECT_PCI_STR_LEN ) { 11.43 + fprintf(stderr, "qemu: too many pci pass-through devices\n"); 11.44 + memset(direct_pci_str, 0, DIRECT_PCI_STR_LEN); 11.45 + goto out; 11.46 + } 11.47 + 11.48 + /* append to direct_pci_str */ 11.49 + if ( dev ) { 11.50 + strcat(direct_pci_str, dev); 11.51 + strcat(direct_pci_str, "-"); 11.52 + } 11.53 + } 11.54 + } 11.55 + 11.56 + 11.57 out: 11.58 free(type); 11.59 free(params); 11.60 @@ -388,7 +422,7 @@ void xenstore_process_logdirty_event(voi 11.61 /* Accept state change commands from the control tools */ 11.62 static void xenstore_process_dm_command_event(void) 11.63 { 11.64 - char *path = NULL, *command = NULL; 11.65 + char *path = NULL, *command = NULL, *par = NULL; 11.66 unsigned int len; 11.67 extern int suspend_requested; 11.68 11.69 @@ -407,6 +441,34 @@ static void xenstore_process_dm_command_ 11.70 } else if (!strncmp(command, "continue", len)) { 11.71 fprintf(logfile, "dm-command: continue after state save\n"); 11.72 suspend_requested = 0; 11.73 + } else if (!strncmp(command, "pci-rem", len)) { 11.74 + fprintf(logfile, "dm-command: hot remove pass-through pci dev \n"); 11.75 + 11.76 + if (pasprintf(&path, 11.77 + "/local/domain/0/device-model/%u/parameter", domid) == -1) { 11.78 + fprintf(logfile, "out of memory reading dm command parameter\n"); 11.79 + goto out; 11.80 + } 11.81 + par = xs_read(xsh, XBT_NULL, path, &len); 11.82 + if (!par) 11.83 + goto out; 11.84 + 11.85 + do_pci_del(par); 11.86 + free(par); 11.87 + } else if (!strncmp(command, "pci-ins", len)) { 11.88 + fprintf(logfile, "dm-command: hot insert pass-through pci dev \n"); 11.89 + 11.90 + if (pasprintf(&path, 11.91 + "/local/domain/0/device-model/%u/parameter", domid) == -1) { 11.92 + fprintf(logfile, "out of memory reading dm command parameter\n"); 11.93 + goto out; 11.94 + } 11.95 + par = xs_read(xsh, XBT_NULL, path, &len); 11.96 + if (!par) 11.97 + goto out; 11.98 + 11.99 + do_pci_add(par); 11.100 + free(par); 11.101 } else { 11.102 fprintf(logfile, "dm-command: unknown command\"%*s\"\n", len, command); 11.103 } 11.104 @@ -416,22 +478,27 @@ static void xenstore_process_dm_command_ 11.105 free(command); 11.106 } 11.107 11.108 -void xenstore_record_dm_state(char *state) 11.109 +void xenstore_record_dm(char *subpath, char *state) 11.110 { 11.111 char *path = NULL; 11.112 11.113 if (pasprintf(&path, 11.114 - "/local/domain/0/device-model/%u/state", domid) == -1) { 11.115 - fprintf(logfile, "out of memory recording dm state\n"); 11.116 + "/local/domain/0/device-model/%u/%s", domid, subpath) == -1) { 11.117 + fprintf(logfile, "out of memory recording dm \n"); 11.118 goto out; 11.119 } 11.120 if (!xs_write(xsh, XBT_NULL, path, state, strlen(state))) 11.121 - fprintf(logfile, "error recording dm state\n"); 11.122 + fprintf(logfile, "error recording dm \n"); 11.123 11.124 out: 11.125 free(path); 11.126 } 11.127 11.128 +void xenstore_record_dm_state(char *state) 11.129 +{ 11.130 + xenstore_record_dm("state", state); 11.131 +} 11.132 + 11.133 void xenstore_process_event(void *opaque) 11.134 { 11.135 char **vec, *offset, *bpath = NULL, *buf = NULL, *drv = NULL, *image = NULL; 11.136 @@ -522,6 +589,23 @@ void xenstore_write_vncport(int display) 11.137 free(buf); 11.138 } 11.139 11.140 +void xenstore_write_vslots(char *vslots) 11.141 +{ 11.142 + char *path = NULL; 11.143 + int pci_devid = 0; 11.144 + 11.145 + if (pasprintf(&path, 11.146 + "/local/domain/0/backend/pci/%u/%u/vslots", domid, pci_devid) == -1) { 11.147 + fprintf(logfile, "out of memory when updating vslots.\n"); 11.148 + goto out; 11.149 + } 11.150 + if (!xs_write(xsh, XBT_NULL, path, vslots, strlen(vslots))) 11.151 + fprintf(logfile, "error updating vslots \n"); 11.152 + 11.153 + out: 11.154 + free(path); 11.155 +} 11.156 + 11.157 void xenstore_read_vncpasswd(int domid, char *pwbuf, size_t pwbuflen) 11.158 { 11.159 char *buf = NULL, *path, *uuid = NULL, *passwd = NULL;
12.1 --- a/tools/libxc/xc_domain.c Fri Feb 15 12:50:55 2008 +0000 12.2 +++ b/tools/libxc/xc_domain.c Fri Feb 15 14:13:17 2008 +0000 12.3 @@ -762,6 +762,20 @@ int xc_test_assign_device( 12.4 return do_domctl(xc_handle, &domctl); 12.5 } 12.6 12.7 +int xc_deassign_device( 12.8 + int xc_handle, 12.9 + uint32_t domid, 12.10 + uint32_t machine_bdf) 12.11 +{ 12.12 + DECLARE_DOMCTL; 12.13 + 12.14 + domctl.cmd = XEN_DOMCTL_deassign_device; 12.15 + domctl.domain = domid; 12.16 + domctl.u.assign_device.machine_bdf = machine_bdf; 12.17 + 12.18 + return do_domctl(xc_handle, &domctl); 12.19 +} 12.20 + 12.21 /* Pass-through: binds machine irq to guests irq */ 12.22 int xc_domain_bind_pt_irq( 12.23 int xc_handle, 12.24 @@ -797,6 +811,36 @@ int xc_domain_bind_pt_irq( 12.25 return rc; 12.26 } 12.27 12.28 +int xc_domain_unbind_pt_irq( 12.29 + int xc_handle, 12.30 + uint32_t domid, 12.31 + uint8_t machine_irq, 12.32 + uint8_t irq_type, 12.33 + uint8_t bus, 12.34 + uint8_t device, 12.35 + uint8_t intx, 12.36 + uint8_t isa_irq) 12.37 +{ 12.38 + int rc; 12.39 + xen_domctl_bind_pt_irq_t * bind; 12.40 + DECLARE_DOMCTL; 12.41 + 12.42 + domctl.cmd = XEN_DOMCTL_unbind_pt_irq; 12.43 + domctl.domain = (domid_t)domid; 12.44 + 12.45 + bind = &(domctl.u.bind_pt_irq); 12.46 + bind->hvm_domid = domid; 12.47 + bind->irq_type = irq_type; 12.48 + bind->machine_irq = machine_irq; 12.49 + bind->u.pci.bus = bus; 12.50 + bind->u.pci.device = device; 12.51 + bind->u.pci.intx = intx; 12.52 + bind->u.isa.isa_irq = isa_irq; 12.53 + 12.54 + rc = do_domctl(xc_handle, &domctl); 12.55 + return rc; 12.56 +} 12.57 + 12.58 int xc_domain_bind_pt_pci_irq( 12.59 int xc_handle, 12.60 uint32_t domid,
13.1 --- a/tools/libxc/xenctrl.h Fri Feb 15 12:50:55 2008 +0000 13.2 +++ b/tools/libxc/xenctrl.h Fri Feb 15 14:13:17 2008 +0000 13.3 @@ -914,6 +914,10 @@ int xc_test_assign_device(int xc_handle, 13.4 uint32_t domid, 13.5 uint32_t machine_bdf); 13.6 13.7 +int xc_deassign_device(int xc_handle, 13.8 + uint32_t domid, 13.9 + uint32_t machine_bdf); 13.10 + 13.11 int xc_domain_memory_mapping(int xc_handle, 13.12 uint32_t domid, 13.13 unsigned long first_gfn, 13.14 @@ -937,6 +941,15 @@ int xc_domain_bind_pt_irq(int xc_handle, 13.15 uint8_t intx, 13.16 uint8_t isa_irq); 13.17 13.18 +int xc_domain_unbind_pt_irq(int xc_handle, 13.19 + uint32_t domid, 13.20 + uint8_t machine_irq, 13.21 + uint8_t irq_type, 13.22 + uint8_t bus, 13.23 + uint8_t device, 13.24 + uint8_t intx, 13.25 + uint8_t isa_irq); 13.26 + 13.27 int xc_domain_bind_pt_pci_irq(int xc_handle, 13.28 uint32_t domid, 13.29 uint8_t machine_irq,
14.1 --- a/tools/python/xen/xend/XendDomainInfo.py Fri Feb 15 12:50:55 2008 +0000 14.2 +++ b/tools/python/xen/xend/XendDomainInfo.py Fri Feb 15 14:13:17 2008 +0000 14.3 @@ -516,6 +516,131 @@ class XendDomainInfo: 14.4 asserts.isCharConvertible(key) 14.5 self.storeDom("control/sysrq", '%c' % key) 14.6 14.7 + def sync_pcidev_info(self): 14.8 + 14.9 + if not self.info.is_hvm(): 14.10 + return 14.11 + 14.12 + devid = '0' 14.13 + dev_info = self._getDeviceInfo_pci(devid) 14.14 + if dev_info is None: 14.15 + return 14.16 + 14.17 + # get the virtual slot info from xenstore 14.18 + dev_uuid = sxp.child_value(dev_info, 'uuid') 14.19 + pci_conf = self.info['devices'][dev_uuid][1] 14.20 + pci_devs = pci_conf['devs'] 14.21 + 14.22 + count = 0 14.23 + vslots = None 14.24 + while vslots is None and count < 20: 14.25 + vslots = xstransact.Read("/local/domain/0/backend/pci/%u/%s/vslots" 14.26 + % (self.getDomid(), devid)) 14.27 + time.sleep(0.1) 14.28 + count += 1 14.29 + if vslots is None: 14.30 + log.error("Device model didn't tell the vslots for PCI device") 14.31 + return 14.32 + 14.33 + #delete last delim 14.34 + if vslots[-1] == ";": 14.35 + vslots = vslots[:-1] 14.36 + 14.37 + slot_list = vslots.split(';') 14.38 + if len(slot_list) != len(pci_devs): 14.39 + log.error("Device model's pci dev num dismatch") 14.40 + return 14.41 + 14.42 + #update the vslot info 14.43 + count = 0; 14.44 + for x in pci_devs: 14.45 + x['vslt'] = slot_list[count] 14.46 + count += 1 14.47 + 14.48 + 14.49 + def pci_device_create(self, dev_config): 14.50 + log.debug("XendDomainInfo.pci_device_create: %s" % scrub_password(dev_config)) 14.51 + 14.52 + if not self.info.is_hvm(): 14.53 + raise VmError("only HVM guest support pci attach") 14.54 + 14.55 + #all the PCI devs share one conf node 14.56 + devid = '0' 14.57 + 14.58 + dev_type = sxp.name(dev_config) 14.59 + new_devs = sxp.child_value(dev_config, 'devs') 14.60 + new_dev = new_devs[0] 14.61 + dev_info = self._getDeviceInfo_pci(devid)#from self.info['devices'] 14.62 + 14.63 + #check conflict before trigger hotplug event 14.64 + if dev_info is not None: 14.65 + dev_uuid = sxp.child_value(dev_info, 'uuid') 14.66 + pci_conf = self.info['devices'][dev_uuid][1] 14.67 + pci_devs = pci_conf['devs'] 14.68 + for x in pci_devs: 14.69 + if (int(x['vslt'], 16) == int(new_dev['vslt'], 16) and 14.70 + int(x['vslt'], 16) != 0 ): 14.71 + raise VmError("vslot %s already have a device." % (new_dev['vslt'])) 14.72 + 14.73 + if (int(x['domain'], 16) == int(new_dev['domain'], 16) and 14.74 + int(x['bus'], 16) == int(new_dev['bus'], 16) and 14.75 + int(x['slot'], 16) == int(new_dev['slot'], 16) and 14.76 + int(x['func'], 16) == int(new_dev['func'], 16) ): 14.77 + raise VmError("device is already inserted") 14.78 + 14.79 + # Test whether the devices can be assigned with VT-d 14.80 + pci_str = "%s, %s, %s, %s" % (new_dev['domain'], 14.81 + new_dev['bus'], 14.82 + new_dev['slot'], 14.83 + new_dev['func']) 14.84 + bdf = xc.test_assign_device(self.domid, pci_str) 14.85 + if bdf != 0: 14.86 + bus = (bdf >> 16) & 0xff 14.87 + devfn = (bdf >> 8) & 0xff 14.88 + dev = (devfn >> 3) & 0x1f 14.89 + func = devfn & 0x7 14.90 + raise VmError("Fail to hot insert device(%x:%x.%x): maybe VT-d is " 14.91 + "not enabled, or the device is not exist, or it " 14.92 + "has already been assigned to other domain" 14.93 + % (bus, dev, func)) 14.94 + 14.95 + bdf_str = "%s:%s:%s.%s@%s" % (new_dev['domain'], 14.96 + new_dev['bus'], 14.97 + new_dev['slot'], 14.98 + new_dev['func'], 14.99 + new_dev['vslt']) 14.100 + self.image.signalDeviceModel('pci-ins', 'pci-inserted', bdf_str) 14.101 + 14.102 + # update the virtual pci slot 14.103 + vslt = xstransact.Read("/local/domain/0/device-model/%i/parameter" 14.104 + % self.getDomid()) 14.105 + new_dev['vslt'] = vslt 14.106 + 14.107 + if dev_info is None: 14.108 + # create a new one from scrach 14.109 + dev_cfg_sxp = [dev_type, 14.110 + ['dev', 14.111 + ['domain', new_dev['domain']], 14.112 + ['bus', new_dev['bus']], 14.113 + ['slot', new_dev['slot']], 14.114 + ['func', new_dev['func']], 14.115 + ['vslt', new_dev['vslt']] 14.116 + ]] 14.117 + dev_uuid = self.info.device_add(dev_type, cfg_sxp = dev_cfg_sxp) 14.118 + dev_config_dict = self.info['devices'][dev_uuid][1] 14.119 + try: 14.120 + dev_config_dict['devid'] = devid = \ 14.121 + self._createDevice(dev_type, dev_config_dict) 14.122 + self._waitForDevice(dev_type, devid) 14.123 + except VmError, ex: 14.124 + raise ex 14.125 + else: 14.126 + # update the pci config to add the new dev 14.127 + pci_devs.extend(new_devs) 14.128 + self._reconfigureDevice('pci', devid, pci_conf) 14.129 + 14.130 + return self.getDeviceController('pci').sxpr(devid) 14.131 + 14.132 def device_create(self, dev_config): 14.133 """Create a new device. 14.134 14.135 @@ -524,6 +649,11 @@ class XendDomainInfo: 14.136 """ 14.137 log.debug("XendDomainInfo.device_create: %s" % scrub_password(dev_config)) 14.138 dev_type = sxp.name(dev_config) 14.139 + 14.140 + if dev_type == 'pci': 14.141 + rc = self.pci_device_create(dev_config) 14.142 + return rc 14.143 + 14.144 dev_uuid = self.info.device_add(dev_type, cfg_sxp = dev_config) 14.145 dev_config_dict = self.info['devices'][dev_uuid][1] 14.146 log.debug("XendDomainInfo.device_create: %s" % scrub_password(dev_config_dict)) 14.147 @@ -584,10 +714,65 @@ class XendDomainInfo: 14.148 for devclass in XendDevices.valid_devices(): 14.149 self.getDeviceController(devclass).waitForDevices() 14.150 14.151 + def destroyPCIDevice(self, vslot): 14.152 + log.debug("destroyPCIDevice called %s", vslot) 14.153 + 14.154 + if not self.info.is_hvm(): 14.155 + raise VmError("only HVM guest support pci detach") 14.156 + 14.157 + #all the PCI devs share one conf node 14.158 + devid = '0' 14.159 + vslot = int(vslot) 14.160 + dev_info = self._getDeviceInfo_pci('0')#from self.info['devices'] 14.161 + dev_uuid = sxp.child_value(dev_info, 'uuid') 14.162 + 14.163 + #delete the pci bdf config under the pci device 14.164 + pci_conf = self.info['devices'][dev_uuid][1] 14.165 + pci_len = len(pci_conf['devs']) 14.166 + 14.167 + #find the pass-through device with the virtual slot 14.168 + devnum = 0 14.169 + for x in pci_conf['devs']: 14.170 + if int(x['vslt'], 16) == vslot: 14.171 + break 14.172 + devnum += 1 14.173 + 14.174 + if devnum >= pci_len: 14.175 + raise VmError("Device @ vslot 0x%x doesn't exist." % (vslot)) 14.176 + 14.177 + if vslot == 0: 14.178 + raise VmError("Device @ vslot 0x%x do not support hotplug." % (vslot)) 14.179 + 14.180 + bdf_str = "%s:%s:%s.%s" % (x['domain'], x['bus'], x['slot'], x['func']) 14.181 + log.info("destroyPCIDevice:%s:%s!", x, bdf_str) 14.182 + 14.183 + self.image.signalDeviceModel('pci-rem', 'pci-removed', bdf_str) 14.184 + 14.185 + if pci_len > 1: 14.186 + del pci_conf['devs'][devnum] 14.187 + self._reconfigureDevice('pci', devid, pci_conf) 14.188 + else: 14.189 + self.getDeviceController('pci').destroyDevice(devid, True) 14.190 + del self.info['devices'][dev_uuid] 14.191 + platform = self.info['platform'] 14.192 + orig_dev_num = len(platform['pci']) 14.193 + 14.194 + #need remove the pci config 14.195 + #TODO:can use this to keep some info to ask high level management tools to hot insert a new passthrough dev after migration 14.196 + if orig_dev_num != 0: 14.197 +# platform['pci'] = ["%dDEVs" % orig_dev_num] 14.198 + platform['pci'] = [] 14.199 + 14.200 + return 0 14.201 + 14.202 def destroyDevice(self, deviceClass, devid, force = False, rm_cfg = False): 14.203 log.debug("XendDomainInfo.destroyDevice: deviceClass = %s, device = %s", 14.204 deviceClass, devid) 14.205 14.206 + if deviceClass == 'dpci': 14.207 + rc = self.destroyPCIDevice(devid) 14.208 + return rc 14.209 + 14.210 if rm_cfg: 14.211 # Convert devid to device number. A device number is 14.212 # needed to remove its configuration. 14.213 @@ -647,6 +832,14 @@ class XendDomainInfo: 14.214 return rc 14.215 14.216 def getDeviceSxprs(self, deviceClass): 14.217 + if deviceClass == 'pci': 14.218 + dev_info = self._getDeviceInfo_pci('0')#from self.info['devices'] 14.219 + if dev_info is None: 14.220 + return [] 14.221 + dev_uuid = sxp.child_value(dev_info, 'uuid') 14.222 + pci_devs = self.info['devices'][dev_uuid][1]['devs'] 14.223 + pci_len = len(pci_devs) 14.224 + return pci_devs 14.225 if self._stateGet() in (DOM_STATE_RUNNING, DOM_STATE_PAUSED, DOM_STATE_CRASHED): 14.226 return self.getDeviceController(deviceClass).sxprs() 14.227 else: 14.228 @@ -683,6 +876,12 @@ class XendDomainInfo: 14.229 if devid == dev: 14.230 return dev_info 14.231 14.232 + def _getDeviceInfo_pci(self, devid): 14.233 + for dev_type, dev_info in self.info.all_devices_sxpr(): 14.234 + if dev_type != 'pci': 14.235 + continue 14.236 + return dev_info 14.237 + return None 14.238 14.239 def setMemoryTarget(self, target): 14.240 """Set the memory target of this domain. 14.241 @@ -1543,6 +1742,9 @@ class XendDomainInfo: 14.242 if self.image: 14.243 self.image.createDeviceModel() 14.244 14.245 + #if have pass-through devs, need the virtual pci slots info from qemu 14.246 + self.sync_pcidev_info() 14.247 + 14.248 def _releaseDevices(self, suspend = False): 14.249 """Release all domain's devices. Nothrow guarantee.""" 14.250 if self.image:
15.1 --- a/tools/python/xen/xend/image.py Fri Feb 15 12:50:55 2008 +0000 15.2 +++ b/tools/python/xen/xend/image.py Fri Feb 15 14:13:17 2008 +0000 15.3 @@ -300,23 +300,42 @@ class ImageHandler: 15.4 self.vm.storeDom("image/device-model-pid", self.pid) 15.5 log.info("device model pid: %d", self.pid) 15.6 15.7 - def saveDeviceModel(self): 15.8 + def signalDeviceModel(self, cmd, ret, par = None): 15.9 if self.device_model is None: 15.10 return 15.11 - # Signal the device model to pause itself and save its state 15.12 + # Signal the device model to for action 15.13 + if cmd is '' or ret is '': 15.14 + raise VmError('need valid command and result when signal device model') 15.15 + 15.16 + orig_state = xstransact.Read("/local/domain/0/device-model/%i/state" 15.17 + % self.vm.getDomid()) 15.18 + 15.19 + if par is not None: 15.20 + xstransact.Store("/local/domain/0/device-model/%i" 15.21 + % self.vm.getDomid(), ('parameter', par)) 15.22 + 15.23 xstransact.Store("/local/domain/0/device-model/%i" 15.24 - % self.vm.getDomid(), ('command', 'save')) 15.25 + % self.vm.getDomid(), ('command', cmd)) 15.26 # Wait for confirmation. Could do this with a watch but we'd 15.27 # still end up spinning here waiting for the watch to fire. 15.28 state = '' 15.29 count = 0 15.30 - while state != 'paused': 15.31 + while state != ret: 15.32 state = xstransact.Read("/local/domain/0/device-model/%i/state" 15.33 % self.vm.getDomid()) 15.34 time.sleep(0.1) 15.35 count += 1 15.36 if count > 100: 15.37 - raise VmError('Timed out waiting for device model to save') 15.38 + raise VmError('Timed out waiting for device model action') 15.39 + 15.40 + #resotre orig state 15.41 + xstransact.Store("/local/domain/0/device-model/%i" 15.42 + % self.vm.getDomid(), ('state', orig_state)) 15.43 + log.info("signalDeviceModel:restore dm state to %s", orig_state) 15.44 + 15.45 + def saveDeviceModel(self): 15.46 + # Signal the device model to pause itself and save its state 15.47 + self.signalDeviceModel('save', 'paused') 15.48 15.49 def resumeDeviceModel(self): 15.50 if self.device_model is None: 15.51 @@ -479,7 +498,7 @@ class HVMImageHandler(ImageHandler): 15.52 15.53 dmargs = [ 'boot', 'fda', 'fdb', 'soundhw', 15.54 'localtime', 'serial', 'stdvga', 'isa', 15.55 - 'acpi', 'usb', 'usbdevice', 'pci' ] 15.56 + 'acpi', 'usb', 'usbdevice' ] 15.57 15.58 for a in dmargs: 15.59 v = vmConfig['platform'].get(a)
16.1 --- a/tools/python/xen/xend/server/DevController.py Fri Feb 15 12:50:55 2008 +0000 16.2 +++ b/tools/python/xen/xend/server/DevController.py Fri Feb 15 14:13:17 2008 +0000 16.3 @@ -412,6 +412,14 @@ class DevController: 16.4 return result 16.5 16.6 16.7 + def removeBackend(self, devid, *args): 16.8 + frontpath = self.frontendPath(devid) 16.9 + backpath = xstransact.Read(frontpath, "backend") 16.10 + if backpath: 16.11 + return xstransact.Remove(backpath, *args) 16.12 + else: 16.13 + raise VmError("Device %s not connected" % devid) 16.14 + 16.15 def readBackend(self, devid, *args): 16.16 frontpath = self.frontendPath(devid) 16.17 backpath = xstransact.Read(frontpath, "backend")
17.1 --- a/tools/python/xen/xend/server/pciif.py Fri Feb 15 12:50:55 2008 +0000 17.2 +++ b/tools/python/xen/xend/server/pciif.py Fri Feb 15 14:13:17 2008 +0000 17.3 @@ -18,6 +18,7 @@ 17.4 17.5 17.6 import types 17.7 +import time 17.8 17.9 from xen.xend import sxp 17.10 from xen.xend.XendError import VmError 17.11 @@ -62,25 +63,62 @@ class PciController(DevController): 17.12 17.13 back = {} 17.14 pcidevid = 0 17.15 + vslots = "" 17.16 for pci_config in config.get('devs', []): 17.17 domain = parse_hex(pci_config.get('domain', 0)) 17.18 bus = parse_hex(pci_config.get('bus', 0)) 17.19 slot = parse_hex(pci_config.get('slot', 0)) 17.20 func = parse_hex(pci_config.get('func', 0)) 17.21 + 17.22 + vslt = pci_config.get('vslt') 17.23 + if vslt is not None: 17.24 + vslots = vslots + vslt + ";" 17.25 + 17.26 self.setupDevice(domain, bus, slot, func) 17.27 back['dev-%i' % pcidevid] = "%04x:%02x:%02x.%02x" % \ 17.28 (domain, bus, slot, func) 17.29 pcidevid += 1 17.30 17.31 + if vslots != "": 17.32 + back['vslots'] = vslots 17.33 + 17.34 back['num_devs']=str(pcidevid) 17.35 back['uuid'] = config.get('uuid','') 17.36 return (0, back, {}) 17.37 17.38 + def reconfigureDevice(self, _, config): 17.39 + """@see DevController.reconfigureDevice""" 17.40 + #currently only support config changes by hot insert/remove pass-through dev 17.41 + #delete all the devices in xenstore 17.42 + (devid, new_back, new_front) = self.getDeviceDetails(config) 17.43 + num_devs = self.readBackend(devid, 'num_devs') 17.44 + for i in range(int(num_devs)): 17.45 + self.removeBackend(devid, 'dev-%d' % i) 17.46 + self.removeBackend(devid, 'num_devs') 17.47 + 17.48 + #create new devices config 17.49 + num_devs = new_back['num_devs'] 17.50 + for i in range(int(num_devs)): 17.51 + dev_no = 'dev-%d' % i 17.52 + self.writeBackend(devid, dev_no, new_back[dev_no]) 17.53 + self.writeBackend(devid, 'num_devs', num_devs) 17.54 + 17.55 + if new_back['vslots'] is not None: 17.56 + self.writeBackend(devid, 'vslots', new_back['vslots']) 17.57 + 17.58 + return new_back.get('uuid') 17.59 + 17.60 def getDeviceConfiguration(self, devid, transaction = None): 17.61 result = DevController.getDeviceConfiguration(self, devid, transaction) 17.62 num_devs = self.readBackend(devid, 'num_devs') 17.63 pci_devs = [] 17.64 17.65 + vslots = self.readBackend(devid, 'vslots') 17.66 + if vslots is not None: 17.67 + if vslots[-1] == ";": 17.68 + vslots = vslots[:-1] 17.69 + slot_list = vslots.split(';') 17.70 + 17.71 for i in range(int(num_devs)): 17.72 dev_config = self.readBackend(devid, 'dev-%d' % i) 17.73 17.74 @@ -91,10 +129,16 @@ class PciController(DevController): 17.75 17.76 if pci_match!=None: 17.77 pci_dev_info = pci_match.groupdict() 17.78 - pci_devs.append({'domain': '0x%(domain)s' % pci_dev_info, 17.79 + dev_dict = {'domain': '0x%(domain)s' % pci_dev_info, 17.80 'bus': '0x%(bus)s' % pci_dev_info, 17.81 'slot': '0x%(slot)s' % pci_dev_info, 17.82 - 'func': '0x%(func)s' % pci_dev_info}) 17.83 + 'func': '0x%(func)s' % pci_dev_info} 17.84 + 17.85 + #append vslot info 17.86 + if vslots is not None: 17.87 + dev_dict['vslt'] = slot_list[i] 17.88 + 17.89 + pci_devs.append(dev_dict) 17.90 17.91 result['devs'] = pci_devs 17.92 result['uuid'] = self.readBackend(devid, 'uuid')
18.1 --- a/tools/python/xen/xm/main.py Fri Feb 15 12:50:55 2008 +0000 18.2 +++ b/tools/python/xen/xm/main.py Fri Feb 15 14:13:17 2008 +0000 18.3 @@ -175,6 +175,12 @@ SUBCOMMAND_HELP = { 18.4 'vnet-delete' : ('<VnetId>', 'Delete a Vnet.'), 18.5 'vnet-list' : ('[-l|--long]', 'List Vnets.'), 18.6 'vtpm-list' : ('<Domain> [--long]', 'List virtual TPM devices.'), 18.7 + 'pci-attach ' : ('<Domain> <dom> <bus> <slot> <func> [virtual slot]', 18.8 + 'Insert a new pass-through pci device.'), 18.9 + 'pci-detach ' : ('<Domain> <virtual slot>', 18.10 + 'Remove a domain\'s pass-through pci device.'), 18.11 + 'pci-list' : ('<Domain>', 18.12 + 'List pass-through pci devices for a domain.'), 18.13 18.14 # security 18.15 18.16 @@ -335,6 +341,9 @@ device_commands = [ 18.17 "network-detach", 18.18 "network-list", 18.19 "vtpm-list", 18.20 + "pci-attach", 18.21 + "pci-detach", 18.22 + "pci-list", 18.23 ] 18.24 18.25 vnet_commands = [ 18.26 @@ -2051,6 +2060,31 @@ def xm_vtpm_list(args): 18.27 % ni) 18.28 18.29 18.30 +def xm_pci_list(args): 18.31 + (use_long, params) = arg_check_for_resource_list(args, "pci-list") 18.32 + 18.33 + dom = params[0] 18.34 + 18.35 + devs = server.xend.domain.getDeviceSxprs(dom, 'pci') 18.36 + 18.37 + if len(devs) == 0: 18.38 + return 18.39 + 18.40 + has_vslt = devs[0].has_key('vslt') 18.41 + if has_vslt: 18.42 + hdr_str = 'VSlt domain bus slot func' 18.43 + fmt_str = "%(vslt)-3s %(domain)-3s %(bus)-3s %(slot)-3s %(func)-3s " 18.44 + else: 18.45 + hdr_str = 'domain bus slot func' 18.46 + fmt_str = "%(domain)-3s %(bus)-3s %(slot)-3s %(func)-3s " 18.47 + hdr = 0 18.48 + 18.49 + for x in devs: 18.50 + if hdr == 0: 18.51 + print (hdr_str) 18.52 + hdr = 1 18.53 + print ( fmt_str % x ) 18.54 + 18.55 def parse_block_configuration(args): 18.56 dom = args[0] 18.57 18.58 @@ -2198,6 +2232,29 @@ def xm_network_attach(args): 18.59 vif.append(vif_param) 18.60 server.xend.domain.device_create(dom, vif) 18.61 18.62 +def parse_pci_configuration(args): 18.63 + dom = args[0] 18.64 + 18.65 + if len(args) == 6: 18.66 + vslt = args[5] 18.67 + else: 18.68 + vslt = '0x0' #chose a free virtual PCI slot 18.69 + 18.70 + pci = ['pci', 18.71 + ['devs', 18.72 + [{'domain': "0x%x" % int(args[1], 16), 18.73 + 'bus': "0x%x" % int(args[2], 16), 18.74 + 'slot': "0x%x" % int(args[3], 16), 18.75 + 'func': "0x%x" % int(args[4], 16), 18.76 + 'vslt': "0x%x" % int(vslt, 16)}] 18.77 + ]] 18.78 + 18.79 + return (dom, pci) 18.80 + 18.81 +def xm_pci_attach(args): 18.82 + arg_check(args, 'xm_pci_attach', 5, 6) 18.83 + (dom, pci) = parse_pci_configuration(args) 18.84 + server.xend.domain.device_create(dom, pci) 18.85 18.86 def detach(args, deviceClass): 18.87 rm_cfg = True 18.88 @@ -2263,6 +2320,12 @@ def xm_network_detach(args): 18.89 detach(args, 'vif') 18.90 18.91 18.92 +def xm_pci_detach(args): 18.93 + arg_check(args, 'xm_pci_detach', 2, 2) 18.94 + dom = args[0] 18.95 + dev = args[1] 18.96 + server.xend.domain.destroyDevice(dom, 'dpci', dev) 18.97 + 18.98 def xm_vnet_list(args): 18.99 xenapi_unsupported() 18.100 try: 18.101 @@ -2452,6 +2515,10 @@ commands = { 18.102 "vnet-delete": xm_vnet_delete, 18.103 # vtpm 18.104 "vtpm-list": xm_vtpm_list, 18.105 + #pci 18.106 + "pci-attach": xm_pci_attach, 18.107 + "pci-detach": xm_pci_detach, 18.108 + "pci-list": xm_pci_list, 18.109 } 18.110 18.111 ## The commands supported by a separate argument parser in xend.xm.
19.1 --- a/xen/arch/x86/domctl.c Fri Feb 15 12:50:55 2008 +0000 19.2 +++ b/xen/arch/x86/domctl.c Fri Feb 15 14:13:17 2008 +0000 19.3 @@ -580,6 +580,34 @@ long arch_do_domctl( 19.4 } 19.5 break; 19.6 19.7 + case XEN_DOMCTL_deassign_device: 19.8 + { 19.9 + struct domain *d; 19.10 + u8 bus, devfn; 19.11 + 19.12 + ret = -EINVAL; 19.13 + if ( !iommu_enabled ) 19.14 + break; 19.15 + 19.16 + if ( unlikely((d = get_domain_by_id(domctl->domain)) == NULL) ) 19.17 + { 19.18 + gdprintk(XENLOG_ERR, 19.19 + "XEN_DOMCTL_deassign_device: get_domain_by_id() failed\n"); 19.20 + break; 19.21 + } 19.22 + bus = (domctl->u.assign_device.machine_bdf >> 16) & 0xff; 19.23 + devfn = (domctl->u.assign_device.machine_bdf >> 8) & 0xff; 19.24 + 19.25 + if ( !device_assigned(bus, devfn) ) 19.26 + break; 19.27 + 19.28 + reassign_device_ownership(d, dom0, bus, devfn); 19.29 + gdprintk(XENLOG_INFO, "XEN_DOMCTL_deassign_device: bdf = %x:%x:%x\n", 19.30 + bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); 19.31 + put_domain(d); 19.32 + } 19.33 + break; 19.34 + 19.35 case XEN_DOMCTL_bind_pt_irq: 19.36 { 19.37 struct domain * d; 19.38 @@ -595,6 +623,23 @@ long arch_do_domctl( 19.39 gdprintk(XENLOG_ERR, "pt_irq_create_bind failed!\n"); 19.40 rcu_unlock_domain(d); 19.41 } 19.42 + break; 19.43 + 19.44 + case XEN_DOMCTL_unbind_pt_irq: 19.45 + { 19.46 + struct domain * d; 19.47 + xen_domctl_bind_pt_irq_t * bind; 19.48 + 19.49 + ret = -ESRCH; 19.50 + if ( (d = rcu_lock_domain_by_id(domctl->domain)) == NULL ) 19.51 + break; 19.52 + bind = &(domctl->u.bind_pt_irq); 19.53 + if ( iommu_enabled ) 19.54 + ret = pt_irq_destroy_bind_vtd(d, bind); 19.55 + if ( ret < 0 ) 19.56 + gdprintk(XENLOG_ERR, "pt_irq_destroy_bind failed!\n"); 19.57 + rcu_unlock_domain(d); 19.58 + } 19.59 break; 19.60 19.61 case XEN_DOMCTL_memory_mapping:
20.1 --- a/xen/arch/x86/hvm/irq.c Fri Feb 15 12:50:55 2008 +0000 20.2 +++ b/xen/arch/x86/hvm/irq.c Fri Feb 15 14:13:17 2008 +0000 20.3 @@ -211,8 +211,7 @@ void hvm_set_pci_link_route(struct domai 20.4 clear_bit(old_isa_irq, &hvm_irq->dpci->isairq_map); 20.5 20.6 for ( i = 0; i < NR_LINK; i++ ) 20.7 - if ( test_bit(i, &hvm_irq->dpci->link_map) && 20.8 - hvm_irq->pci_link.route[i] ) 20.9 + if ( hvm_irq->dpci->link_cnt[i] && hvm_irq->pci_link.route[i] ) 20.10 set_bit(hvm_irq->pci_link.route[i], 20.11 &hvm_irq->dpci->isairq_map); 20.12 }
21.1 --- a/xen/arch/x86/hvm/vmx/vtd/intel-iommu.c Fri Feb 15 12:50:55 2008 +0000 21.2 +++ b/xen/arch/x86/hvm/vmx/vtd/intel-iommu.c Fri Feb 15 14:13:17 2008 +0000 21.3 @@ -1441,6 +1441,8 @@ void reassign_device_ownership( 21.4 bus, PCI_SLOT(devfn), PCI_FUNC(devfn), 21.5 source->domain_id, target->domain_id); 21.6 21.7 + pdev_flr(bus, devfn); 21.8 + 21.9 for_each_pdev( source, pdev ) 21.10 { 21.11 if ( (pdev->bus != bus) || (pdev->devfn != devfn) ) 21.12 @@ -1476,7 +1478,6 @@ void return_devices_to_dom0(struct domai 21.13 dprintk(XENLOG_INFO VTDPREFIX, 21.14 "return_devices_to_dom0: bdf = %x:%x:%x\n", 21.15 pdev->bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); 21.16 - pdev_flr(pdev->bus, pdev->devfn); 21.17 reassign_device_ownership(d, dom0, pdev->bus, pdev->devfn); 21.18 } 21.19 21.20 @@ -1941,7 +1942,6 @@ int intel_iommu_assign_device(struct dom 21.21 "assign_device: bus = %x dev = %x func = %x\n", 21.22 bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); 21.23 21.24 - pdev_flr(bus, devfn); 21.25 reassign_device_ownership(dom0, d, bus, devfn); 21.26 21.27 /* Setup rmrr identify mapping */
22.1 --- a/xen/arch/x86/hvm/vmx/vtd/io.c Fri Feb 15 12:50:55 2008 +0000 22.2 +++ b/xen/arch/x86/hvm/vmx/vtd/io.c Fri Feb 15 14:13:17 2008 +0000 22.3 @@ -101,7 +101,7 @@ int pt_irq_create_bind_vtd( 22.4 intx = pt_irq_bind->u.pci.intx; 22.5 guest_gsi = hvm_pci_intx_gsi(device, intx); 22.6 link = hvm_pci_intx_link(device, intx); 22.7 - set_bit(link, hvm_irq_dpci->link_map); 22.8 + hvm_irq_dpci->link_cnt[link]++; 22.9 22.10 digl = xmalloc(struct dev_intx_gsi_link); 22.11 if ( !digl ) 22.12 @@ -137,6 +137,65 @@ int pt_irq_create_bind_vtd( 22.13 return 0; 22.14 } 22.15 22.16 +int pt_irq_destroy_bind_vtd( 22.17 + struct domain *d, xen_domctl_bind_pt_irq_t *pt_irq_bind) 22.18 +{ 22.19 + struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci; 22.20 + uint32_t machine_gsi, guest_gsi; 22.21 + uint32_t device, intx, link; 22.22 + struct list_head *digl_list, *tmp; 22.23 + struct dev_intx_gsi_link *digl; 22.24 + 22.25 + if ( hvm_irq_dpci == NULL ) 22.26 + return 0; 22.27 + 22.28 + machine_gsi = pt_irq_bind->machine_irq; 22.29 + device = pt_irq_bind->u.pci.device; 22.30 + intx = pt_irq_bind->u.pci.intx; 22.31 + guest_gsi = hvm_pci_intx_gsi(device, intx); 22.32 + link = hvm_pci_intx_link(device, intx); 22.33 + hvm_irq_dpci->link_cnt[link]--; 22.34 + 22.35 + gdprintk(XENLOG_INFO, 22.36 + "pt_irq_destroy_bind_vtd: machine_gsi=%d, guest_gsi=%d, device=%d, intx=%d.\n", 22.37 + machine_gsi, guest_gsi, device, intx); 22.38 + memset(&hvm_irq_dpci->girq[guest_gsi], 0, sizeof(struct hvm_girq_dpci_mapping)); 22.39 + 22.40 + /* clear the mirq info */ 22.41 + if ( hvm_irq_dpci->mirq[machine_gsi].valid ) 22.42 + { 22.43 + 22.44 + list_for_each_safe ( digl_list, tmp, 22.45 + &hvm_irq_dpci->mirq[machine_gsi].digl_list ) 22.46 + { 22.47 + digl = list_entry(digl_list, 22.48 + struct dev_intx_gsi_link, list); 22.49 + if ( digl->device == device && 22.50 + digl->intx == intx && 22.51 + digl->link == link && 22.52 + digl->gsi == guest_gsi ) 22.53 + { 22.54 + list_del(&digl->list); 22.55 + xfree(digl); 22.56 + } 22.57 + } 22.58 + 22.59 + if ( list_empty(&hvm_irq_dpci->mirq[machine_gsi].digl_list) ) 22.60 + { 22.61 + pirq_guest_unbind(d, machine_gsi); 22.62 + kill_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(machine_gsi)]); 22.63 + hvm_irq_dpci->mirq[machine_gsi].dom = NULL; 22.64 + hvm_irq_dpci->mirq[machine_gsi].valid = 0; 22.65 + } 22.66 + } 22.67 + 22.68 + gdprintk(XENLOG_INFO, 22.69 + "XEN_DOMCTL_irq_unmapping: m_irq = %x device = %x intx = %x\n", 22.70 + machine_gsi, device, intx); 22.71 + 22.72 + return 0; 22.73 +} 22.74 + 22.75 int hvm_do_IRQ_dpci(struct domain *d, unsigned int mirq) 22.76 { 22.77 struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
23.1 --- a/xen/include/asm-x86/hvm/irq.h Fri Feb 15 12:50:55 2008 +0000 23.2 +++ b/xen/include/asm-x86/hvm/irq.h Fri Feb 15 14:13:17 2008 +0000 23.3 @@ -64,7 +64,7 @@ struct hvm_irq_dpci { 23.4 /* Record of mapped ISA IRQs */ 23.5 DECLARE_BITMAP(isairq_map, NR_ISAIRQS); 23.6 /* Record of mapped Links */ 23.7 - DECLARE_BITMAP(link_map, NR_LINK); 23.8 + uint8_t link_cnt[NR_LINK]; 23.9 struct timer hvm_timer[NR_IRQS]; 23.10 }; 23.11
24.1 --- a/xen/include/asm-x86/iommu.h Fri Feb 15 12:50:55 2008 +0000 24.2 +++ b/xen/include/asm-x86/iommu.h Fri Feb 15 14:13:17 2008 +0000 24.3 @@ -74,6 +74,9 @@ int iommu_domain_init(struct domain *d); 24.4 void iommu_domain_destroy(struct domain *d); 24.5 int device_assigned(u8 bus, u8 devfn); 24.6 int assign_device(struct domain *d, u8 bus, u8 devfn); 24.7 +void reassign_device_ownership(struct domain *source, 24.8 + struct domain *target, 24.9 + u8 bus, u8 devfn); 24.10 int iommu_map_page(struct domain *d, unsigned long gfn, unsigned long mfn); 24.11 int iommu_unmap_page(struct domain *d, unsigned long gfn); 24.12 void iommu_flush(struct domain *d, unsigned long gfn, u64 *p2m_entry); 24.13 @@ -83,6 +86,8 @@ int hvm_do_IRQ_dpci(struct domain *d, un 24.14 int dpci_ioport_intercept(ioreq_t *p); 24.15 int pt_irq_create_bind_vtd(struct domain *d, 24.16 xen_domctl_bind_pt_irq_t *pt_irq_bind); 24.17 +int pt_irq_destroy_bind_vtd(struct domain *d, 24.18 + xen_domctl_bind_pt_irq_t *pt_irq_bind); 24.19 unsigned int io_apic_read_remap_rte( 24.20 unsigned int apic, unsigned int reg); 24.21 void io_apic_write_remap_rte(unsigned int apic,
25.1 --- a/xen/include/public/domctl.h Fri Feb 15 12:50:55 2008 +0000 25.2 +++ b/xen/include/public/domctl.h Fri Feb 15 14:13:17 2008 +0000 25.3 @@ -439,6 +439,7 @@ DEFINE_XEN_GUEST_HANDLE(xen_domctl_sendt 25.4 /* Assign PCI device to HVM guest. Sets up IOMMU structures. */ 25.5 #define XEN_DOMCTL_assign_device 37 25.6 #define XEN_DOMCTL_test_assign_device 45 25.7 +#define XEN_DOMCTL_deassign_device 47 25.8 struct xen_domctl_assign_device { 25.9 uint32_t machine_bdf; /* machine PCI ID of assigned device */ 25.10 }; 25.11 @@ -448,6 +449,7 @@ DEFINE_XEN_GUEST_HANDLE(xen_domctl_assig 25.12 25.13 /* Pass-through interrupts: bind real irq -> hvm devfn. */ 25.14 #define XEN_DOMCTL_bind_pt_irq 38 25.15 +#define XEN_DOMCTL_unbind_pt_irq 48 25.16 typedef enum pt_irq_type_e { 25.17 PT_IRQ_TYPE_PCI, 25.18 PT_IRQ_TYPE_ISA
26.1 --- a/xen/include/public/hvm/ioreq.h Fri Feb 15 12:50:55 2008 +0000 26.2 +++ b/xen/include/public/hvm/ioreq.h Fri Feb 15 14:13:17 2008 +0000 26.3 @@ -118,6 +118,11 @@ struct buffered_piopage { 26.4 #define ACPI_PM1A_EVT_BLK_ADDRESS 0x0000000000001f40 26.5 #define ACPI_PM1A_CNT_BLK_ADDRESS (ACPI_PM1A_EVT_BLK_ADDRESS + 0x04) 26.6 #define ACPI_PM_TMR_BLK_ADDRESS (ACPI_PM1A_EVT_BLK_ADDRESS + 0x08) 26.7 + 26.8 +#define ACPI_GPE0_BLK_ADDRESS (ACPI_PM_TMR_BLK_ADDRESS + 0x20) 26.9 + 26.10 +#define ACPI_GPE0_BLK_LEN 0x08 26.11 + 26.12 #endif /* defined(__i386__) || defined(__x86_64__) */ 26.13 26.14 #endif /* _IOREQ_H_ */