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

Re: [Xen-devel] [PATCH v8 4/4] iommu: add rmrr Xen command line option for extra rmrrs



. snip..
> diff --git a/xen/drivers/passthrough/vtd/dmar.c 
> b/xen/drivers/passthrough/vtd/dmar.c
> index a8e1e5d..fa659a9 100644
> --- a/xen/drivers/passthrough/vtd/dmar.c
> +++ b/xen/drivers/passthrough/vtd/dmar.c
> @@ -42,6 +42,8 @@
>  #define MIN_SCOPE_LEN (sizeof(struct acpi_dmar_device_scope) + \
>                         sizeof(struct acpi_dmar_pci_path))
>  
> +#define PRI_RMRR(s,e) "[%lx-%lx]"
> +
>  LIST_HEAD_READ_MOSTLY(acpi_drhd_units);
>  LIST_HEAD_READ_MOSTLY(acpi_rmrr_units);
>  static LIST_HEAD_READ_MOSTLY(acpi_atsr_units);
> @@ -425,7 +427,7 @@ static int __init acpi_parse_dev_scope(
>          default:
>              if ( iommu_verbose )
>                  printk(XENLOG_WARNING VTDPREFIX "Unknown scope type %#x\n",
> -                       acpi_scope->entry_type);
> +                acpi_scope->entry_type);

Stray change? It should be in a seperate patch I think?

>              start += acpi_scope->length;
>              continue;
>          }
> @@ -479,8 +481,7 @@ acpi_parse_one_drhd(struct acpi_dmar_header *header)
>      INIT_LIST_HEAD(&dmaru->ioapic_list);
>      INIT_LIST_HEAD(&dmaru->hpet_list);
>      if ( iommu_verbose )
> -        dprintk(VTDPREFIX, "  dmaru->address = %"PRIx64"\n",
> -                dmaru->address);
> +        dprintk(VTDPREFIX, "  dmaru->address = %"PRIx64"\n", dmaru->address);

Ditto.
>  
>      ret = iommu_alloc(dmaru);
>      if ( ret )
> @@ -541,8 +542,8 @@ acpi_parse_one_drhd(struct acpi_dmar_header *header)
>              if ( !pci_device_detect(drhd->segment, b, d, f) )
>              {
>                  dprintk(XENLOG_WARNING VTDPREFIX,
> -                        " Non-existent device (%04x:%02x:%02x.%u) is 
> reported"
> -                        " in this DRHD's scope!\n", drhd->segment, b, d, f);
> +                        " Non-existent device (%04x:%02x:%02x.%u) is 
> reported in this DRHD's scope!\n",
> +                        drhd->segment, b, d, f);

