|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v8 07/11] vpci/bars: add handlers to map the BARs
>>> On 27.02.18 at 10:21, <roger.pau@xxxxxxxxxx> wrote:
> On Tue, Feb 27, 2018 at 01:32:24AM -0700, Jan Beulich wrote:
>> >>> On 26.02.18 at 19:00, <roger.pau@xxxxxxxxxx> wrote:
>> > On Mon, Feb 26, 2018 at 04:20:17AM -0700, Jan Beulich wrote:
>> >> >>> On 23.01.18 at 16:07, <roger.pau@xxxxxxxxxx> wrote:
>> >> > +static void maybe_defer_map(struct domain *d, const struct pci_dev
>> >> > *pdev,
>> >> > + struct rangeset *mem, bool map, bool rom)
>> >> > +{
>> >> > + struct vcpu *curr = current;
>> >> > +
>> >> > + if ( is_idle_vcpu(curr) )
>> >> > + {
>> >> > + struct map_data data = { .d = d, .map = true };
>> >> > +
>> >> > + /*
>> >> > + * Only used for domain construction in order to map the BARs
>> >> > + * of devices with memory decoding enabled.
>> >> > + */
>> >> > + ASSERT(map && !rom);
>> >> > + rangeset_consume_ranges(mem, map_range, &data);
>> >>
>> >> What if this produces -ENOMEM? And despite having looked at
>> >> several revisions of this, I can't make the connection to why this
>> >> is in an is_idle_vcpu() conditional (neither the direct caller nor the
>> >> next level up make this obvious to me). There's clearly a need
>> >> for extending the comment.
>> >
>> > I thought the comment above that mentions domain construction would be
>> > enough. I can try to expand this, maybe like:
>> >
>> > "This function will only be called from the idle vCPU while building
>> > the domain, in which case it's not possible to defer the operation
>> > (like done in the else branch). Call rangeset_consume_ranges in order
>> > to establish the mappings right away."
>>
>> And what again is the connection between is_idle_domain() and
>> domain construction? I think the comment belongs ahead of the
>> if(), and it needs to make that connection.
>
> Oh, domain constructions runs on the idle vCPU, that's the relation.
>
> "This function will only be called from the idle vCPU while building
> the domain (because Dom0 building runs on the idle vCPU), in which
> case it's not possible to defer the operation (like done in the else
> branch). Call rangeset_consume_ranges in order to establish the
> mappings right away."
>
> Does that seem clearer if placed ahead of the if?
Can be shorter imo - the thing I didn't pay attention to is that
this is all about _dom0_ building, not general _domain_ building.
Hence perhaps:
"Dom0 building runs on the idle vCPU, in which case it's not possible
to defer the operation (like done in the else branch). Call
rangeset_consume_ranges in order to establish the mappings right
away."
>> >> > +static void modify_bars(const struct pci_dev *pdev, bool map, bool rom)
>> >> > +{
>> >> > + struct vpci_header *header = &pdev->vpci->header;
>> >> > + struct rangeset *mem = rangeset_new(NULL, NULL, 0);
>> >> > + const struct pci_dev *tmp;
>> >> > + unsigned int i;
>> >> > + int rc;
>> >> > +
>> >> > + if ( !map )
>> >> > + modify_decoding(pdev, false, rom);
>> >> > +
>> >> > + if ( !mem )
>> >> > + return;
>> >>
>> >> Similarly here - why is it okay (or what effect will it have) to return
>> >> here when we're out of memory, but the caller won't know?
>> >
>> > The behaviour here depends on the change to the memory decoding bit:
>> >
>> > - Clearing: memory decoding on device will be disabled, BARs won't be
>> > unmapped.
>> > - Setting: no change to device memory decoding bit, BARs won't be
>> > mapped.
>> >
>> > Do you think this is suitable? IMO it's fine to disable the memory
>> > decoding bit on the device and leave the memory regions mapped.
>>
>> As long as subsequent changes to the decoding bit can't leave
>> stale mappings. Plus there needs to be a comment to explain this.
>
> With the current approach in the unmap case there will be stale
> mappings left behind.
>
> I guess it's better then to not modify the memory decoding bit at all
> until the operation finishes. That also rises the question of whether
> the memory decoding bit should be modified if p2m mapping/unmapping
> reports an error.
>
> Should we also attempt to rollback failed map/unmap operations? What
> happens if the rollback also fails?
It is in particular this last question why I don't think rollback makes
sense. If there's any failure, I think the decode bit should be sticky
clear; we may want (need?) to invent some magical mechanism to
get a device back out of this state later on. But that way stale
mappings are not an immediate problem (I think).
> What about the following:
>
> +---------+ SUCCESS +---------------------------------+
> |map/unmap+------------>Change decoding or ROM enable bit|
> +----+----+ +---------------------------------+
> |
> |FAILURE
> |
> +--------v-------+ SUCCESS +---------------------------------------+
> |revert operation+--------->No change to decoding or ROM enable bit|
> +--------+-------+ +---------------------------------------+
> |
> |FAILURE
> |
> +-----v-----+
> |Kill domain|
> +-----------+
Possibly. Killing Dom0 is a bad thing though, if just some random
device has a problem.
>> >> > + for ( i = 0; i < ARRAY_SIZE(header->bars); i++ )
>> >> > + {
>> >> > + const struct vpci_bar *bar = &header->bars[i];
>> >> > +
>> >> > + if ( !MAPPABLE_BAR(bar) ||
>> >> > + (rom ? bar->type != VPCI_BAR_ROM
>> >> > + : (bar->type == VPCI_BAR_ROM &&
>> >> > !header->rom_enabled)) )
>> >> > + continue;
>> >>
>> >> Why does rom_enabled matter for the !rom case rather than for
>> >> the rom one? I.e.
>> >>
>> >> if ( !MAPPABLE_BAR(bar) ||
>> >> (rom ? bar->type != VPCI_BAR_ROM || !header->rom_enabled
>> >> : bar->type == VPCI_BAR_ROM) )
>> >> continue;
>> >>
>> >> ?
>> >
>> > No, for the ROM case we only want to map/unmap the ROM, so that's the
>> > only thing added to the rangeset. For the non-ROM case Xen will also
>> > map/unmap the ROM if the enable bit is set.
>> >
>> > Your proposed code would always map/unmap the ROM into the p2m when
>> > the memory decoding bit is changed even if it's not enabled.
>>
>> I don't understand. Taking apart the conditional I've suggested,
>> and converting to human language:
>> - if the BAR is no mappable, continue
>> - if we want to deal with ROM (rom=true), if the BAR isn't ROM
>> or isn't enabled, continue
>
> With the current flow rom_enabled is set after the ROM BAR mappings
> are established, which means that when modify_bars is called with
> rom=true rom_enabled is not yet set, and using the logic above the
> mappings won't be created.
>
>> - if we want to deal with non-ROM (rom=false), if the BAR is ROM,
>> continue
>
> Xen also has to deal with the ROM if it's enabled when the memory
> decoding bit is toggled, hence in rom=false case the ROM also needs to
> be mapped/unampped if it's enabled.
>
> This dependency between the memory decoding bit and the ROM enable bit
> is quite convoluted TBH.
>
>> To me this is in line with the 2nd paragraph of your reply. It's not
>> in line with the first, which makes me wonder whether "rom" is
>> misnamed and wants to be "rom_only". Still, the question would
>> remain of why rom_enabled doesn't matter when the variable is
>> true.
>
> Yes, rom means rom_only (ie: ROM enable bit has been toggled and
> memory decoding bit is enabled). I assume you would prefer to change
> the name to rom_only.
Yes, and perhaps provide an abridged version of your explanation
above in a comment next to the conditional.
Jan
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |