Message ID | 1484089056-8762-4-git-send-email-venu.busireddy@oracle.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
>>> On 10.01.17 at 23:57, <venu.busireddy@oracle.com> wrote: > Changes in v13: > - Implement feedback from Kevin Tian. > https://lists.xenproject.org/archives/html/xen-devel/2015-10/msg03169.html > https://lists.xenproject.org/archives/html/xen-devel/2015-10/msg03170.html > https://lists.xenproject.org/archives/html/xen-devel/2015-10/msg03171.html Any reason some of the review comments I had given were left un-addressed? I'll reproduce them in quotes below. > --- a/xen/drivers/passthrough/vtd/dmar.c > +++ b/xen/drivers/passthrough/vtd/dmar.c > @@ -859,6 +859,132 @@ out: > return ret; > } > > +#define MAX_EXTRA_RMRR_PAGES 16 > +#define MAX_EXTRA_RMRR 10 > + > +/* RMRR units derived from command line rmrr option. */ > +#define MAX_EXTRA_RMRR_DEV 20 So you've kept "extra" in these, but ... > +struct user_rmrr { ... switched to "user" here and below. Please be consistent. > +static int __init add_user_rmrr(void) > +{ > + struct acpi_rmrr_unit *rmrr, *rmrru; > + unsigned int idx, seg, i; > + unsigned long base, end; > + bool overlap; > + > + for ( i = 0; i < nr_rmrr; i++ ) > + { > + base = user_rmrrs[i].base_pfn; > + end = user_rmrrs[i].end_pfn; > + > + if ( base > end ) > + { > + printk(XENLOG_ERR VTDPREFIX > + "Invalid RMRR Range "ERMRRU_FMT"\n", > + ERMRRU_ARG(user_rmrrs[i])); > + continue; > + } > + > + if ( (end - base) >= MAX_EXTRA_RMRR_PAGES ) > + { > + printk(XENLOG_ERR VTDPREFIX > + "RMRR range "ERMRRU_FMT" exceeds "\ > + __stringify(MAX_EXTRA_RMRR_PAGES)" pages\n", > + ERMRRU_ARG(user_rmrrs[i])); > + continue; > + } > + > + overlap = false; > + list_for_each_entry(rmrru, &acpi_rmrr_units, list) > + { > + if ( pfn_to_paddr(base) < rmrru->end_address && > + rmrru->base_address < pfn_to_paddr(end + 1) ) "Aren't both ranges inclusive? I.e. shouldn't the first one be <= (and the second one could be <= too when dropping the +1), matching the check acpi_parse_one_rmrr() does?" > + { > + printk(XENLOG_ERR VTDPREFIX > + "Overlapping RMRRs: "ERMRRU_FMT" and [%lx-%lx]\n", > + ERMRRU_ARG(user_rmrrs[i]), > + paddr_to_pfn(rmrru->base_address), > + paddr_to_pfn(rmrru->end_address)); > + overlap = true; > + break; > + } > + } > + /* Don't add overlapping RMRR. */ > + if ( overlap ) > + continue; > + > + do > + { > + if ( !mfn_valid(base) ) > + { > + printk(XENLOG_ERR VTDPREFIX > + "Invalid pfn in RMRR range "ERMRRU_FMT"\n", > + ERMRRU_ARG(user_rmrrs[i])); > + break; > + } > + } while ( base++ < end ); > + > + /* Invalid pfn in range as the loop ended before end_pfn was reached. */ > + if ( base <= end ) > + continue; > + > + rmrr = xzalloc(struct acpi_rmrr_unit); > + if ( !rmrr ) > + return -ENOMEM; > + > + rmrr->scope.devices = xmalloc_array(u16, user_rmrrs[i].dev_count); > + if ( !rmrr->scope.devices ) > + { > + xfree(rmrr); > + return -ENOMEM; > + } > + > + seg = 0; > + for ( idx = 0; idx < user_rmrrs[i].dev_count; idx++ ) > + { > + rmrr->scope.devices[idx] = user_rmrrs[i].sbdf[idx]; > + seg |= PCI_SEG(user_rmrrs[i].sbdf[idx]); > + } > + if ( seg != PCI_SEG(user_rmrrs[i].sbdf[0]) ) > + { > + printk(XENLOG_ERR VTDPREFIX > + "Segments are not equal for RMRR range "ERMRRU_FMT"\n", > + ERMRRU_ARG(user_rmrrs[i])); > + scope_devices_free(&rmrr->scope); > + xfree(rmrr); > + continue; > + } > + > + rmrr->segment = seg; > + rmrr->base_address = pfn_to_paddr(user_rmrrs[i].base_pfn); > + rmrr->end_address = pfn_to_paddr(user_rmrrs[i].end_pfn + 1); "And this seems wrong too, unless I'm mistaken with the inclusive-ness." > + rmrr->scope.devices_cnt = user_rmrrs[i].dev_count; > + > + if ( register_one_rmrr(rmrr) ) > + { > + printk(XENLOG_ERR VTDPREFIX > + "Could not register RMMR range "ERMRRU_FMT"\n", > + ERMRRU_ARG(user_rmrrs[i])); > + scope_devices_free(&rmrr->scope); > + xfree(rmrr); > + } > + } > + return 0; Blank line please before a function's final return statement. Jan
On Thu, Jan 12, 2017 at 04:44:42AM -0700, Jan Beulich wrote: > >>> On 10.01.17 at 23:57, <venu.busireddy@oracle.com> wrote: > > Changes in v13: > > - Implement feedback from Kevin Tian. > > https://lists.xenproject.org/archives/html/xen-devel/2015-10/msg03169.html > > https://lists.xenproject.org/archives/html/xen-devel/2015-10/msg03170.html > > https://lists.xenproject.org/archives/html/xen-devel/2015-10/msg03171.html > > Any reason some of the review comments I had given were left > un-addressed? I'll reproduce them in quotes below. > Hi Jan Thanks for reminding! That was my fault that I did not tell this to Venu when transferring this patchset to him. > > --- a/xen/drivers/passthrough/vtd/dmar.c > > +++ b/xen/drivers/passthrough/vtd/dmar.c > > @@ -859,6 +859,132 @@ out: > > return ret; > > } > > > > +#define MAX_EXTRA_RMRR_PAGES 16 > > +#define MAX_EXTRA_RMRR 10 > > + > > +/* RMRR units derived from command line rmrr option. */ > > +#define MAX_EXTRA_RMRR_DEV 20 > > So you've kept "extra" in these, but ... > > > +struct user_rmrr { > > ... switched to "user" here and below. Please be consistent. > > > +static int __init add_user_rmrr(void) > > +{ > > + struct acpi_rmrr_unit *rmrr, *rmrru; > > + unsigned int idx, seg, i; > > + unsigned long base, end; > > + bool overlap; > > + > > + for ( i = 0; i < nr_rmrr; i++ ) > > + { > > + base = user_rmrrs[i].base_pfn; > > + end = user_rmrrs[i].end_pfn; > > + > > + if ( base > end ) > > + { > > + printk(XENLOG_ERR VTDPREFIX > > + "Invalid RMRR Range "ERMRRU_FMT"\n", > > + ERMRRU_ARG(user_rmrrs[i])); > > + continue; > > + } > > + > > + if ( (end - base) >= MAX_EXTRA_RMRR_PAGES ) > > + { > > + printk(XENLOG_ERR VTDPREFIX > > + "RMRR range "ERMRRU_FMT" exceeds "\ > > + __stringify(MAX_EXTRA_RMRR_PAGES)" pages\n", > > + ERMRRU_ARG(user_rmrrs[i])); > > + continue; > > + } > > + > > + overlap = false; > > + list_for_each_entry(rmrru, &acpi_rmrr_units, list) > > + { > > + if ( pfn_to_paddr(base) < rmrru->end_address && > > + rmrru->base_address < pfn_to_paddr(end + 1) ) > > "Aren't both ranges inclusive? I.e. shouldn't the first one be <= (and > the second one could be <= too when dropping the +1), matching > the check acpi_parse_one_rmrr() does?" I agree. The ranges in acpu_rmrr_units and user_rmrrs are inclusive. If this is fixed, then there is another part where I am not sure what would be the better way to fix this. If fix is needed. I am looking at rmrr_identity_mapping where the RMRR paddr get converted to pfn and then mapped with iommu. If ( rmrr->end_address & ~PAGE_SHIFT_MASK_4K ) == 0, the while loop while ( base_pfn < end_pfn ) will not map that inclusive end_address of rmrr. Does it seem wrong? > > > + { > > + printk(XENLOG_ERR VTDPREFIX > > + "Overlapping RMRRs: "ERMRRU_FMT" and [%lx-%lx]\n", > > + ERMRRU_ARG(user_rmrrs[i]), > > + paddr_to_pfn(rmrru->base_address), > > + paddr_to_pfn(rmrru->end_address)); > > + overlap = true; > > + break; > > + } > > + } > > + /* Don't add overlapping RMRR. */ > > + if ( overlap ) > > + continue; > > + > > + do > > + { > > + if ( !mfn_valid(base) ) > > + { > > + printk(XENLOG_ERR VTDPREFIX > > + "Invalid pfn in RMRR range "ERMRRU_FMT"\n", > > + ERMRRU_ARG(user_rmrrs[i])); > > + break; > > + } > > + } while ( base++ < end ); > > + > > + /* Invalid pfn in range as the loop ended before end_pfn was reached. */ > > + if ( base <= end ) > > + continue; > > + > > + rmrr = xzalloc(struct acpi_rmrr_unit); > > + if ( !rmrr ) > > + return -ENOMEM; > > + > > + rmrr->scope.devices = xmalloc_array(u16, user_rmrrs[i].dev_count); > > + if ( !rmrr->scope.devices ) > > + { > > + xfree(rmrr); > > + return -ENOMEM; > > + } > > + > > + seg = 0; > > + for ( idx = 0; idx < user_rmrrs[i].dev_count; idx++ ) > > + { > > + rmrr->scope.devices[idx] = user_rmrrs[i].sbdf[idx]; > > + seg |= PCI_SEG(user_rmrrs[i].sbdf[idx]); > > + } > > + if ( seg != PCI_SEG(user_rmrrs[i].sbdf[0]) ) > > + { > > + printk(XENLOG_ERR VTDPREFIX > > + "Segments are not equal for RMRR range "ERMRRU_FMT"\n", > > + ERMRRU_ARG(user_rmrrs[i])); > > + scope_devices_free(&rmrr->scope); > > + xfree(rmrr); > > + continue; > > + } > > + > > + rmrr->segment = seg; > > + rmrr->base_address = pfn_to_paddr(user_rmrrs[i].base_pfn); > > + rmrr->end_address = pfn_to_paddr(user_rmrrs[i].end_pfn + 1); > > "And this seems wrong too, unless I'm mistaken with the inclusive-ness." > This one is the avoidance of the while loop mapping in rmrr_identity_mapping. > > + rmrr->scope.devices_cnt = user_rmrrs[i].dev_count; > > + > > + if ( register_one_rmrr(rmrr) ) > > + { > > + printk(XENLOG_ERR VTDPREFIX > > + "Could not register RMMR range "ERMRRU_FMT"\n", > > + ERMRRU_ARG(user_rmrrs[i])); > > + scope_devices_free(&rmrr->scope); > > + xfree(rmrr); > > + } > > + } > > + return 0; > > Blank line please before a function's final return statement. > > Jan
>>> On 18.01.17 at 20:56, <elena.ufimtseva@oracle.com> wrote: > I am looking at rmrr_identity_mapping where the RMRR paddr get converted > to pfn and then mapped with iommu. > If ( rmrr->end_address & ~PAGE_SHIFT_MASK_4K ) == 0, the while loop > while ( base_pfn < end_pfn ) > will not map that inclusive end_address of rmrr. > Does it seem wrong? I don't think so, no. end_pfn is being calculated using PAGE_ALIGN_4K(), i.e. rounding up. >> > + rmrr->segment = seg; >> > + rmrr->base_address = pfn_to_paddr(user_rmrrs[i].base_pfn); >> > + rmrr->end_address = pfn_to_paddr(user_rmrrs[i].end_pfn + 1); >> >> "And this seems wrong too, unless I'm mistaken with the inclusive-ness." >> > This one is the avoidance of the while loop mapping in > rmrr_identity_mapping. Well, that's the purpose you describe, but the comment was about the calculation itself, which I think is lacking a "- 1", but even better would be - for avoiding boundary issues - rmrr->end_address = pfn_to_paddr(user_rmrrs[i].end_pfn) | ~PAGE_MASK; or some such. Jan
On Thu, Jan 19, 2017 at 01:29:15AM -0700, Jan Beulich wrote: > >>> On 18.01.17 at 20:56, <elena.ufimtseva@oracle.com> wrote: > > I am looking at rmrr_identity_mapping where the RMRR paddr get converted > > to pfn and then mapped with iommu. > > If ( rmrr->end_address & ~PAGE_SHIFT_MASK_4K ) == 0, the while loop > > while ( base_pfn < end_pfn ) > > will not map that inclusive end_address of rmrr. > > Does it seem wrong? > > I don't think so, no. end_pfn is being calculated using > PAGE_ALIGN_4K(), i.e. rounding up. I mean to say, if the end address is already aligned, then the page wont be mapped. For example, if end paddr is 0x00000000000ed000, end_pfn will be 0x00000000000ed and wont be mapped in the loop while ( base_pfn < end_pfn ). And we will have mapped RMRR end address saved in arch.mapped_rmrrs as 0x00000000000ed000. Looks like parsed ACPI RMRR end addresses are extended to end of the page though. Not sure if there is somewhere same boundary alignment in code similar to what you proposed below. > > >> > + rmrr->segment = seg; > >> > + rmrr->base_address = pfn_to_paddr(user_rmrrs[i].base_pfn); > >> > + rmrr->end_address = pfn_to_paddr(user_rmrrs[i].end_pfn + 1); > >> > >> "And this seems wrong too, unless I'm mistaken with the inclusive-ness." > >> > > This one is the avoidance of the while loop mapping in > > rmrr_identity_mapping. > > Well, that's the purpose you describe, but the comment was about > the calculation itself, which I think is lacking a "- 1", but even better > would be - for avoiding boundary issues - > > rmrr->end_address = pfn_to_paddr(user_rmrrs[i].end_pfn) | ~PAGE_MASK; Yes, this will eliminate this problem. This will need to be accounted for in overlapping condition as well. > > or some such. > > Jan >
>>> On 19.01.17 at 18:44, <elena.ufimtseva@oracle.com> wrote: > On Thu, Jan 19, 2017 at 01:29:15AM -0700, Jan Beulich wrote: >> >>> On 18.01.17 at 20:56, <elena.ufimtseva@oracle.com> wrote: >> > I am looking at rmrr_identity_mapping where the RMRR paddr get converted >> > to pfn and then mapped with iommu. >> > If ( rmrr->end_address & ~PAGE_SHIFT_MASK_4K ) == 0, the while loop >> > while ( base_pfn < end_pfn ) >> > will not map that inclusive end_address of rmrr. >> > Does it seem wrong? >> >> I don't think so, no. end_pfn is being calculated using >> PAGE_ALIGN_4K(), i.e. rounding up. > > I mean to say, if the end address is already aligned, then the page wont > be mapped. Ah, that would be a problem, but would only affect systems with non-spec compliant firmware, as the doc says: "The reserved memory region size (Limit - Base + 1) must be an integer multiple of 4KB", along with requiring the base address to be 4k-aligned. Jan
diff --git a/docs/misc/xen-command-line.markdown b/docs/misc/xen-command-line.markdown index 0138978..a11fdf9 100644 --- a/docs/misc/xen-command-line.markdown +++ b/docs/misc/xen-command-line.markdown @@ -1377,6 +1377,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 RMRR 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 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. +Note: grub2 requires to escape or use quotations if special characters are used, +namely ';', refer to the grub2 documentation if multiple ranges are specified. + ### ro-hpet > `= <boolean>` diff --git a/xen/drivers/passthrough/vtd/dmar.c b/xen/drivers/passthrough/vtd/dmar.c index 84bf63d..23ba7a6 100644 --- a/xen/drivers/passthrough/vtd/dmar.c +++ b/xen/drivers/passthrough/vtd/dmar.c @@ -859,6 +859,132 @@ out: return ret; } +#define MAX_EXTRA_RMRR_PAGES 16 +#define MAX_EXTRA_RMRR 10 + +/* RMRR units derived from command line rmrr option. */ +#define MAX_EXTRA_RMRR_DEV 20 +struct user_rmrr { + 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 user_rmrr user_rmrrs[MAX_EXTRA_RMRR]; + +/* Macro for RMRR inclusive range formatting. */ +#define ERMRRU_FMT "[%lx-%lx]" +#define ERMRRU_ARG(eru) eru.base_pfn, eru.end_pfn + +static int __init add_user_rmrr(void) +{ + struct acpi_rmrr_unit *rmrr, *rmrru; + unsigned int idx, seg, i; + unsigned long base, end; + bool overlap; + + for ( i = 0; i < nr_rmrr; i++ ) + { + base = user_rmrrs[i].base_pfn; + end = user_rmrrs[i].end_pfn; + + if ( base > end ) + { + printk(XENLOG_ERR VTDPREFIX + "Invalid RMRR Range "ERMRRU_FMT"\n", + ERMRRU_ARG(user_rmrrs[i])); + continue; + } + + if ( (end - base) >= MAX_EXTRA_RMRR_PAGES ) + { + printk(XENLOG_ERR VTDPREFIX + "RMRR range "ERMRRU_FMT" exceeds "\ + __stringify(MAX_EXTRA_RMRR_PAGES)" pages\n", + ERMRRU_ARG(user_rmrrs[i])); + continue; + } + + overlap = false; + list_for_each_entry(rmrru, &acpi_rmrr_units, list) + { + if ( pfn_to_paddr(base) < rmrru->end_address && + rmrru->base_address < pfn_to_paddr(end + 1) ) + { + printk(XENLOG_ERR VTDPREFIX + "Overlapping RMRRs: "ERMRRU_FMT" and [%lx-%lx]\n", + ERMRRU_ARG(user_rmrrs[i]), + paddr_to_pfn(rmrru->base_address), + paddr_to_pfn(rmrru->end_address)); + overlap = true; + break; + } + } + /* Don't add overlapping RMRR. */ + if ( overlap ) + continue; + + do + { + if ( !mfn_valid(base) ) + { + printk(XENLOG_ERR VTDPREFIX + "Invalid pfn in RMRR range "ERMRRU_FMT"\n", + ERMRRU_ARG(user_rmrrs[i])); + break; + } + } while ( base++ < end ); + + /* Invalid pfn in range as the loop ended before end_pfn was reached. */ + if ( base <= end ) + continue; + + rmrr = xzalloc(struct acpi_rmrr_unit); + if ( !rmrr ) + return -ENOMEM; + + rmrr->scope.devices = xmalloc_array(u16, user_rmrrs[i].dev_count); + if ( !rmrr->scope.devices ) + { + xfree(rmrr); + return -ENOMEM; + } + + seg = 0; + for ( idx = 0; idx < user_rmrrs[i].dev_count; idx++ ) + { + rmrr->scope.devices[idx] = user_rmrrs[i].sbdf[idx]; + seg |= PCI_SEG(user_rmrrs[i].sbdf[idx]); + } + if ( seg != PCI_SEG(user_rmrrs[i].sbdf[0]) ) + { + printk(XENLOG_ERR VTDPREFIX + "Segments are not equal for RMRR range "ERMRRU_FMT"\n", + ERMRRU_ARG(user_rmrrs[i])); + scope_devices_free(&rmrr->scope); + xfree(rmrr); + continue; + } + + rmrr->segment = seg; + rmrr->base_address = pfn_to_paddr(user_rmrrs[i].base_pfn); + rmrr->end_address = pfn_to_paddr(user_rmrrs[i].end_pfn + 1); + rmrr->scope.devices_cnt = user_rmrrs[i].dev_count; + + if ( register_one_rmrr(rmrr) ) + { + printk(XENLOG_ERR VTDPREFIX + "Could not register RMMR range "ERMRRU_FMT"\n", + ERMRRU_ARG(user_rmrrs[i])); + scope_devices_free(&rmrr->scope); + xfree(rmrr); + } + } + return 0; +} + #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) */ @@ -868,6 +994,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)) ) @@ -878,7 +1005,12 @@ 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); + + if ( !ret ) + return add_user_rmrr(); + + return ret; } void acpi_dmar_reinstate(void) @@ -937,3 +1069,70 @@ int intel_iommu_get_reserved_device_memory(iommu_grdm_t *func, void *ctxt) return 0; } + +/* + * Parse rmrr Xen command line options and add parsed devices and regions 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, dev_count; + 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; + + user_rmrrs[nr_rmrr].base_pfn = start; + user_rmrrs[nr_rmrr].end_pfn = end; + + if ( *s != '=' ) + continue; + + do { + bool def_seg = false; + + stmp = parse_pci_seg(s + 1, &seg, &bus, &dev, &func, &def_seg); + if ( !stmp ) + break; + + /* + * Not specified. + * Segment will be replaced with one from first device. + */ + if ( user_rmrrs[nr_rmrr].dev_count && def_seg ) + seg = PCI_SEG(user_rmrrs[nr_rmrr].sbdf[0]); + + /* Keep sbdf's even if they differ and later report an error. */ + dev_count = user_rmrrs[nr_rmrr].dev_count; + user_rmrrs[nr_rmrr].sbdf[dev_count] = PCI_SBDF(seg, bus, dev, func); + + user_rmrrs[nr_rmrr].dev_count++; + s = stmp; + } while ( *s == ',' && + user_rmrrs[nr_rmrr].dev_count < MAX_EXTRA_RMRR_DEV ); + + if ( user_rmrrs[nr_rmrr].dev_count ) + nr_rmrr++; + + } while ( *s++ == ';' && nr_rmrr < MAX_EXTRA_RMRR ); +} +custom_param("rmrr", parse_rmrr_param);