As well - an seperate cleanup patch.
>                  invalid_cnt++;
>              }
>          }
> @@ -553,8 +554,8 @@ acpi_parse_one_drhd(struct acpi_dmar_header *header)
>                   invalid_cnt == dmaru->scope.devices_cnt )
>              {
>                  dprintk(XENLOG_WARNING VTDPREFIX,
> -                    "  Workaround BIOS bug: ignore the DRHD due to all "
> -                    "devices under its scope are not PCI discoverable!\n");
> +                        "  Workaround BIOS bug: ignore the DRHD due to all "
> +                        "devices under its scope are not PCI 
> discoverable!\n");

This one too.
>  
>                  scope_devices_free(&dmaru->scope);
>                  iommu_free(dmaru);
> @@ -563,10 +564,10 @@ acpi_parse_one_drhd(struct acpi_dmar_header *header)
>              else
>              {
>                  dprintk(XENLOG_WARNING VTDPREFIX,
> -                    "  The DRHD is invalid due to there are devices under "
> -                    "its scope are not PCI discoverable! Pls try option "
> -                    "iommu=force or iommu=workaround_bios_bug if you "
> -                    "really want VT-d\n");
> +                        "  The DRHD is invalid due to there are devices 
> under "
> +                        "its scope are not PCI discoverable! Pls try option "
> +                        "iommu=force or iommu=workaround_bios_bug if you "
> +                        "really want VT-d\n");

And that as well.
>                  ret = -EINVAL;
>              }
>          }
> @@ -604,8 +605,7 @@ static int register_one_rmrr(struct acpi_rmrr_unit *rmrru)
>          if ( pci_device_detect(rmrru->segment, b, d, f) == 0 )
>          {
>              dprintk(XENLOG_WARNING VTDPREFIX,
> -                    " Non-existent device (%04x:%02x:%02x.%u) is reported"
> -                    " in RMRR (%"PRIx64", %"PRIx64")'s scope!\n",
> +                    " Non-existent device (%04x:%02x:%02x.%u) is reported in 
> RMRR "PRI_RMRR(s,e)"'s scope!\n",
>                      rmrru->segment, b, d, f,
>                      rmrru->base_address, rmrru->end_address);
>              ignore = 1;
> @@ -620,16 +620,16 @@ static int register_one_rmrr(struct acpi_rmrr_unit 
> *rmrru)
>      if ( ignore )
>      {
>          dprintk(XENLOG_WARNING VTDPREFIX,
> -                "  Ignore the RMRR (%"PRIx64", %"PRIx64") due to "
> +                "  Ignore the RMRR "PRI_RMRR(s,e)" due to "
>                  "devices under its scope are not PCI discoverable!\n",
> -            rmrru->base_address, rmrru->end_address);
> +                rmrru->base_address, rmrru->end_address);
>          scope_devices_free(&rmrru->scope);
>          xfree(rmrru);
>      }
>      else if ( rmrru->base_address > rmrru->end_address )
>      {
>          dprintk(XENLOG_WARNING VTDPREFIX,
> -                "  The RMRR (%"PRIx64", %"PRIx64") is incorrect!\n",
> +                "  The RMRR "PRI_RMRR(s,e)" is incorrect!\n",
>                  rmrru->base_address, rmrru->end_address);
>          scope_devices_free(&rmrru->scope);
>          xfree(rmrru);
> @@ -639,7 +639,7 @@ static int register_one_rmrr(struct acpi_rmrr_unit *rmrru)
>      {
>          if ( iommu_verbose )
>              dprintk(VTDPREFIX,
> -                    "  RMRR region: base_addr %"PRIx64" end_address 
> %"PRIx64"\n",
> +                    "  RMRR region: "PRI_RMRR(s,e)"\n",
>                      rmrru->base_address, rmrru->end_address);
>          acpi_register_rmrr_unit(rmrru);
>      }
> @@ -664,7 +664,7 @@ acpi_parse_one_rmrr(struct acpi_dmar_header *header)
>         if ( base_addr <= rmrru->end_address && rmrru->base_address <= 
> end_addr )
>         {
>             printk(XENLOG_ERR VTDPREFIX
> -                  "Overlapping RMRRs [%"PRIx64",%"PRIx64"] and 
> [%"PRIx64",%"PRIx64"]\n",
> +                  "Overlapping RMRRs "PRI_RMRR(s,e)" and "PRI_RMRR(s,e)"\n",
>                    rmrru->base_address, rmrru->end_address,
>                    base_addr, end_addr);
>             return -EEXIST;
> @@ -678,8 +678,7 @@ acpi_parse_one_rmrr(struct acpi_dmar_header *header)
>           (!page_is_ram_type(paddr_to_pfn(end_addr), RAM_TYPE_RESERVED)) )
>      {
>          dprintk(XENLOG_WARNING VTDPREFIX,
> -                "  RMRR address range not in reserved memory "
> -                "base = %"PRIx64" end = %"PRIx64"; "
> +                "  RMRR address range "PRI_RMRR(s,e)" not in reserved 
> memory; "
>                  "iommu_inclusive_mapping=1 parameter may be needed.\n",
>                  base_addr, end_addr);
>      }
> @@ -779,8 +778,7 @@ acpi_parse_one_rhsa(struct acpi_dmar_header *header)
>      list_add_tail(&rhsau->list, &acpi_rhsa_units);
>      if ( iommu_verbose )
>          dprintk(VTDPREFIX,
> -                "  rhsau->address: %"PRIx64
> -                " rhsau->proximity_domain: %"PRIx32"\n",
> +                "  rhsau->address: %"PRIx64" rhsau->proximity_domain: 
> %"PRIx32"\n",

All of those should go in a seperate cleanup patch please.

>                  rhsau->address, rhsau->proximity_domain);
>  
>      return ret;
> @@ -869,6 +867,140 @@ out:
>      return ret;
>  }
>  
> +#define MAX_EXTRA_RMRR_PAGES 16
> +#define MAX_EXTRA_RMRR 10
> +
> +/* RMRR units derived from command line rmrr option */

