lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Tue, 11 Nov 2014 12:29:01 +0000
From:	Lorenzo Pieralisi <lorenzo.pieralisi@....com>
To:	Ming Lei <ming.lei@...onical.com>
Cc:	Bjorn Helgaas <bhelgaas@...gle.com>,
	Will Deacon <Will.Deacon@....com>,
	"linux-kernel@...r.kernel.org" <linux-kernel@...r.kernel.org>,
	"linux-pci@...r.kernel.org" <linux-pci@...r.kernel.org>,
	Rob Herring <robh+dt@...nel.org>,
	alvise rigo <a.rigo@...tualopensystems.com>
Subject: Re: [PATCH] pci: generic host: make it more generic

On Tue, Nov 11, 2014 at 10:33:59AM +0000, Ming Lei wrote:
> This patch converts the generic host controller driver
> into a more generic one, and basically don't need
> platform's pcibios support, and use DT based generic
> APIs to parse resource and remap IO port.
> 
> This patch has been tested on both ARMv7 and ARMv8
> VM, and in theroy it should support other ARCHs too.

In theory, yes.

> With this patch, virtio PCI block, network and scsi devices
> can work well on ARMv7 and ARMv8 VM.
> 
> QEMU needs below patches for runing the test:
> 
> - Rob Herring's "Add generic PCI host device" patches
> 	http://lists.gnu.org/archive/html/qemu-devel/2014-06/msg03482.html
> 	http://lists.gnu.org/archive/html/qemu-devel/2014-06/msg03483.html
> - Alvise Rigo's "Add Generic PCI host device update"
> 	http://marc.info/?l=qemu-devel&m=140506329920172&w=2
> 
> For ARMv8, cpu model of "host" and "cortex-a57" is missed
> in Alvise Rigo's patchset, otherwise ARM64 VM can't boot.
> 
> All these QEMU patches can be found in below tree:
> 
> 	http://kernel.ubuntu.com/git?p=ming/qemu.git;a=shortlog;h=refs/heads/arm64-pci-test
> 
> Signed-off-by: Ming Lei <ming.lei@...onical.com>
> ---
>  drivers/pci/host/Kconfig            |    2 +-
>  drivers/pci/host/pci-host-generic.c |  196 +++++++++++------------------------
>  2 files changed, 63 insertions(+), 135 deletions(-)
> 
> diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
> index 3dc25fa..885034d 100644
> --- a/drivers/pci/host/Kconfig
> +++ b/drivers/pci/host/Kconfig
> @@ -50,7 +50,7 @@ config PCI_RCAR_GEN2_PCIE
>  
>  config PCI_HOST_GENERIC
>  	bool "Generic PCI host controller"
> -	depends on ARM && OF
> +	depends on OF
>  	help
>  	  Say Y here if you want to support a simple generic PCI host
>  	  controller, such as the one emulated by kvmtool.
> diff --git a/drivers/pci/host/pci-host-generic.c b/drivers/pci/host/pci-host-generic.c
> index 3d2076f..00d0ca3 100644
> --- a/drivers/pci/host/pci-host-generic.c
> +++ b/drivers/pci/host/pci-host-generic.c
> @@ -44,12 +44,14 @@ struct gen_pci {
>  	struct list_head			resources;
>  };
>  
> +/* fake sysdata for cheating ARCH's pcibios code */
> +static char	gen_sysdata[256];

I take this as a joke and it does not make me laugh.

