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

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



On Tue, May 26, 2015 at 01:02:27PM +0100, Jan Beulich wrote:
> >>> On 23.05.15 at 03:33, <elena.ufimtseva@xxxxxxxxxx> wrote:
> > --- a/docs/misc/xen-command-line.markdown
> > +++ b/docs/misc/xen-command-line.markdown
> > @@ -1185,6 +1185,19 @@ Specify the host reboot method.
> >  'efi' instructs Xen to reboot using the EFI reboot call (in EFI mode by
> >   default it will use that method first).
> >  
> > +### rmrr
> > +> '= 
> > start<-end>=[s1]bdf1[,[s1]bdf2[,...]];start<-end>=[s2]bdf1[,[s2]bdf2[,...]]
> > +
> > +Define RMRRs units that are missing from ACPI table along with device
> > +they belong to and use them for 1:1 mapping. End addresses can be omitted
> > +and one page will be mapped. The ranges are inclusive when start and end
> > +are specified.If segement of the first device is not specified, the 
> > default segment will be used.
> 

Thanks for review Jan.

> "specified. If the segment ..., segment zero will be used."
> 
> > +If segments are specified for every device and not equal, error will be 
> > reported.
> 
> "..., an error ..."
> 
> > --- a/xen/drivers/passthrough/vtd/dmar.c
> > +++ b/xen/drivers/passthrough/vtd/dmar.c
> > @@ -50,6 +50,7 @@ static LIST_HEAD_READ_MOSTLY(acpi_rhsa_units);
> >  static struct acpi_table_header *__read_mostly dmar_table;
> >  static int __read_mostly dmar_flags;
> >  static u64 __read_mostly igd_drhd_address;
> > +static void __init add_extra_rmrr(void);
> 
> Why do you need this declaration? (And if you really need it - no
> segment annotations on declarations please.)
> 
> > @@ -856,6 +857,78 @@ out:
> >      return ret;
> >  }
> >  
> > +#define MAX_EXTRA_RMRR_PAGES 16
> > +#define MAX_EXTRA_RMRR 10
> > +static __initdata unsigned int nr_rmrr;
> > +static struct __initdata extra_rmrr_unit rmrru[MAX_EXTRA_RMRR];
> > +
> > +static void __init add_extra_rmrr(void)
> > +{
> > +    struct acpi_rmrr_unit *rmrrn;
> > +    unsigned int dev, seg, addr;
> > +
> > +    for (unsigned int i = 0; i < nr_rmrr; i++ )
> 
> No C++ style constructs like this please. Instead please add the
> missing blank after the opening parenthesis.
> 
> > +    {
> > +        rmrrn = xmalloc(struct acpi_rmrr_unit);
> 
> acpi_parse_one_rmrr() uses xzalloc() here. For the avoidance of
> doubt, I'd be fine with you doing so provided this is correct (i.e. all
> fields end up properly initialized, just like is the case with the
> ->scope.devices allocation), if this wasn't introducing a latent bug
> (should a field get added).
Agree, will change this.
> 
> > +        if ( !rmrrn )
> > +            return;
> > +
> > +        rmrrn->scope.devices = xmalloc_array(typeof(*rmrrn->scope.devices),
> 
> I'm afraid I may have mislead you with comments elsewhere: In
> xmalloc() invocations, considering the typeful result it produces,
> using the spelled out type is preferred over typeof() like used
> here.
Thanks for explanation, I did not know that.
> 
> > +                                             rmrru[i].dev_count);
> > +        if ( !rmrrn->scope.devices )
> > +        {
> > +            xfree(rmrrn);
> > +            return;
> > +        }
> > +
> > +        if ( rmrru[i].end_address - rmrru[i].base_address > 
> > MAX_EXTRA_RMRR_PAGES )
> 
> Now this reads really odd: With the conversion to store page numbers
> in these fields, they should have got renamed from _address (and
> afaict no longer need to be of u64 type). Also note that you have an
> off-by-one error here: The end address being inclusive, you want to
> bail on >= max.
> 
> I also fail to see end < base being rejected somewhere. Nor are
> overlaps being dealt with (see acpi_parse_one_rmrr()).

Somehow I skipped that, possibly wrong brnach.
Will fix this and add overlap check.
> 
> > +        {
> > +            printk(XENLOG_ERR VTDPREFIX
> > +                   "RMRR range exceeds 16 pages [%"PRIx64" - %"PRIx64"]\n",
> > +                   rmrru[i].base_address, rmrru[i].end_address);
> > +            xfree(rmrrn->scope.devices);
> > +            xfree(rmrrn);
> > +            return;
> > +        }
> > +
> > +        for ( addr = rmrru[i].base_address; addr <= rmrru[i].end_address; 
> > addr++ )
> 
> And the loop variable here shouldn't be addr then (and certainly not
> of type "unsigned int").
> 
> > +        {
> > +            if ( iommu_verbose )
> > +                printk(XENLOG_ERR VTDPREFIX
> > +                       "Invalid mfn in RMRR range [%"PRIx64" - 
> > %"PRIx64"]\n",
> > +                       rmrru[i].base_address, rmrru[i].end_address);
> > +            xfree(rmrrn->scope.devices);
> > +            xfree(rmrrn);
> > +            return;
> > +        }
> > +
> > +        seg = 0;
> > +        for ( dev = 0; dev < rmrru->dev_count; dev++ )
> > +        {
> > +            rmrrn->scope.devices[dev] = rmrru->sbdf[dev];
> > +            seg = seg | (rmrru->sbdf[dev] >> 16);
> 
> |=
> 
> Also with you having added PCI_SBDF() in patch 1, you should add
> the matched PCI_SEG() (or some such) instead of open coding it
> here.
Yes, will be also useful.
> 
> > +        }
> > +        if ( seg != (rmrru->sbdf[0] >> 16) )
> > +        {
> > +            printk(XENLOG_ERR VTDPREFIX
> > +                   "Segments are not equal for RMRR range  [%"PRIx64" - 
> > %"PRIx64"]\n",
> > +                   rmrru->base_address, rmrru->end_address);
> > +            xfree(rmrrn->scope.devices);
> > +            xfree(rmrrn);
> > +            continue;
> > +        }
> > +        rmrrn->segment = seg;
> > +        rmrrn->base_address = rmrru[i].base_address << PAGE_SHIFT;
> > +        rmrrn->end_address = (rmrru[i].end_address + 1) << PAGE_SHIFT;
> > +        rmrrn->scope.devices_cnt = rmrru[i].dev_count;
> > +
> > +        if ( register_one_rmrr(rmrrn) )
> > +            printk(XENLOG_ERR VTDPREFIX
> > +                   "Could not register RMMR range  [%"PRIx64" - 
> > %"PRIx64"]\n",
> > +                   rmrru[i].base_address, rmrru[i].end_address);
> 
> xfree(rmrrn)?
> 
> > @@ -874,6 +947,7 @@ int __init acpi_dmar_init(void)
> >                           PAGE_HYPERVISOR);
> >          dmar_table = __va(dmar_addr);
> >      }
> > +    add_extra_rmrr();
> >  
> >      return parse_dmar_table(acpi_parse_dmar);
> >  }
> 
> I'd really like to see the extra RMRRs being added after the ones
> parsed from the ACPI tables. 
> 
> > + * If segement of the first device is not specified, the default segment 
> > will be used.
> > + * If other segments are not specified, first device segment will be used.
> > + * If segments are specified for every device and not equal, error will be 
> > reported.
> 
> See patch description comments.
> 
> > +static void __init parse_rmrr_param(const char *str)
> > +{
> > +    const char *s = str, *cur, *stmp;
> > +    unsigned int seg, bus, dev, func;
> > +    int default_segment = 0;
> 
> This must be initialized on each iteration of the inner loop below.
> Best to simply move the declaration + initializer into that loop (as
> could be done for several of the other variables).
> 
> > +    u64 start, end;
> > +
> > +    do {
> > +        start = simple_strtoull(cur = s, &s, 0);
> 
> strtoul() is sufficient for parsing frame numbers.
> 
> > +        if ( cur == s )
> > +            break;
> > +
> > +        if ( *s == '-' )
> > +        {
> > +            end = simple_strtoull(cur = s + 1, &s, 0);
> > +            if ( cur == s )
> > +                break;
> > +        }
> > +        else
> > +            end = start;
> > +        if ( nr_rmrr < MAX_EXTRA_RMRR )
> > +        {
> > +            rmrru[nr_rmrr].base_address = start;
> > +            rmrru[nr_rmrr].end_address = end;
> > +            rmrru[nr_rmrr].dev_count = 0;
> > +        }
> > +        else
> > +            break;
> 
> Pointless if/else (else can be avoided by inverting the condition).
> And the resulting if() would then be moved up and as a result be
> folded (after inverting back) into the loop condition.

Agree.
> 
> > +        if ( *s != '=' )
> > +            continue;
> > +
> > +        do {
> > +            if ( rmrru[nr_rmrr].dev_count >= MAX_EXTRA_RMRR_DEV )
> > +                break;
> 
> Similarly this could be inverted and folded into the loop condition.
> 
> > +            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 ( rmrru[nr_rmrr].dev_count > 0 && (seg != 
> > (rmrru[nr_rmrr].sbdf[0] >> 16)) )
> > +                if ( default_segment )
> 
> The two if()-s should be folded. And then I don't see what the right
> side of the && is good for.

True, later I compare them anyways.
> 
> > --- a/xen/drivers/passthrough/vtd/dmar.h
> > +++ b/xen/drivers/passthrough/vtd/dmar.h
> > @@ -132,4 +132,14 @@ void disable_pmr(struct iommu *iommu);
> >  int is_usb_device(u16 seg, u8 bus, u8 devfn);
> >  int is_igd_drhd(struct acpi_drhd_unit *drhd);
> >  
> > +/* RMRR units derived from command line rmrr option */
> > +#define MAX_EXTRA_RMRR_DEV 20
> > +struct extra_rmrr_unit {
> > +    struct list_head list;
> > +    u64    base_address;
> > +    u64    end_address;
> > +    u16    dev_count;
> > +    u32    sbdf[MAX_EXTRA_RMRR_DEV];
> > +};
> 
> I'm pretty certain I had already indicated that types used in only a
> single source file should not be put in any header.

Yep, missed that.
> 
> Jan

_______________________________________________
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®.