Missing full stop.

> +#define MAX_EXTRA_RMRR_DEV 20
> +struct extra_rmrr_unit {
> +    struct list_head list;
> +    unsigned long base_pfn, end_pfn;
> +    unsigned int dev_count;
> +    u32    sbdf[MAX_EXTRA_RMRR_DEV];
> +};
> +static __initdata unsigned int nr_rmrr;
> +static struct __initdata extra_rmrr_unit extra_rmrr_units[MAX_EXTRA_RMRR];
> +
> +/* Macro for RMRR inclusive range formatting */

Macro? Ah I think you meant the:
#define PRI_RMRR(s,e) "[%lx-%lx]"

which is defined somewhere at the top of the file with your patch. Please
move it here.

Also, missing full stop at the end of the line.
> +
> +static void __init add_extra_rmrr(void)
> +{
> +    struct acpi_rmrr_unit *acpi_rmrr;
> +    struct acpi_rmrr_unit *rmrru;
> +    unsigned int dev, seg, i, j;
> +    unsigned long pfn;
> +
> +    for ( i = 0; i < nr_rmrr; i++ )
> +    {
> +        if ( extra_rmrr_units[i].base_pfn > extra_rmrr_units[i].end_pfn )
> +        {
> +            printk(XENLOG_ERR VTDPREFIX
> +                   "Invalid RMRR Range "PRI_RMRR(s,e)"\n",
> +                   extra_rmrr_units[i].base_pfn, 
> extra_rmrr_units[i].end_pfn);
> +            continue;
> +        }
> +
> +        if ( extra_rmrr_units[i].end_pfn - extra_rmrr_units[i].base_pfn >=
> +             MAX_EXTRA_RMRR_PAGES )
> +        {
> +            printk(XENLOG_ERR VTDPREFIX
> +                   "RMRR range "PRI_RMRR(s,e)" exceeds 
> "__stringify(MAX_EXTRA_RMRR_PAGES)" pages\n",
> +                   extra_rmrr_units[i].base_pfn, 
> extra_rmrr_units[i].end_pfn);
> +            continue;
> +        }
> +
> +        for ( j = 0; j < nr_rmrr; j++ )
> +        {
> +            if ( i != j &&
> +                 extra_rmrr_units[i].base_pfn <= extra_rmrr_units[j].end_pfn 
> &&
> +                 extra_rmrr_units[j].base_pfn <= extra_rmrr_units[i].end_pfn 
> )
> +            {
> +                printk(XENLOG_ERR VTDPREFIX
> +                      "Overlapping RMRRs "PRI_RMRR(s,e)" and 
> "PRI_RMRR(s,e)"\n",
> +                      extra_rmrr_units[i].base_pfn, 
> extra_rmrr_units[i].end_pfn,
> +                      extra_rmrr_units[j].base_pfn, 
> extra_rmrr_units[j].end_pfn);
> +                break;
> +            }
> +        }
> +        /* Broke out of the overlap loop check, continue with next rmrr. */
> +        if ( j < nr_rmrr )
> +            continue;
> +        list_for_each_entry(rmrru, &acpi_rmrr_units, list)
> +        {
> +            if ( pfn_to_paddr(extra_rmrr_units[i].base_pfn <= 
> rmrru->end_address) &&
> +                 rmrru->base_address <= 
> pfn_to_paddr(extra_rmrr_units[i].end_pfn) )
> +            {
> +                printk(XENLOG_ERR VTDPREFIX
> +                       "Overlapping extra RMRRs "PRI_RMRR(s,e)" and ACPI 
> RMRRs "PRI_RMRR(s,e)"\n",
> +                       extra_rmrr_units[i].base_pfn,
> +                       extra_rmrr_units[i].end_pfn,
> +                       paddr_to_pfn(rmrru->base_address),
> +                       paddr_to_pfn(rmrru->end_address));
> +                break;

You break out of the for loop (list_for_each_entry) - did ..
> +            }
> +        }

... you also want to continue with the next rmrr? Right now the code
will continue on with this 'i'.

> +
> +
> +        pfn = extra_rmrr_units[i].base_pfn;
> +        do
> +        {
> +            if ( !mfn_valid(pfn) || (pfn >> (paddr_bits - PAGE_SHIFT)) )
> +            {
> +                if ( iommu_verbose )

Why the 'iommu_verbose' ? Why not just print it out as all the other errors
are printed?

> +                    printk(XENLOG_ERR VTDPREFIX
> +                           "Invalid mfn in RMRR range "PRI_RMRR(s,e)"\n",
> +                           extra_rmrr_units[i].base_pfn, 
> extra_rmrr_units[i].end_pfn);
> +                break;
> +            }
> +        } while ( pfn++ <= extra_rmrr_units[i].end_pfn );
> +        /* The range had invalid mfn as the loop was broken out before 
> reaching end_pfn. */
> +        if ( pfn <= extra_rmrr_units[i].end_pfn )
> +            continue;
> +
> +        acpi_rmrr = xzalloc(struct acpi_rmrr_unit);
> +        if ( !acpi_rmrr )
> +            return;
> +
> +        acpi_rmrr->scope.devices = xmalloc_array(u16,
> +                                                 
> extra_rmrr_units[i].dev_count);
> +        if ( !acpi_rmrr->scope.devices )
> +        {
> +            xfree(acpi_rmrr);
> +            return;
> +        }
> +
> +        seg = 0;
> +        for ( dev = 0; dev < extra_rmrr_units[i].dev_count; dev++ )
> +        {
> +            acpi_rmrr->scope.devices[dev] = extra_rmrr_units[i].sbdf[dev];
> +            seg = seg | PCI_SEG(extra_rmrr_units[i].sbdf[dev]);
> +        }
> +        if ( seg != PCI_SEG(extra_rmrr_units[i].sbdf[0]) )
> +        {
> +            printk(XENLOG_ERR VTDPREFIX
> +                   "Segments are not equal for RMRR range "PRI_RMRR(s,e)"\n",
> +                   extra_rmrr_units[i].base_pfn, 
> extra_rmrr_units[i].end_pfn);
> +            scope_devices_free(&acpi_rmrr->scope);
> +            xfree(acpi_rmrr);
> +            continue;
> +        }
> +
> +        acpi_rmrr->segment = seg;
> +        acpi_rmrr->base_address = pfn_to_paddr(extra_rmrr_units[i].base_pfn);
> +        acpi_rmrr->end_address = pfn_to_paddr(extra_rmrr_units[i].end_pfn + 
> 1);
> +        acpi_rmrr->scope.devices_cnt = extra_rmrr_units[i].dev_count;
> +
> +        if ( register_one_rmrr(acpi_rmrr) )
> +        {
> +            printk(XENLOG_ERR VTDPREFIX
> +                   "Could not register RMMR range "PRI_RMRR(s,e)"\n",
> +                   extra_rmrr_units[i].base_pfn, 
> extra_rmrr_units[i].end_pfn);
> +            scope_devices_free(&acpi_rmrr->scope);
> +            xfree(acpi_rmrr);
> +        }
> +    }
> +}
> +
>  #include <asm/tboot.h>
>  /* ACPI tables may not be DMA protected by tboot, so use DMAR copy */
>  /* SINIT saved in SinitMleData in TXT heap (which is DMA protected) */
> @@ -878,6 +1010,7 @@ int __init acpi_dmar_init(void)
>  {
>      acpi_physical_address dmar_addr;
>      acpi_native_uint dmar_len;
> +    int ret;
>  
>      if ( ACPI_SUCCESS(acpi_get_table_phys(ACPI_SIG_DMAR, 0,
>                                            &dmar_addr, &dmar_len)) )
> @@ -888,7 +1021,10 @@ int __init acpi_dmar_init(void)
>          dmar_table = __va(dmar_addr);
>      }
>  
> -    return parse_dmar_table(acpi_parse_dmar);
> +    ret = parse_dmar_table(acpi_parse_dmar);
> +    add_extra_rmrr();
> +
> +    return ret;
>  }
>  
>  void acpi_dmar_reinstate(void)
> @@ -919,3 +1055,67 @@ int platform_supports_x2apic(void)
>      unsigned int mask = ACPI_DMAR_INTR_REMAP | ACPI_DMAR_X2APIC_OPT_OUT;
>      return cpu_has_x2apic && ((dmar_flags & mask) == ACPI_DMAR_INTR_REMAP);
>  }
> +
> +/*
> + * Parse rmrr Xen command line options and add parsed device and region into
> + * acpi_rmrr_unit list to mapped as RMRRs parsed from ACPI.
> + * Format:
> + * 
> rmrr=start<-end>=[s1]bdf1[,[s1]bdf2[,...]];start<-end>=[s2]bdf1[,[s2]bdf2[,...]]
> + * If the segment of the first device is not specified, segment zero will be 
> used.
> + * If other segments are not specified, first device segment will be used.
> + * If a segment is specified for other than the first device and it does not 
> match
> + * the one specified for the first one, an error will be reported.
> + */
> +static void __init parse_rmrr_param(const char *str)
> +{
> +    const char *s = str, *cur, *stmp;
> +    unsigned int seg, bus, dev, func;
> +    unsigned long start, end;
> +
> +    do {
> +        start = simple_strtoul(cur = s, &s, 0);
> +        if ( cur == s )
> +            break;
> +
> +        if ( *s == '-' )
> +        {
> +            end = simple_strtoul(cur = s + 1, &s, 0);
> +            if ( cur == s )
> +                break;
> +        }
> +        else
> +            end = start;
> +
> +        extra_rmrr_units[nr_rmrr].base_pfn = start;
> +        extra_rmrr_units[nr_rmrr].end_pfn = end;
> +        extra_rmrr_units[nr_rmrr].dev_count = 0;
> +
> +        if ( *s != '=' )
> +            continue;
> +
> +        do {
> +            bool_t default_segment = 0;
> +
> +            if ( *s == ';' )
> +                break;
> +            stmp = __parse_pci(s + 1, &seg, &bus, &dev, &func, 
> &default_segment);
> +            if ( !stmp )
> +                break;
> +
> +            /* Not specified segment will be replaced with one from first 
> device. */
> +            if ( extra_rmrr_units[nr_rmrr].dev_count && default_segment )
> +                seg = PCI_SEG(extra_rmrr_units[nr_rmrr].sbdf[0]);
> +
> +            /* Keep sbdf's even if they differ and later report an error. */
> +            
> extra_rmrr_units[nr_rmrr].sbdf[extra_rmrr_units[nr_rmrr].dev_count] = 
> PCI_SBDF(seg, bus, dev, func);
> +            extra_rmrr_units[nr_rmrr].dev_count++;
> +            s = stmp;
> +        } while ( *s == ',' &&
> +                  extra_rmrr_units[nr_rmrr].dev_count < MAX_EXTRA_RMRR_DEV );
> +
> +        if ( extra_rmrr_units[nr_rmrr].dev_count )
> +            nr_rmrr++;
> +
> +    } while ( *s++ == ';' && nr_rmrr < MAX_EXTRA_RMRR );
> +}
> +custom_param("rmrr", parse_rmrr_param);


Otherwise looks fine!
> -- 
> 2.1.3
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

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