>  static void __iomem *gen_pci_map_cfg_bus_cam(struct pci_bus *bus,
>  					     unsigned int devfn,
>  					     int where)
>  {
> -	struct pci_sys_data *sys = bus->sysdata;
> -	struct gen_pci *pci = sys->private_data;
> +	struct gen_pci *pci = dev_get_drvdata(bus->dev.parent->parent);
>  	resource_size_t idx = bus->number - pci->cfg.bus_range.start;
>  
>  	return pci->cfg.win[idx] + ((devfn << 8) | where);
> @@ -64,8 +66,7 @@ static void __iomem *gen_pci_map_cfg_bus_ecam(struct pci_bus *bus,
>  					      unsigned int devfn,
>  					      int where)
>  {
> -	struct pci_sys_data *sys = bus->sysdata;
> -	struct gen_pci *pci = sys->private_data;
> +	struct gen_pci *pci = dev_get_drvdata(bus->dev.parent->parent);
>  	resource_size_t idx = bus->number - pci->cfg.bus_range.start;
>  
>  	return pci->cfg.win[idx] + ((devfn << 12) | where);
> @@ -80,8 +81,7 @@ static int gen_pci_config_read(struct pci_bus *bus, unsigned int devfn,
>  				int where, int size, u32 *val)
>  {
>  	void __iomem *addr;
> -	struct pci_sys_data *sys = bus->sysdata;
> -	struct gen_pci *pci = sys->private_data;
> +	struct gen_pci *pci = dev_get_drvdata(bus->dev.parent->parent);
>  
>  	addr = pci->cfg.ops->map_bus(bus, devfn, where);
>  
> @@ -103,8 +103,7 @@ static int gen_pci_config_write(struct pci_bus *bus, unsigned int devfn,
>  				 int where, int size, u32 val)
>  {
>  	void __iomem *addr;
> -	struct pci_sys_data *sys = bus->sysdata;
> -	struct gen_pci *pci = sys->private_data;
> +	struct gen_pci *pci = dev_get_drvdata(bus->dev.parent->parent);
>  
>  	addr = pci->cfg.ops->map_bus(bus, devfn, where);
>  
> @@ -138,45 +137,6 @@ static const struct of_device_id gen_pci_of_match[] = {
>  };
>  MODULE_DEVICE_TABLE(of, gen_pci_of_match);
>  
> -static int gen_pci_calc_io_offset(struct device *dev,
> -				  struct of_pci_range *range,
> -				  struct resource *res,
> -				  resource_size_t *offset)
> -{
> -	static atomic_t wins = ATOMIC_INIT(0);
> -	int err, idx, max_win;
> -	unsigned int window;
> -
> -	if (!PAGE_ALIGNED(range->cpu_addr))
> -		return -EINVAL;
> -
> -	max_win = (IO_SPACE_LIMIT + 1) / SZ_64K;
> -	idx = atomic_inc_return(&wins);
> -	if (idx > max_win)
> -		return -ENOSPC;
> -
> -	window = (idx - 1) * SZ_64K;
> -	err = pci_ioremap_io(window, range->cpu_addr);
> -	if (err)
> -		return err;
> -
> -	of_pci_range_to_resource(range, dev->of_node, res);
> -	res->start = window;
> -	res->end = res->start + range->size - 1;
> -	*offset = window - range->pci_addr;
> -	return 0;
> -}
> -
> -static int gen_pci_calc_mem_offset(struct device *dev,
> -				   struct of_pci_range *range,
> -				   struct resource *res,
> -				   resource_size_t *offset)
> -{
> -	of_pci_range_to_resource(range, dev->of_node, res);
> -	*offset = range->cpu_addr - range->pci_addr;
> -	return 0;
> -}
> -
>  static void gen_pci_release_of_pci_ranges(struct gen_pci *pci)
>  {
>  	struct pci_host_bridge_window *win;
> @@ -187,72 +147,6 @@ static void gen_pci_release_of_pci_ranges(struct gen_pci *pci)
>  	pci_free_resource_list(&pci->resources);
>  }
>  
> -static int gen_pci_parse_request_of_pci_ranges(struct gen_pci *pci)
> -{
> -	struct of_pci_range range;
> -	struct of_pci_range_parser parser;
> -	int err, res_valid = 0;
> -	struct device *dev = pci->host.dev.parent;
> -	struct device_node *np = dev->of_node;
> -
> -	if (of_pci_range_parser_init(&parser, np)) {
> -		dev_err(dev, "missing \"ranges\" property\n");
> -		return -EINVAL;
> -	}
> -
> -	for_each_of_pci_range(&parser, &range) {
> -		struct resource *parent, *res;
> -		resource_size_t offset;
> -		u32 restype = range.flags & IORESOURCE_TYPE_BITS;
> -
> -		res = devm_kmalloc(dev, sizeof(*res), GFP_KERNEL);
> -		if (!res) {
> -			err = -ENOMEM;
> -			goto out_release_res;
> -		}
> -
> -		switch (restype) {
> -		case IORESOURCE_IO:
> -			parent = &ioport_resource;
> -			err = gen_pci_calc_io_offset(dev, &range, res, &offset);
> -			break;
> -		case IORESOURCE_MEM:
> -			parent = &iomem_resource;
> -			err = gen_pci_calc_mem_offset(dev, &range, res, &offset);
> -			res_valid |= !(res->flags & IORESOURCE_PREFETCH || err);
> -			break;
> -		default:
> -			err = -EINVAL;
> -			continue;
> -		}
> -
> -		if (err) {
> -			dev_warn(dev,
> -				 "error %d: failed to add resource [type 0x%x, %lld bytes]\n",
> -				 err, restype, range.size);
> -			continue;
> -		}
> -
> -		err = request_resource(parent, res);
> -		if (err)
> -			goto out_release_res;
> -
> -		pci_add_resource_offset(&pci->resources, res, offset);
> -	}
> -
> -	if (!res_valid) {
> -		dev_err(dev, "non-prefetchable memory resource required\n");
> -		err = -EINVAL;
> -		goto out_release_res;
> -	}
> -
> -	return 0;
> -
> -out_release_res:
> -	gen_pci_release_of_pci_ranges(pci);
> -	return err;
> -}
> -
>  static int gen_pci_parse_map_cfg_windows(struct gen_pci *pci)
>  {
>  	int err;
> @@ -305,16 +199,33 @@ static int gen_pci_parse_map_cfg_windows(struct gen_pci *pci)
>  			return -ENOMEM;
>  	}
>  
> -	/* Register bus resource */
> -	pci_add_resource(&pci->resources, bus_range);
>  	return 0;
>  }
>  
> -static int gen_pci_setup(int nr, struct pci_sys_data *sys)
> +static int gen_pci_map_ranges(struct list_head *res,
> +		resource_size_t io_base)
>  {
> -	struct gen_pci *pci = sys->private_data;
> -	list_splice_init(&pci->resources, &sys->resources);
> -	return 1;
> +	struct pci_host_bridge_window *window;
> +	int ret;
> +
> +	list_for_each_entry(window, res, list) {
> +		struct resource *res = window->res;
> +		u64 restype = resource_type(res);
> +
> +		switch (restype) {
> +		case IORESOURCE_IO:
> +			ret = pci_remap_iospace(res, io_base);
> +			if (ret < 0)
> +				return ret;
> +			break;
> +		case IORESOURCE_MEM:
> +		case IORESOURCE_BUS:
> +			break;
> +		default:
> +			return -EINVAL;
> +		}
> +	}
> +	return 0;
>  }

http://lists.infradead.org/pipermail/linux-arm-kernel/2014-October/296535.html

Patch above is already queued and applies most of the changes you have posted
above.

>  static int gen_pci_probe(struct platform_device *pdev)
> @@ -325,14 +236,11 @@ static int gen_pci_probe(struct platform_device *pdev)
>  	const int *prop;
>  	struct device *dev = &pdev->dev;
>  	struct device_node *np = dev->of_node;
> +	resource_size_t iobase = 0;
>  	struct gen_pci *pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
> -	struct hw_pci hw = {
> -		.nr_controllers	= 1,
> -		.private_data	= (void **)&pci,
> -		.setup		= gen_pci_setup,
> -		.map_irq	= of_irq_parse_and_map_pci,
> -		.ops		= &gen_pci_ops,
> -	};
> +	struct pci_bus *bus;
> +	struct pci_dev *pci_dev = NULL;
> +	bool probe_only = false;
>  
>  	if (!pci)
>  		return -ENOMEM;
> @@ -346,9 +254,9 @@ static int gen_pci_probe(struct platform_device *pdev)
>  	prop = of_get_property(of_chosen, "linux,pci-probe-only", NULL);
>  	if (prop) {
>  		if (*prop)
> -			pci_add_flags(PCI_PROBE_ONLY);
> +			probe_only = true;
>  		else
> -			pci_clear_flags(PCI_PROBE_ONLY);
> +			probe_only = false;
>  	}

How can this possibly work ? If firmware assigns resources, they
should not be enabled, and this is done in pcibios code by checking
the PCI_PROBE_ONLY flag (pcibios_enable_device()).
Now you are removing the flag, how can pcibios_enable_device() work on
platforms that are PROBE_ONLY ? I do not see any additional patch, so I
am confused.

>  
>  	of_id = of_match_node(gen_pci_of_match, np);
> @@ -357,20 +265,40 @@ static int gen_pci_probe(struct platform_device *pdev)
>  	INIT_LIST_HEAD(&pci->host.windows);
>  	INIT_LIST_HEAD(&pci->resources);
>  
> -	/* Parse our PCI ranges and request their resources */
> -	err = gen_pci_parse_request_of_pci_ranges(pci);
> +	err = of_pci_get_host_bridge_resources(np, 0, 0xff,
> +			&pci->resources, &iobase);
>  	if (err)
>  		return err;
>  
>  	/* Parse and map our Configuration Space windows */
>  	err = gen_pci_parse_map_cfg_windows(pci);
> -	if (err) {
> -		gen_pci_release_of_pci_ranges(pci);
> -		return err;
> +	if (err)
> +		goto fail;
> +
> +	err = gen_pci_map_ranges(&pci->resources, iobase);
> +	if (err)
> +		goto fail;
> +
> +	err = -ENOMEM;
> +	platform_set_drvdata(pdev, pci);
> +	bus = pci_scan_root_bus(dev, 0, &gen_pci_ops, gen_sysdata,
> +				&pci->resources);
> +	if (!bus)
> +		goto fail;
> +
> +	for_each_pci_dev(pci_dev)
> +		pci_dev->irq = of_irq_parse_and_map_pci(pci_dev, 0, 0);
> +
> +	if (!probe_only) {
> +		pci_bus_size_bridges(bus);
> +		pci_bus_assign_resources(bus);
> +		pci_bus_add_devices(bus);
>  	}

Do you realize that pci_scan_root_bus() already calls pci_bus_add_devices() ?
On top of that:

+	if (!probe_only) {
+		pci_bus_size_bridges(bus);
+		pci_bus_assign_resources(bus);
+		pci_bus_add_devices(bus);

Should be called in pci_scan_root_bus() before pci_bus_add_devices(), if
things are working for you at the moment it is out of sheer chance (and
unfortunately that's the case for other host controllers IMO).

I am working on adding the code above to pci_scan_root_bus() implementation
this is a generic issue that we need to solve, there are already patches
on the list to remove the dependency on pci_sys_data (I mean properly)
and move the code to generic pci_scan_root_bus() implementation.

Overall, we are already working to achieve what this patch is trying to
achieve, I will keep you posted.

Thanks,
Lorenzo
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