Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2009-2016 Cavium, Inc.
0004  */
0005 
0006 #include <linux/acpi.h>
0007 #include <linux/gfp.h>
0008 #include <linux/io.h>
0009 #include <linux/module.h>
0010 #include <linux/of_address.h>
0011 #include <linux/of_mdio.h>
0012 #include <linux/pci.h>
0013 #include <linux/phy.h>
0014 
0015 #include "mdio-cavium.h"
0016 
0017 struct thunder_mdiobus_nexus {
0018     void __iomem *bar0;
0019     struct cavium_mdiobus *buses[4];
0020 };
0021 
0022 static int thunder_mdiobus_pci_probe(struct pci_dev *pdev,
0023                      const struct pci_device_id *ent)
0024 {
0025     struct device_node *node;
0026     struct fwnode_handle *fwn;
0027     struct thunder_mdiobus_nexus *nexus;
0028     int err;
0029     int i;
0030 
0031     nexus = devm_kzalloc(&pdev->dev, sizeof(*nexus), GFP_KERNEL);
0032     if (!nexus)
0033         return -ENOMEM;
0034 
0035     pci_set_drvdata(pdev, nexus);
0036 
0037     err = pcim_enable_device(pdev);
0038     if (err) {
0039         dev_err(&pdev->dev, "Failed to enable PCI device\n");
0040         pci_set_drvdata(pdev, NULL);
0041         return err;
0042     }
0043 
0044     err = pci_request_regions(pdev, KBUILD_MODNAME);
0045     if (err) {
0046         dev_err(&pdev->dev, "pci_request_regions failed\n");
0047         goto err_disable_device;
0048     }
0049 
0050     nexus->bar0 = pcim_iomap(pdev, 0, pci_resource_len(pdev, 0));
0051     if (!nexus->bar0) {
0052         err = -ENOMEM;
0053         goto err_release_regions;
0054     }
0055 
0056     i = 0;
0057     device_for_each_child_node(&pdev->dev, fwn) {
0058         struct resource r;
0059         struct mii_bus *mii_bus;
0060         struct cavium_mdiobus *bus;
0061         union cvmx_smix_en smi_en;
0062 
0063         /* If it is not an OF node we cannot handle it yet, so
0064          * exit the loop.
0065          */
0066         node = to_of_node(fwn);
0067         if (!node)
0068             break;
0069 
0070         err = of_address_to_resource(node, 0, &r);
0071         if (err) {
0072             dev_err(&pdev->dev,
0073                 "Couldn't translate address for \"%pOFn\"\n",
0074                 node);
0075             break;
0076         }
0077 
0078         mii_bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*bus));
0079         if (!mii_bus)
0080             break;
0081         bus = mii_bus->priv;
0082         bus->mii_bus = mii_bus;
0083 
0084         nexus->buses[i] = bus;
0085         i++;
0086 
0087         bus->register_base = nexus->bar0 +
0088             r.start - pci_resource_start(pdev, 0);
0089 
0090         smi_en.u64 = 0;
0091         smi_en.s.en = 1;
0092         oct_mdio_writeq(smi_en.u64, bus->register_base + SMI_EN);
0093         bus->mii_bus->name = KBUILD_MODNAME;
0094         snprintf(bus->mii_bus->id, MII_BUS_ID_SIZE, "%llx", r.start);
0095         bus->mii_bus->parent = &pdev->dev;
0096         bus->mii_bus->read = cavium_mdiobus_read;
0097         bus->mii_bus->write = cavium_mdiobus_write;
0098 
0099         err = of_mdiobus_register(bus->mii_bus, node);
0100         if (err)
0101             dev_err(&pdev->dev, "of_mdiobus_register failed\n");
0102 
0103         dev_info(&pdev->dev, "Added bus at %llx\n", r.start);
0104         if (i >= ARRAY_SIZE(nexus->buses))
0105             break;
0106     }
0107     return 0;
0108 
0109 err_release_regions:
0110     pci_release_regions(pdev);
0111 
0112 err_disable_device:
0113     pci_set_drvdata(pdev, NULL);
0114     return err;
0115 }
0116 
0117 static void thunder_mdiobus_pci_remove(struct pci_dev *pdev)
0118 {
0119     int i;
0120     struct thunder_mdiobus_nexus *nexus = pci_get_drvdata(pdev);
0121 
0122     for (i = 0; i < ARRAY_SIZE(nexus->buses); i++) {
0123         struct cavium_mdiobus *bus = nexus->buses[i];
0124 
0125         if (!bus)
0126             continue;
0127 
0128         mdiobus_unregister(bus->mii_bus);
0129         oct_mdio_writeq(0, bus->register_base + SMI_EN);
0130     }
0131     pci_release_regions(pdev);
0132     pci_set_drvdata(pdev, NULL);
0133 }
0134 
0135 static const struct pci_device_id thunder_mdiobus_id_table[] = {
0136     { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, 0xa02b) },
0137     { 0, } /* End of table. */
0138 };
0139 MODULE_DEVICE_TABLE(pci, thunder_mdiobus_id_table);
0140 
0141 static struct pci_driver thunder_mdiobus_driver = {
0142     .name = KBUILD_MODNAME,
0143     .id_table = thunder_mdiobus_id_table,
0144     .probe = thunder_mdiobus_pci_probe,
0145     .remove = thunder_mdiobus_pci_remove,
0146 };
0147 
0148 module_pci_driver(thunder_mdiobus_driver);
0149 
0150 MODULE_DESCRIPTION("Cavium ThunderX MDIO bus driver");
0151 MODULE_LICENSE("GPL v2");