[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [RFC PATCH 06/12] hvmloader: add basic Q35 support



On Mon, 19 Mar 2018 15:30:14 +0000
Roger Pau Monné <roger.pau@xxxxxxxxxx> wrote:

>On Tue, Mar 13, 2018 at 04:33:51AM +1000, Alexey Gerasimenko wrote:
>> This patch does following:
>> 
>> 1. Move PCI-device specific initialization out of pci_setup function
>> to the newly created class_specific_pci_device_setup function to
>> simplify code.
>> 
>> 2. PCI-device specific initialization extended with LPC controller
>> initialization
>> 
>> 3. Initialize PIRQA...{PIRQD, PIRQH} routing accordingly to the
>> emulated south bridge (either located on PCI_ISA_DEVFN or
>> PCI_ICH9_LPC_DEVFN).
>> 
>> Signed-off-by: Alexey Gerasimenko <x1917x@xxxxxxxxx>
>> ---
>>  tools/firmware/hvmloader/config.h |   1 +
>>  tools/firmware/hvmloader/pci.c    | 162
>> ++++++++++++++++++++++++-------------- 2 files changed, 104
>> insertions(+), 59 deletions(-)
>> 
>> diff --git a/tools/firmware/hvmloader/config.h
>> b/tools/firmware/hvmloader/config.h index 6e00413f2e..6fde6b7b60
>> 100644 --- a/tools/firmware/hvmloader/config.h
>> +++ b/tools/firmware/hvmloader/config.h
>> @@ -52,6 +52,7 @@ extern uint8_t ioapic_version;
>>  
>>  #define PCI_ISA_DEVFN       0x08    /* dev 1, fn 0 */
>>  #define PCI_ISA_IRQ_MASK    0x0c20U /* ISA IRQs 5,10,11 are PCI
>> connected */ +#define PCI_ICH9_LPC_DEVFN  0xf8    /* dev 31, fn 0 */
>>  
>>  /* MMIO hole: Hardcoded defaults, which can be dynamically
>> expanded. */ #define PCI_MEM_END         0xfc000000
>> diff --git a/tools/firmware/hvmloader/pci.c
>> b/tools/firmware/hvmloader/pci.c index 0b708bf578..033bd20992 100644
>> --- a/tools/firmware/hvmloader/pci.c
>> +++ b/tools/firmware/hvmloader/pci.c
>> @@ -35,6 +35,7 @@ unsigned long pci_mem_end = PCI_MEM_END;
>>  uint64_t pci_hi_mem_start = 0, pci_hi_mem_end = 0;
>>  
>>  enum virtual_vga virtual_vga = VGA_none;
>> +uint32_t vga_devfn = 256;  
>
>uint8_t should be enough to store a devfn. Also this should be static
>maybe?

Yep, forgot 'static'. Changing uint32_t to uint8_t here will require
to change the
'    if ( vga_devfn != 256 )' condition as well -- it's a bit out of the
patch scope, probably a separate tiny patch would be better.

>>  unsigned long igd_opregion_pgbase = 0;
>>  
>>  /* Check if the specified range conflicts with any reserved device
>> memory. */ @@ -76,14 +77,93 @@ static int find_next_rmrr(uint32_t
>> base) return next_rmrr;
>>  }
>>  
>> +#define SCI_EN_IOPORT  (ACPI_PM1A_EVT_BLK_ADDRESS_V1 + 0x30)
>> +#define GBL_SMI_EN      (1 << 0)
>> +#define APMC_EN         (1 << 5)  
>
>Alignment.

Will correct.

