[PATCH 6/8] [Xilinx] xilinx_pcipr: Added Xilinx reconfigurable PCI endpoint driver.

Grant Likely grant.likely at secretlab.ca
Sat Jul 17 04:43:16 EST 2010


On Fri, Jul 16, 2010 at 12:13 PM, Stephen Neuendorffer
<stephen.neuendorffer at xilinx.com> wrote:
> This device has an internal bus which contains multiple devices, which
> are described in a device tree.
>
> Signed-off-by: Stephen Neuendorffer <stephen.neuendorffer at xilinx.com>

Looks sane to me.  A few comments below.

>
> ----
>
> This is probably still preliminary, although it actually works now.
> 1) It should probably correctly deallocate and free all the contained
> devices.
> 2) It should probably handle different device trees for multiple boards
> in the same system.  How to do this?
> ---
>  drivers/pci/Kconfig        |    9 ++
>  drivers/pci/Makefile       |    2 +
>  drivers/pci/xilinx_pcipr.c |  197 ++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 208 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/pci/xilinx_pcipr.c
>
> diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
> index 34ef70d..ec9b25d 100644
> --- a/drivers/pci/Kconfig
> +++ b/drivers/pci/Kconfig
> @@ -65,3 +65,12 @@ config PCI_IOAPIC
>        depends on ACPI
>        depends on HOTPLUG
>        default y
> +
> +config XILINX_PCIPR
> +       tristate "Xilinx OF-based PCI endpoint"
> +       depends on PCI
> +       select OF
> +       select OF_FLATTREE
> +        select OF_DEVICE

OF_DEVICE is automatically enabled now.  You don't need to select it.
It also looks like your patch has whitespace inconsistencies.

