static int grpci1_of_probe()

in kernel/leon_pci_grpci1.c [511:697]


static int grpci1_of_probe(struct platform_device *ofdev)
{
	struct grpci1_regs __iomem *regs;
	struct grpci1_priv *priv;
	int err, len;
	const int *tmp;
	u32 cfg, size, err_mask;
	struct resource *res;

	if (grpci1priv) {
		dev_err(&ofdev->dev, "only one GRPCI1 supported\n");
		return -ENODEV;
	}

	if (ofdev->num_resources < 3) {
		dev_err(&ofdev->dev, "not enough APB/AHB resources\n");
		return -EIO;
	}

	priv = devm_kzalloc(&ofdev->dev, sizeof(*priv), GFP_KERNEL);
	if (!priv) {
		dev_err(&ofdev->dev, "memory allocation failed\n");
		return -ENOMEM;
	}
	platform_set_drvdata(ofdev, priv);
	priv->dev = &ofdev->dev;

	/* find device register base address */
	res = platform_get_resource(ofdev, IORESOURCE_MEM, 0);
	regs = devm_ioremap_resource(&ofdev->dev, res);
	if (IS_ERR(regs))
		return PTR_ERR(regs);

	/*
	 * check that we're in Host Slot and that we can act as a Host Bridge
	 * and not only as target/peripheral.
	 */
	cfg = REGLOAD(regs->cfg_stat);
	if ((cfg & CFGSTAT_HOST) == 0) {
		dev_err(&ofdev->dev, "not in host system slot\n");
		return -EIO;
	}

	/* check that BAR1 support 256 MByte so that we can map kernel space */
	REGSTORE(regs->page1, 0xffffffff);
	size = ~REGLOAD(regs->page1) + 1;
	if (size < 0x10000000) {
		dev_err(&ofdev->dev, "BAR1 must be at least 256MByte\n");
		return -EIO;
	}

	/* hardware must support little-endian PCI (byte-twisting) */
	if ((REGLOAD(regs->page0) & PAGE0_BTEN) == 0) {
		dev_err(&ofdev->dev, "byte-twisting is required\n");
		return -EIO;
	}

	priv->regs = regs;
	priv->irq = irq_of_parse_and_map(ofdev->dev.of_node, 0);
	dev_info(&ofdev->dev, "host found at 0x%p, irq%d\n", regs, priv->irq);

	/* Find PCI Memory, I/O and Configuration Space Windows */
	priv->pci_area = ofdev->resource[1].start;
	priv->pci_area_end = ofdev->resource[1].end+1;
	priv->pci_io = ofdev->resource[2].start;
	priv->pci_conf = ofdev->resource[2].start + 0x10000;
	priv->pci_conf_end = priv->pci_conf + 0x10000;
	priv->pci_io_va = (unsigned long)ioremap(priv->pci_io, 0x10000);
	if (!priv->pci_io_va) {
		dev_err(&ofdev->dev, "unable to map PCI I/O area\n");
		return -EIO;
	}

	printk(KERN_INFO
		"GRPCI1: MEMORY SPACE [0x%08lx - 0x%08lx]\n"
		"        I/O    SPACE [0x%08lx - 0x%08lx]\n"
		"        CONFIG SPACE [0x%08lx - 0x%08lx]\n",
		priv->pci_area, priv->pci_area_end-1,
		priv->pci_io, priv->pci_conf-1,
		priv->pci_conf, priv->pci_conf_end-1);

	/*
	 * I/O Space resources in I/O Window mapped into Virtual Adr Space
	 * We never use low 4KB because some devices seem have problems using
	 * address 0.
	 */
	priv->info.io_space.name = "GRPCI1 PCI I/O Space";
	priv->info.io_space.start = priv->pci_io_va + 0x1000;
	priv->info.io_space.end = priv->pci_io_va + 0x10000 - 1;
	priv->info.io_space.flags = IORESOURCE_IO;

	/*
	 * grpci1 has no prefetchable memory, map everything as
	 * non-prefetchable memory
	 */
	priv->info.mem_space.name = "GRPCI1 PCI MEM Space";
	priv->info.mem_space.start = priv->pci_area;
	priv->info.mem_space.end = priv->pci_area_end - 1;
	priv->info.mem_space.flags = IORESOURCE_MEM;

	if (request_resource(&iomem_resource, &priv->info.mem_space) < 0) {
		dev_err(&ofdev->dev, "unable to request PCI memory area\n");
		err = -ENOMEM;
		goto err1;
	}

	if (request_resource(&ioport_resource, &priv->info.io_space) < 0) {
		dev_err(&ofdev->dev, "unable to request PCI I/O area\n");
		err = -ENOMEM;
		goto err2;
	}

	/* setup maximum supported PCI buses */
	priv->info.busn.name = "GRPCI1 busn";
	priv->info.busn.start = 0;
	priv->info.busn.end = 15;

	grpci1priv = priv;

	/* Initialize hardware */
	grpci1_hw_init(priv);

	/*
	 * Get PCI Interrupt to System IRQ mapping and setup IRQ handling
	 * Error IRQ. All PCI and PCI-Error interrupts are shared using the
	 * same system IRQ.
	 */
	leon_update_virq_handling(priv->irq, grpci1_pci_flow_irq, "pcilvl", 0);

	priv->irq_map[0] = grpci1_build_device_irq(1);
	priv->irq_map[1] = grpci1_build_device_irq(2);
	priv->irq_map[2] = grpci1_build_device_irq(3);
	priv->irq_map[3] = grpci1_build_device_irq(4);
	priv->irq_err = grpci1_build_device_irq(5);

	printk(KERN_INFO "        PCI INTA..D#: IRQ%d, IRQ%d, IRQ%d, IRQ%d\n",
		priv->irq_map[0], priv->irq_map[1], priv->irq_map[2],
		priv->irq_map[3]);

	/* Enable IRQs on LEON IRQ controller */
	err = devm_request_irq(&ofdev->dev, priv->irq, grpci1_jump_interrupt, 0,
				"GRPCI1_JUMP", priv);
	if (err) {
		dev_err(&ofdev->dev, "ERR IRQ request failed: %d\n", err);
		goto err3;
	}

	/* Setup IRQ handler for access errors */
	err = devm_request_irq(&ofdev->dev, priv->irq_err,
				grpci1_err_interrupt, IRQF_SHARED, "GRPCI1_ERR",
				priv);
	if (err) {
		dev_err(&ofdev->dev, "ERR VIRQ request failed: %d\n", err);
		goto err3;
	}

	tmp = of_get_property(ofdev->dev.of_node, "all_pci_errors", &len);
	if (tmp && (len == 4)) {
		priv->pci_err_mask = ALL_PCI_ERRORS;
		err_mask = IRQ_ALL_ERRORS << IRQ_MASK_BIT;
	} else {
		priv->pci_err_mask = DEF_PCI_ERRORS;
		err_mask = IRQ_DEF_ERRORS << IRQ_MASK_BIT;
	}

	/*
	 * Enable Error Interrupts. PCI interrupts are unmasked once request_irq
	 * is called by the PCI Device drivers
	 */
	REGSTORE(regs->irq, err_mask);

	/* Init common layer and scan buses */
	priv->info.ops = &grpci1_ops;
	priv->info.map_irq = grpci1_map_irq;
	leon_pci_init(ofdev, &priv->info);

	return 0;

err3:
	release_resource(&priv->info.io_space);
err2:
	release_resource(&priv->info.mem_space);
err1:
	iounmap((void __iomem *)priv->pci_io_va);
	grpci1priv = NULL;
	return err;
}