Re: [kvm-unit-tests PATCH 04/14] pci: refactor init process to pci_dev_init()

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

 



On Fri, Oct 14, 2016 at 08:40:42PM +0800, Peter Xu wrote:
> pci_find_dev() is not sufficient for further tests for Intel IOMMU. This
> patch introduced pci_dev struct, as a abstract of a specific PCI device.
> 
> All the rest of current PCI APIs are changed to leverage the pci_dev
> struct.
> 
> x86/vmexit.c is the only user of the old PCI APIs. Changing it to use
> the new ones.
> 
> (Indentation is fixed from using 4 spaces into tab in pci.c)

We need to get Alex's series in and then revisit this. He's maintained
the API's use of a devid handle. It's possible a struct would be better,
but I'm not so sure. In any case we need to break this patch up in order
to see the goals step-by-step.

1) cleanup style - Alex's series does that already
2) replace the devid handle with struct pci_dev - should be done
everywhere or nowhere
3) simplify x86/vmexit's by making better use of the API
4) extend the API for IOMMU

I've added few more comments below.

> 
> Signed-off-by: Peter Xu <peterx@xxxxxxxxxx>
> ---
>  lib/pci.c    | 75 +++++++++++++++++++++++++++++++++++++++++-------------------
>  lib/pci.h    | 29 ++++++++++++++++++-----
>  x86/vmexit.c | 22 ++++--------------
>  3 files changed, 80 insertions(+), 46 deletions(-)
> 
> diff --git a/lib/pci.c b/lib/pci.c
> index 0058d70..ef0b02a 100644
> --- a/lib/pci.c
> +++ b/lib/pci.c
> @@ -7,37 +7,66 @@
>  #include "pci.h"
>  #include "asm/pci.h"
>  
> -/* Scan bus look for a specific device. Only bus 0 scanned for now. */
> -pcidevaddr_t pci_find_dev(uint16_t vendor_id, uint16_t device_id)
> +/*
> + * Scan bus look for a specific device. Only bus 0 scanned for now.
> + * After the scan, a pci_dev is returned with correct BAR information.
> + */
> +int pci_dev_init(pci_dev *dev, uint16_t vendor_id, uint16_t device_id)
> +{
> +	unsigned i;
> +	uint32_t id;
> +
> +	memset(dev, 0, sizeof(*dev));
> +
> +	for (i = 0; i < PCI_DEVFN_MAX; ++i) {
> +		id = pci_config_read(i, 0);

Hmm, pci_config_read still uses devid, but everything else now uses
pci_dev. I don't really like that inconsistency.

> +		if ((id & 0xFFFF) == vendor_id && (id >> 16) == device_id)
> +			break;
> +	}
> +
> +	if (i == PCI_DEVFN_MAX) {
> +		printf("PCI: failed init dev (vendor: 0x%04x, "
> +		       "device: 0x%04x)\n", vendor_id, device_id);
> +		return -1;
> +	}
> +
> +	dev->pci_addr = i;

but i is the devid, not the addr. Unless I misunderstand what 'addr' means
here.

> +	for (i = 0; i < PCI_BAR_NUM; i++) {
> +		if (!pci_bar_is_valid(dev, i))
> +			continue;
> +		dev->pci_bar[i] = pci_bar_addr(dev, i);
> +		printf("PCI: init dev 0x%04x BAR %d [%s] addr 0x%lx\n",
> +		       dev->pci_addr, i, pci_bar_is_memory(dev, i) ?
> +		       "MEM" : "IO", dev->pci_bar[i]);
> +	}
> +	dev->inited = true;
> +
> +	return 0;
> +}
> +
> +static inline uint32_t pci_config_read_bar(pci_dev *dev, int n)
>  {
> -    unsigned dev;
> -    for (dev = 0; dev < 256; ++dev) {
> -    uint32_t id = pci_config_read(dev, 0);
> -    if ((id & 0xFFFF) == vendor_id && (id >> 16) == device_id) {
> -        return dev;
> -    }
> -    }
> -    return PCIDEVADDR_INVALID;
> +	return pci_config_read(dev->pci_addr,
> +			       PCI_BASE_ADDRESS_0 + n * 4);
>  }
>  
> -unsigned long pci_bar_addr(pcidevaddr_t dev, int bar_num)
> +phys_addr_t pci_bar_addr(pci_dev *dev, int bar_num)
>  {
> -    uint32_t bar = pci_config_read(dev, PCI_BASE_ADDRESS_0 + bar_num * 4);
> -    if (bar & PCI_BASE_ADDRESS_SPACE_IO) {
> -        return bar & PCI_BASE_ADDRESS_IO_MASK;
> -    } else {
> -        return bar & PCI_BASE_ADDRESS_MEM_MASK;
> -    }
> +	uint32_t bar = pci_config_read_bar(dev, bar_num);
> +	if (bar & PCI_BASE_ADDRESS_SPACE_IO) {
> +		return bar & PCI_BASE_ADDRESS_IO_MASK;
> +	} else {
> +		return bar & PCI_BASE_ADDRESS_MEM_MASK;
> +	}
>  }
>  
> -bool pci_bar_is_memory(pcidevaddr_t dev, int bar_num)
> +bool pci_bar_is_memory(pci_dev *dev, int bar_num)
>  {
> -    uint32_t bar = pci_config_read(dev, PCI_BASE_ADDRESS_0 + bar_num * 4);
> -    return !(bar & PCI_BASE_ADDRESS_SPACE_IO);
> +	uint32_t bar = pci_config_read_bar(dev, bar_num);
> +	return !(bar & PCI_BASE_ADDRESS_SPACE_IO);
>  }
>  
> -bool pci_bar_is_valid(pcidevaddr_t dev, int bar_num)
> +bool pci_bar_is_valid(pci_dev *dev, int bar_num)
>  {
> -    uint32_t bar = pci_config_read(dev, PCI_BASE_ADDRESS_0 + bar_num * 4);
> -    return bar;
> +	return pci_config_read_bar(dev, bar_num);
>  }
> diff --git a/lib/pci.h b/lib/pci.h
> index 9160cfb..b8755ff 100644
> --- a/lib/pci.h
> +++ b/lib/pci.h
> @@ -14,10 +14,21 @@ typedef uint16_t pcidevaddr_t;
>  enum {
>      PCIDEVADDR_INVALID = 0xffff,
>  };
> -pcidevaddr_t pci_find_dev(uint16_t vendor_id, uint16_t device_id);
> -unsigned long pci_bar_addr(pcidevaddr_t dev, int bar_num);
> -bool pci_bar_is_memory(pcidevaddr_t dev, int bar_num);
> -bool pci_bar_is_valid(pcidevaddr_t dev, int bar_num);
> +
> +#define PCI_BAR_NUM                     (6)
> +#define PCI_DEVFN_MAX                   (256)
> +
> +struct pci_dev {
> +	bool inited;
> +	uint16_t pci_addr;
> +	phys_addr_t pci_bar[PCI_BAR_NUM];
> +};
> +typedef struct pci_dev pci_dev;
> +
> +int pci_dev_init(pci_dev *dev, uint16_t vendor_id, uint16_t device_id);
> +phys_addr_t pci_bar_addr(pci_dev *dev, int bar_num);
> +bool pci_bar_is_memory(pci_dev *dev, int bar_num);
> +bool pci_bar_is_valid(pci_dev *dev, int bar_num);
>  
>  /*
>   * pci-testdev is a driver for the pci-testdev qemu pci device. The
> @@ -27,8 +38,6 @@ bool pci_bar_is_valid(pcidevaddr_t dev, int bar_num);
>  #define PCI_VENDOR_ID_REDHAT		0x1b36
>  #define PCI_DEVICE_ID_REDHAT_TEST	0x0005
>  
> -#define PCI_TESTDEV_NUM_BARS		2

Why remove this? I could be used to test that we only find this many
BARs on the testdev, no?

> -
>  struct pci_test_dev_hdr {
>  	uint8_t  test;
>  	uint8_t  width;
> @@ -39,4 +48,12 @@ struct pci_test_dev_hdr {
>  	uint8_t  name[];
>  };
>  
> +enum pci_dma_dir {
> +	PCI_DMA_FROM_DEVICE = 0,
> +	PCI_DMA_TO_DEVICE,
> +};
> +typedef enum pci_dma_dir pci_dma_dir_t;
> +
> +typedef uint64_t iova_t;

stray changes

> +
>  #endif /* PCI_H */
> diff --git a/x86/vmexit.c b/x86/vmexit.c
> index c2e1e49..908d2dc 100644
> --- a/x86/vmexit.c
> +++ b/x86/vmexit.c
> @@ -371,8 +371,7 @@ int main(int ac, char **av)
>  {
>  	struct fadt_descriptor_rev1 *fadt;
>  	int i;
> -	unsigned long membar = 0;
> -	pcidevaddr_t pcidev;
> +	pci_dev dev;
>  
>  	smp_init();
>  	setup_vm();
> @@ -385,21 +384,10 @@ int main(int ac, char **av)
>  	pm_tmr_blk = fadt->pm_tmr_blk;
>  	printf("PM timer port is %x\n", pm_tmr_blk);
>  
> -	pcidev = pci_find_dev(PCI_VENDOR_ID_REDHAT, PCI_DEVICE_ID_REDHAT_TEST);
> -	if (pcidev != PCIDEVADDR_INVALID) {
> -		for (i = 0; i < PCI_TESTDEV_NUM_BARS; i++) {
> -			if (!pci_bar_is_valid(pcidev, i)) {
> -				continue;
> -			}
> -			if (pci_bar_is_memory(pcidev, i)) {
> -				membar = pci_bar_addr(pcidev, i);
> -				pci_test.memaddr = ioremap(membar, PAGE_SIZE);
> -			} else {
> -				pci_test.iobar = pci_bar_addr(pcidev, i);
> -			}
> -		}
> -		printf("pci-testdev at 0x%x membar %lx iobar %x\n",
> -		       pcidev, membar, pci_test.iobar);
> +	if (!pci_dev_init(&dev, PCI_VENDOR_ID_REDHAT,
> +			  PCI_DEVICE_ID_REDHAT_TEST)) {
> +		pci_test.memaddr = ioremap(dev.pci_bar[0], PAGE_SIZE);
> +		pci_test.iobar = dev.pci_bar[1];

Before we didn't require BAR0 to be MEM and BAR1 to be IO, now we do. It's
probably safe, but less flexible. I think we should at least provide
asserts that our assumptions are correct.

>  	}
>  
>  	for (i = 0; i < ARRAY_SIZE(tests); ++i)
> -- 
> 2.7.4
>

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