> +       help
> +         Enable support for Xilinx PCIPR endpoint
> \ No newline at end of file
> diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
> index 0b51857..ec44c21 100644
> --- a/drivers/pci/Makefile
> +++ b/drivers/pci/Makefile
> @@ -62,6 +62,8 @@ obj-$(CONFIG_PCI_SYSCALL) += syscall.o
>
>  obj-$(CONFIG_PCI_STUB) += pci-stub.o
>
> +obj-$(CONFIG_XILINX_PCIPR) += xilinx_pcipr.o
> +
>  ifeq ($(CONFIG_PCI_DEBUG),y)
>  EXTRA_CFLAGS += -DDEBUG
>  endif
> diff --git a/drivers/pci/xilinx_pcipr.c b/drivers/pci/xilinx_pcipr.c
> new file mode 100644
> index 0000000..80f8f1a
> --- /dev/null
> +++ b/drivers/pci/xilinx_pcipr.c
> @@ -0,0 +1,197 @@
> +/*
> + *  Copyright 2010 Xilinx, Inc.
> + *
> + */
> +
> +#include <linux/module.h>
> +#include <linux/types.h>
> +#include <linux/kernel.h>
> +#include <linux/pci.h>
> +#include <linux/ide.h>
> +#include <linux/init.h>
> +#include <linux/dmi.h>
> +#include <linux/firmware.h>
> +
> +#include <linux/of.h>
> +#include <linux/of_fdt.h>
> +#include <linux/of_platform.h>
> +
> +#include <linux/io.h>
> +
> +#define DRV_NAME "xilinx_pcipr"
> +
> +struct xilinx_pcipr_drvdata {
> +       struct device_node *child_nodes;
> +       struct firmware *fw_entry;
> +};
> +
> +/**
> + *     xilinx_pcipr_probe - Setup the endpoint
> + *     @dev: PCI device to set up
> + */
> +static int __devinit xilinx_pcipr_probe(struct pci_dev *pdev,
> +                                       const struct pci_device_id *id)
> +{
> +       int ret;
> +       struct xilinx_pcipr_drvdata *drvdata;
> +       resource_size_t start, len;
> +       struct property *ranges_prop;
> +       unsigned long *value;
> +       struct device_node *bus_node;
> +
> +       dev_dbg(&pdev->dev, "xilinx_pcipr_probe\n");
> +
> +       drvdata = kzalloc(sizeof(struct xilinx_pcipr_drvdata), GFP_KERNEL);
> +       if (!drvdata) {
> +               dev_err(&pdev->dev,
> +                       "Couldn't allocate device private record\n");
> +               ret = -ENOMEM;
> +               goto out;
> +       }
> +
> +       dev_set_drvdata(&pdev->dev, (void *)drvdata);
> +
> +       /*
> +        * Do some basic sanity checking..
> +        */
> +       if (pci_enable_device(pdev)) {
> +               ret = -EBUSY;
> +               goto free;
> +       }
> +
> +       /* Enable the board to bus master. */
> +       pci_set_master(pdev);
> +
> +       if (request_firmware(&drvdata->fw_entry,
> +                           "xilinx_pcipr.dtb", &pdev->dev)) {
> +               dev_err(&pdev->dev, "Couldn't get dtb\n");
> +               ret = -ENODEV;
> +               goto disable;
> +       }
> +
> +
> +       ret = pci_request_regions(pdev, "xilinx_pcipr");
> +       if (ret)
> +               goto release_dtb;
> +
> +       if (!pci_resource_start(pdev, 0)) {
> +               dev_printk(KERN_ERR, &pdev->dev, "No cardbus resource!\n");
> +               ret = -ENODEV;
> +               goto release;
> +       }
> +
> +
> +       /*
> +        * report the subsystem vendor and device for help debugging
> +        * the irq stuff...
> +        */
> +       dev_printk(KERN_INFO, &pdev->dev,
> +                  "Xilinx PCIPR bridge found [%04x:%04x]\n",
> +                  pdev->subsystem_vendor, pdev->subsystem_device);
> +
> +       /* Stuff the ranges property into the toplevel bus of the device
> +          tree, according to how the BARs are programmed */
> +       start = pci_resource_start(pdev, 0);
> +       len = pci_resource_len(pdev, 0);
> +
> +       dev_printk(KERN_INFO, &pdev->dev,
> +                  "Xilinx PCIPR bridge range %llx %llx",
> +                  (unsigned long long) start, (unsigned long long) len);
> +
> +       ranges_prop = kzalloc(sizeof(struct property), GFP_KERNEL);
> +       ranges_prop->value = kzalloc(sizeof(unsigned long) * 3, GFP_KERNEL);
> +       ranges_prop->name = "ranges";
> +       ranges_prop->length = sizeof(unsigned long) * 3;
> +       value = (unsigned long *)ranges_prop->value;
> +       /* FIXME: gotta get this from the bridge */
> +       value[0] = cpu_to_be32(0x80000000);
> +       value[1] = cpu_to_be32(start);
> +       value[2] = cpu_to_be32(len);
> +
> +       unflatten_partial_device_tree((unsigned long *)drvdata->fw_entry->data,
> +                                     &drvdata->child_nodes);
> +       of_node_get(drvdata->child_nodes);
> +       bus_node = of_find_node_by_name(drvdata->child_nodes, "plb");
> +       prom_add_property(bus_node, ranges_prop);
> +
> +       /* Generate child devices from the device tree */
> +       of_platform_bus_probe(drvdata->child_nodes, NULL, &pdev->dev);
> +
> +       pci_release_regions(pdev);
> +
> +       goto out; /* Success */
> +
> + release:
> +       pci_release_regions(pdev);
> +
> + release_dtb:
> +       release_firmware(drvdata->fw_entry);
> +
> + disable:
> +       pci_disable_device(pdev);
> + free:
> +       kfree(drvdata);
> +       dev_set_drvdata(&pdev->dev, NULL);
> + out:
> +       return ret;
> +}
> +
> +static int __devexit xilinx_pcipr_remove(struct pci_dev *pdev)
> +{
> +       struct device *dev = &pdev->dev;
> +       struct xilinx_pcipr_drvdata *drvdata = dev_get_drvdata(dev);
> +
> +       /* FIXME: Release the contained devices. There should probably
> +be a device-tree method to free a whole tree of devices, essentially
> +the inverse of of_platform_bus_probe
> +       */
> +
> +       release_firmware(drvdata->fw_entry);
> +       pci_disable_device(pdev);
> +       kfree(drvdata);
> +       dev_set_drvdata(dev, NULL);
> +       return 0;
> +}
> +
> +
> +static const struct pci_device_id xilinx_pcipr_ids[] = {
> +       { PCI_VDEVICE(XILINX, 0x0505), 0 },
> +       { 0, },
> +};
> +MODULE_DEVICE_TABLE(pci, xilinx_pcipr_ids);
> +
> +pci_ers_result_t *xilinx_pcipr_error_detected(struct pci_dev *pdev,
> +                                             enum pci_channel_state error) {
> +       dev_printk(KERN_INFO, &pdev->dev, "Error detected!\n");
> +       return PCI_ERS_RESULT_NEED_RESET;
> +}
> +
> +static struct pci_error_handlers xilinx_pcipr_error_handlers = {
> +       /* PCI bus error detected on this device */
> +       .error_detected = xilinx_pcipr_error_detected,
> +};
> +
> +static struct pci_driver  xilinx_pcipr_driver = {
> +       .name           = "XILINX_PCIPR",
> +       .id_table       = xilinx_pcipr_ids,
> +       .probe          = xilinx_pcipr_probe,
> +       .remove         = __devexit_p(xilinx_pcipr_remove),
> +       .err_handler    = &xilinx_pcipr_error_handlers,
> +};
> +
> +static int __init xilinx_pcipr_init(void)
> +{
> +       return ide_pci_register_driver(&xilinx_pcipr_driver);
> +}
> +
> +static void __exit xilinx_pcipr_exit(void)
> +{
> +       pci_unregister_driver(&xilinx_pcipr_driver);
> +}
> +
> +module_init(xilinx_pcipr_init);
> +module_exit(xilinx_pcipr_exit);
> +
> +MODULE_AUTHOR("Xilinx Research Labs");
> +MODULE_DESCRIPTION("PCI driver for PCI reconfigurable endpoint");
> +MODULE_LICENSE("GPL");
> --
> 1.5.6.6
>
>
>
> This email and any attachments are intended for the sole use of the named recipient(s) and contain(s) confidential information that may be proprietary, privileged or copyrighted under applicable law. If you are not the intended recipient, do not read, copy, or forward this email message or any attachments. Delete this email message and any attachments immediately.
>
>
>



-- 
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.


More information about the devicetree-discuss mailing list