>> +
>> +static void class_specific_pci_device_setup(uint16_t vendor_id,
>> +                                            uint16_t device_id,
>> +                                            uint8_t bus, uint8_t
>> devfn) +{
>> +    uint16_t class;
>> +
>> +    class = pci_readw(devfn, PCI_CLASS_DEVICE);
>> +
>> +    switch ( class )  
>
>switch ( pci_readw(devfn, PCI_CLASS_DEVICE) ) ?
>
>I don't see class being used elsewhere.

>Also why is vendor_id/device_id provided by the caller but not class?
>It seems kind of pointless.

'class' is not used by pci_setup(), thus moved to
class_specific_pci_device_setup().

pci_readw(devfn, PCI_CLASS_DEVICE) inside the switch condition to drop
the variable -- sure, agree.

Passing vendor_id/device_id pair via function args allows to avoid
reading the vendor_id/device_id from PCI conf twice -- a bit less
garbage in the polluted PCI setup debuglog. It's not a big problem
really, so this can be changed to passing only BDF to
class_specific_pci_device_setup().

>Why not fetch vendor/device from the function itself and move the
>(vendor_id == 0xffff) && (device_id == 0xffff) check inside the
>function?

Hmm, this is a part of the PCI bus enumeration, not PCI device setup.

>Also in this case I think it would be better to have a non-functional
>patch that introduces class_specific_pci_device_setup and a second
>patch that adds support for ICH9.
>
>Having code movement and new code in the same patch makes it harder to
>very what you are actually moving vs introducing.

Agree, will split this actions to separate patches for the next version.

>> +    {
>> +    case 0x0300:  
>
>All this values need to be defines documented somewhere.

Agree... although it was not me who introduced all these hardcoded PCI
class values. :) I'll change these numbers into newly added pci_regs.h
#defines in the non-functional patch.

>> +        /* If emulated VGA is found, preserve it as primary VGA. */
>> +        if ( (vendor_id == 0x1234) && (device_id == 0x1111) )
>> +        {
>> +            vga_devfn = devfn;
>> +            virtual_vga = VGA_std;
>> +        }
>> +        else if ( (vendor_id == 0x1013) && (device_id == 0xb8) )
>> +        {
>> +            vga_devfn = devfn;
>> +            virtual_vga = VGA_cirrus;
>> +        }
>> +        else if ( virtual_vga == VGA_none )
>> +        {
>> +            vga_devfn = devfn;
>> +            virtual_vga = VGA_pt;
>> +            if ( vendor_id == 0x8086 )
>> +            {
>> +                igd_opregion_pgbase =
>> mem_hole_alloc(IGD_OPREGION_PAGES);
>> +                /*
>> +                 * Write the the OpRegion offset to give the
>> opregion
>> +                 * address to the device model. The device model
>> will trap
>> +                 * and map the OpRegion at the give address.
>> +                 */
>> +                pci_writel(vga_devfn, PCI_INTEL_OPREGION,
>> +                           igd_opregion_pgbase << PAGE_SHIFT);
>> +            }
>> +        }
>> +        break;
>> +
>> +    case 0x0680:
>> +        /* PIIX4 ACPI PM. Special device with special PCI config
>> space. */
>> +        ASSERT((vendor_id == 0x8086) && (device_id == 0x7113));
>> +        pci_writew(devfn, 0x20, 0x0000); /* No smb bus IO enable */
>> +        pci_writew(devfn, 0xd2, 0x0000); /* No smb bus IO enable */
>> +        pci_writew(devfn, 0x22, 0x0000);
>> +        pci_writew(devfn, 0x3c, 0x0009); /* Hardcoded IRQ9 */
>> +        pci_writew(devfn, 0x3d, 0x0001);
>> +        pci_writel(devfn, 0x40, ACPI_PM1A_EVT_BLK_ADDRESS_V1 | 1);
>> +        pci_writeb(devfn, 0x80, 0x01); /* enable PM io space */
>> +        break;
>> +
>> +    case 0x0601:
>> +        /* LPC bridge */
>> +        if (vendor_id == 0x8086 && device_id == 0x2918)
>> +        {
>> +            pci_writeb(devfn, 0x3c, 0x09); /* Hardcoded IRQ9 */
>> +            pci_writeb(devfn, 0x3d, 0x01);
>> +            pci_writel(devfn, 0x40, ACPI_PM1A_EVT_BLK_ADDRESS_V1 |
>> 1);
>> +            pci_writeb(devfn, 0x44, 0x80); /* enable PM io space */
>> +            outl(SCI_EN_IOPORT, inl(SCI_EN_IOPORT) | GBL_SMI_EN |
>> APMC_EN);
>> +        }
>> +        break;
>> +
>> +    case 0x0101:
>> +        if ( vendor_id == 0x8086 )
>> +        {
>> +            /* Intel ICHs since PIIX3: enable IDE legacy mode. */
>> +            pci_writew(devfn, 0x40, 0x8000); /* enable IDE0 */
>> +            pci_writew(devfn, 0x42, 0x8000); /* enable IDE1 */
>> +        }
>> +        break;
>> +    }
>> +}
>> +
>>  void pci_setup(void)
>>  {
>>      uint8_t is_64bar, using_64bar, bar64_relocate = 0;
>>      uint32_t devfn, bar_reg, cmd, bar_data, bar_data_upper;
>>      uint64_t base, bar_sz, bar_sz_upper, mmio_total = 0;
>> -    uint32_t vga_devfn = 256;
>> -    uint16_t class, vendor_id, device_id;
>> +    uint16_t vendor_id, device_id;
>>      unsigned int bar, pin, link, isa_irq;
>> +    int is_running_on_q35 = 0;  
>
>bool is_running_on_q35 = (get_pc_machine_type() == MACHINE_TYPE_Q35);

OK

>>  
>>      /* Resources assignable to PCI devices via BARs. */
>>      struct resource {
>> @@ -130,13 +210,28 @@ void pci_setup(void)
>>      if ( s )
>>          mmio_hole_size = strtoll(s, NULL, 0);
>>  
>> +    /* check if we are on Q35 and set the flag if it is the case */
>> +    is_running_on_q35 = get_pc_machine_type() == MACHINE_TYPE_Q35;
>> +
>>      /* Program PCI-ISA bridge with appropriate link routes. */
>>      isa_irq = 0;
>>      for ( link = 0; link < 4; link++ )
>>      {
>>          do { isa_irq = (isa_irq + 1) & 15;
>>          } while ( !(PCI_ISA_IRQ_MASK & (1U << isa_irq)) );
>> -        pci_writeb(PCI_ISA_DEVFN, 0x60 + link, isa_irq);
>> +
>> +        if (is_running_on_q35)  
>
>Coding style.

OK

>> +        {
>> +            pci_writeb(PCI_ICH9_LPC_DEVFN, 0x60 + link, isa_irq);
>> +
>> +            /* PIRQE..PIRQH are unused */
>> +            pci_writeb(PCI_ICH9_LPC_DEVFN, 0x68 + link, 0x80);  
>
>According to the spec 0x80 is the default value for this registers, do
>you really need to write it?
>
>Is maybe QEMU not correctly setting the default value?

Won't agree here. We're initializing PIRQ[n] routing in this
fragment, it's better not to rely on any values but simply initialize
all PIRQ[n]_ROUT registers, this makes it explicit.

Even if it is unnecessary due to defaults it's more obvious to set
these registers to our own values than to force a reader to either look
up their emulation in QEMU code or read the ICH9 pdf to confirm
assumptions.

>> +        }
>> +        else
>> +        {
>> +            pci_writeb(PCI_ISA_DEVFN, 0x60 + link, isa_irq);  
>
>Is all this magic described somewhere that you can reference?

It's setting up PCI interrupt routing for PIC mode. All this 
PIRQ[n]_ROUT stuff basically needed for legacy compatibility only,
normally we deal with APIC mode (+MSIs).

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.