Re: [kvm-unit-tests PATCH v4 04/12] pci: Rework pci_bar_addr()

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

 



On Tue, Jun 07, 2016 at 10:00:42PM +0200, Alexander Gordeev wrote:
> On Tue, Jun 07, 2016 at 04:08:22PM +0200, Andrew Jones wrote:
> > On Tue, Jun 07, 2016 at 12:33:54PM +0200, Alexander Gordeev wrote:
> > > On Tue, Jun 07, 2016 at 09:03:18AM +0200, Andrew Jones wrote:
> > > > On Tue, Jun 07, 2016 at 08:38:55AM +0200, Alexander Gordeev wrote:
> > > > > On Mon, Jun 06, 2016 at 04:12:03PM +0200, Andrew Jones wrote:
> > > > > > > +phys_addr_t pci_bar_size(pcidevaddr_t dev, int bar_num)
> > > > > > >  {
> > > > > > >  	uint32_t bar = pci_config_readl(dev, PCI_BASE_ADDRESS_0 + bar_num * 4);
> > > > > > > +	phys_addr_t size = (int32_t)pci_bar_size32(dev, bar_num);
> > > > > > > +	phys_addr_t mask = (int32_t)pci_bar_mask(bar);
> > > > > > >  
> > > > > > > -	if (bar & PCI_BASE_ADDRESS_SPACE_IO)
> > > > > > > -		return bar & PCI_BASE_ADDRESS_IO_MASK;
> > > > > > > -	else
> > > > > > > -		return bar & PCI_BASE_ADDRESS_MEM_MASK;
> > > > > > > +	if (pci_bar_is64(dev, bar_num)) {
> > > > > > > +		uint32_t size_high = pci_bar_size32(dev, bar_num + 1);
> > > > > > > +		size = ((phys_addr_t)size_high << 32) | (uint32_t)size;
> > > > > > > +	}
> > > > > > > +
> > > > > > > +	return (~(size & mask)) + 1;
> > > > > > 
> > > > > > All this casting of size and mask is pointless. Please rework it
> > > > > > similar to what I did above.
> > > > > 
> > > > > This is the most compact and straight variant I was able to come up with:
> > > > > 
> > > > > 	uint32_t bar = pci_bar_get(dev, bar_num);
> > > > > 	phys_addr_t size = (int32_t)pci_bar_size32(dev, bar_num);
> > > > 
> > > > But this is wrong. If your 32-bit size was 0x80000000, then you now
> > > > say it's 0xffffffff80000000.
> > > 
> > > Hmm.. I am either terribly missing the point or we are on different
> > > pages.
> > 
> > Let's make sure I know what the function is supposed to do.
> > 
> > Based on your comment explaining how to get the PCI bar size,
> > it sounds like we should do these steps; let's assume a device
> > needs size=0x200000, and is 32-bit
> 
> I am not quite sure what barsz=0x00000000 at read-write1s-dance	

barsz is initialized to zero in the sequence in order to start the
variable descriptions with something, but it's not necessary to do
so with real code.

> phase is, but otherwise it seems correct to me (well may be a nit -
> the 32-bit variant denoted 64-bit mmio).

Not sure what you mean, but it doesn't matter for this :-)

> 
> >  read-write1s-dance	barsz=0x00000000
> >  readl			barsz=0xffe0000c
> >  mask			barsz=0xffe00000
> > 
> >  barsz = ~barsz + 1	barsz=0x00200000
> > 
> > Now let's say it's 64-bit
> > 
> >  read-write1s-dance	barsz_lo=0x00000000
> >  readl			barsz_lo=0xffe0000c
> >  mask			barsz_lo=0xffe00000
> >  read-write1s-dance	barsz_hi=0x00000000
> >  readl			barsz_hi=0xffffffff
> >  <upper 32-bit mask is 0xffffffff, so don't bother masking at all>
> > 
> >  barsz = ~((phys_addr_t)barsz_hi << 32 | barsz_lo) + 1 (barsz=0x200000)
> > 
> > So you need 5 functions
> > 
> > uint32_t get_mask(int bar)
> > {
> > ...
> > }
> > 
> > uint32_t read_dance(int bar)
> > {
> >   read-write1s-dance
> >   return readl
> > }
> > 
> > uint32_t get_size32(int bar)
> > {
> >   uint32_t size = read_dance(bar) & get_mask(bar);
> >   return ~size + 1;
> > }
> > 
> > uint64_t get_size64(int bar)
> > {
> >   uint64_t size = read_dance(bar) & get_mask(bar);
> >   uint64_t size_hi = read_dance(bar + 1);
> > 
> >   size |= size_hi << 32;
> >   return ~size + 1;
> > }
> > 
> > uint64_t get_size(int bar)
> > {
> >   return bar_size(bar) == BAR64 ? get_size64(bar) : get_size32(bar);
> > }
> 
> If the above is a pseudo code or you want me to rework using these
> functions?

Yes and no. You can do what you like, but pci_bar_size32 should
return a size (like my get_size32), not a 2's complement of size,
otherwise the name is wrong.

> If not, below is how it could look like.
> 
> Also, looking at your get_size() I noticed a bug in my version :-)
> when read_dance() is followed by readl() returns zero - that means no
> (more) BAR(s).
> 
> phys_addr_t pci_bar_size(pcidevaddr_t dev, int bar_num)
> {
> 	uint32_t size;
> 	uint32_t bar;
> 
> 	size = pci_bar_size32(dev, bar_num);
> 	if (!size)
> 		return 0;

Should callers ever call pci_bar_size on a bar_num that will result
in zero, "no more BARs"? If not, then you can assert here. Otherwise
will all callers know what zero means, and check for it?

> 
> 	bar = pci_bar_get(dev, bar_num);
> 	size &= pci_bar_mask(bar);
> 
> 	if (pci_bar_is64(dev, bar_num)) {
> 		phys_addr_t size64 = pci_bar_size32(dev, bar_num + 1);
> 		size64 = (size64 << 32) | size;
> 
> 		return ~size64 + 1;
> 	} else {
> 		return ~size + 1;
> 	}
> }
>

Otherwise I think it's right.

Thanks,
drew
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux