|
[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
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |