diff mbox

net: mdio-octeon: Add PCI driver binding.

Message ID 1442968896-30776-1-git-send-email-ddaney.cavm@gmail.com
State Under Review, archived
Headers show

Commit Message

David Daney Sept. 23, 2015, 12:41 a.m. UTC
From: David Daney <david.daney@cavium.com>

When the Cavium mdio-octeon devices appear in the Thunder family of
arm64 based SoCs, they show up as PCI devices.  Add PCI driver
wrapping so the driver is bound in the standard PCI device scan.

When in this form, a single PCI device may have more than a single
bus, we call this a "nexus" of buses.  The standard firmware
device_for_each_child_node() iterator is used to find the individual
buses underneath the "nexus".

Update the device tree binding documentation for the new PCI driver
binding.

Signed-off-by: David Daney <david.daney@cavium.com>
---
 .../devicetree/bindings/net/cavium-mdio.txt        |  61 +++++++-
 drivers/net/phy/mdio-octeon.c                      | 159 +++++++++++++++++++--
 2 files changed, 209 insertions(+), 11 deletions(-)

Comments

David Miller Sept. 24, 2015, 9:52 p.m. UTC | #1
From: David Daney <ddaney.cavm@gmail.com>

Date: Tue, 22 Sep 2015 17:41:36 -0700

> From: David Daney <david.daney@cavium.com>

> 

> When the Cavium mdio-octeon devices appear in the Thunder family of

> arm64 based SoCs, they show up as PCI devices.  Add PCI driver

> wrapping so the driver is bound in the standard PCI device scan.

> 

> When in this form, a single PCI device may have more than a single

> bus, we call this a "nexus" of buses.  The standard firmware

> device_for_each_child_node() iterator is used to find the individual

> buses underneath the "nexus".

> 

> Update the device tree binding documentation for the new PCI driver

> binding.

> 

> Signed-off-by: David Daney <david.daney@cavium.com>


This patch breaks the build:

  CC [M]  drivers/net/phy/mdio-octeon.o
In file included from drivers/net/phy/mdio-octeon.c:13:0:
include/linux/module.h:128:27: error: redefinition of ‘__inittest’
  static inline initcall_t __inittest(void)  \
                           ^
include/linux/device.h:1321:1: note: in expansion of macro ‘module_init’
 module_init(__driver##_init); \
 ^
include/linux/pci.h:1192:2: note: in expansion of macro ‘module_driver’
  module_driver(__pci_driver, pci_register_driver, \
  ^
drivers/net/phy/mdio-octeon.c:513:1: note: in expansion of macro ‘module_pci_driver’
 module_pci_driver(thunder_mdiobus_driver);
 ^
include/linux/module.h:128:27: note: previous definition of ‘__inittest’ was here
  static inline initcall_t __inittest(void)  \
                           ^
include/linux/device.h:1321:1: note: in expansion of macro ‘module_init’
 module_init(__driver##_init); \
 ^
include/linux/platform_device.h:222:2: note: in expansion of macro ‘module_driver’
  module_driver(__platform_driver, platform_driver_register, \
  ^
drivers/net/phy/mdio-octeon.c:373:1: note: in expansion of macro ‘module_platform_driver’
 module_platform_driver(octeon_mdiobus_driver);
 ^
include/linux/module.h:130:6: error: redefinition of ‘init_module’
  int init_module(void) __attribute__((alias(#initfn)));
      ^
include/linux/device.h:1321:1: note: in expansion of macro ‘module_init’
 module_init(__driver##_init); \
 ^
include/linux/pci.h:1192:2: note: in expansion of macro ‘module_driver’
  module_driver(__pci_driver, pci_register_driver, \
  ^
drivers/net/phy/mdio-octeon.c:513:1: note: in expansion of macro ‘module_pci_driver’
 module_pci_driver(thunder_mdiobus_driver);
 ^
include/linux/module.h:130:6: note: previous definition of ‘init_module’ was here
  int init_module(void) __attribute__((alias(#initfn)));
      ^
include/linux/device.h:1321:1: note: in expansion of macro ‘module_init’
 module_init(__driver##_init); \
 ^
include/linux/platform_device.h:222:2: note: in expansion of macro ‘module_driver’
  module_driver(__platform_driver, platform_driver_register, \
  ^
drivers/net/phy/mdio-octeon.c:373:1: note: in expansion of macro ‘module_platform_driver’
 module_platform_driver(octeon_mdiobus_driver);
 ^
include/linux/module.h:134:27: error: redefinition of ‘__exittest’
  static inline exitcall_t __exittest(void)  \
                           ^
include/linux/device.h:1326:1: note: in expansion of macro ‘module_exit’
 module_exit(__driver##_exit);
 ^
include/linux/pci.h:1192:2: note: in expansion of macro ‘module_driver’
  module_driver(__pci_driver, pci_register_driver, \
  ^
drivers/net/phy/mdio-octeon.c:513:1: note: in expansion of macro ‘module_pci_driver’
 module_pci_driver(thunder_mdiobus_driver);
 ^
include/linux/module.h:134:27: note: previous definition of ‘__exittest’ was here
  static inline exitcall_t __exittest(void)  \
                           ^
include/linux/device.h:1326:1: note: in expansion of macro ‘module_exit’
 module_exit(__driver##_exit);
 ^
include/linux/platform_device.h:222:2: note: in expansion of macro ‘module_driver’
  module_driver(__platform_driver, platform_driver_register, \
  ^
drivers/net/phy/mdio-octeon.c:373:1: note: in expansion of macro ‘module_platform_driver’
 module_platform_driver(octeon_mdiobus_driver);
 ^
include/linux/module.h:136:7: error: redefinition of ‘cleanup_module’
  void cleanup_module(void) __attribute__((alias(#exitfn)));
       ^
include/linux/device.h:1326:1: note: in expansion of macro ‘module_exit’
 module_exit(__driver##_exit);
 ^
include/linux/pci.h:1192:2: note: in expansion of macro ‘module_driver’
  module_driver(__pci_driver, pci_register_driver, \
  ^
drivers/net/phy/mdio-octeon.c:513:1: note: in expansion of macro ‘module_pci_driver’
 module_pci_driver(thunder_mdiobus_driver);
 ^
include/linux/module.h:136:7: note: previous definition of ‘cleanup_module’ was here
  void cleanup_module(void) __attribute__((alias(#exitfn)));
       ^
include/linux/device.h:1326:1: note: in expansion of macro ‘module_exit’
 module_exit(__driver##_exit);
 ^
include/linux/platform_device.h:222:2: note: in expansion of macro ‘module_driver’
  module_driver(__platform_driver, platform_driver_register, \
  ^
drivers/net/phy/mdio-octeon.c:373:1: note: in expansion of macro ‘module_platform_driver’
 module_platform_driver(octeon_mdiobus_driver);
 ^

And frankly I'm not sure I like this change anyways.  If the OF nodes
are there, simply add code to match on those OF nodes.

This is better than assuming what sits underneath a PCI node, without
any checks for the 'name' or 'compatible' properties at all.  That's
what they are there for afterall.
David Daney Sept. 24, 2015, 10:04 p.m. UTC | #2
On 09/24/2015 02:52 PM, David Miller wrote:
> From: David Daney <ddaney.cavm@gmail.com>
> Date: Tue, 22 Sep 2015 17:41:36 -0700
>
>> From: David Daney <david.daney@cavium.com>
>>
>> When the Cavium mdio-octeon devices appear in the Thunder family of
>> arm64 based SoCs, they show up as PCI devices.  Add PCI driver
>> wrapping so the driver is bound in the standard PCI device scan.
>>
>> When in this form, a single PCI device may have more than a single
>> bus, we call this a "nexus" of buses.  The standard firmware
>> device_for_each_child_node() iterator is used to find the individual
>> buses underneath the "nexus".
>>
>> Update the device tree binding documentation for the new PCI driver
>> binding.
>>
>> Signed-off-by: David Daney <david.daney@cavium.com>
>
> This patch breaks the build:

For which architecture?

I tested it on mips and arm64.  I will try x86, as I guess that is where 
you tried your test build.


>
>    CC [M]  drivers/net/phy/mdio-octeon.o
> In file included from drivers/net/phy/mdio-octeon.c:13:0:
> include/linux/module.h:128:27: error: redefinition of ‘__inittest’
>    static inline initcall_t __inittest(void)  \
>                             ^
[...]

>
> And frankly I'm not sure I like this change anyways.  If the OF nodes
> are there, simply add code to match on those OF nodes.
>
> This is better than assuming what sits underneath a PCI node, without
> any checks for the 'name' or 'compatible' properties at all.  That's
> what they are there for afterall.

There is, somewhat of, a method behind the madness here.

In order to use MSI-X interrupts, we need a corresponding PCI device. 
Now, this driver doesn't currently use interrupts, but other devices in 
the SoC do, so they must be PCI devices.

The idea is to have the type of all drivers uniformly be PCI, rather 
than a random mix of PCI and platform, and then switch them back and 
forth as PCI features are/are-not used in the driver.

Also we need to consider ACPI firmware in addition to OF device tree.

David Daney

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
David Daney Sept. 24, 2015, 10:12 p.m. UTC | #3
On 09/24/2015 03:04 PM, David Daney wrote:
> On 09/24/2015 02:52 PM, David Miller wrote:
>> From: David Daney <ddaney.cavm@gmail.com>
>> Date: Tue, 22 Sep 2015 17:41:36 -0700
>>
>>> From: David Daney <david.daney@cavium.com>
>>>
>>> When the Cavium mdio-octeon devices appear in the Thunder family of
>>> arm64 based SoCs, they show up as PCI devices.  Add PCI driver
>>> wrapping so the driver is bound in the standard PCI device scan.
>>>
>>> When in this form, a single PCI device may have more than a single
>>> bus, we call this a "nexus" of buses.  The standard firmware
>>> device_for_each_child_node() iterator is used to find the individual
>>> buses underneath the "nexus".
>>>
>>> Update the device tree binding documentation for the new PCI driver
>>> binding.
>>>
>>> Signed-off-by: David Daney <david.daney@cavium.com>
>>
>> This patch breaks the build:
>
> For which architecture?
>
> I tested it on mips and arm64.  I will try x86, as I guess that is where
> you tried your test build.
>
>
>>
>>    CC [M]  drivers/net/phy/mdio-octeon.o
>> In file included from drivers/net/phy/mdio-octeon.c:13:0:
>> include/linux/module.h:128:27: error: redefinition of ‘__inittest’
>>    static inline initcall_t __inittest(void)  \
>>

OK, I reproduced this failure.  It happens with a module build only.

Sorry for the breakage, I will fix it and resubmit.

David Daney


                              ^
> [...]
>
>>
>> And frankly I'm not sure I like this change anyways.  If the OF nodes
>> are there, simply add code to match on those OF nodes.
>>
>> This is better than assuming what sits underneath a PCI node, without
>> any checks for the 'name' or 'compatible' properties at all.  That's
>> what they are there for afterall.
>
> There is, somewhat of, a method behind the madness here.
>
> In order to use MSI-X interrupts, we need a corresponding PCI device.
> Now, this driver doesn't currently use interrupts, but other devices in
> the SoC do, so they must be PCI devices.
>
> The idea is to have the type of all drivers uniformly be PCI, rather
> than a random mix of PCI and platform, and then switch them back and
> forth as PCI features are/are-not used in the driver.
>
> Also we need to consider ACPI firmware in addition to OF device tree.
>
> David Daney
>

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
David Miller Sept. 24, 2015, 10:14 p.m. UTC | #4
From: David Daney <ddaney@caviumnetworks.com>
Date: Thu, 24 Sep 2015 15:04:23 -0700

> On 09/24/2015 02:52 PM, David Miller wrote:
>> From: David Daney <ddaney.cavm@gmail.com>
>> Date: Tue, 22 Sep 2015 17:41:36 -0700
>>
>>> From: David Daney <david.daney@cavium.com>
>>>
>>> When the Cavium mdio-octeon devices appear in the Thunder family of
>>> arm64 based SoCs, they show up as PCI devices.  Add PCI driver
>>> wrapping so the driver is bound in the standard PCI device scan.
>>>
>>> When in this form, a single PCI device may have more than a single
>>> bus, we call this a "nexus" of buses.  The standard firmware
>>> device_for_each_child_node() iterator is used to find the individual
>>> buses underneath the "nexus".
>>>
>>> Update the device tree binding documentation for the new PCI driver
>>> binding.
>>>
>>> Signed-off-by: David Daney <david.daney@cavium.com>
>>
>> This patch breaks the build:
> 
> For which architecture?
> 
> I tested it on mips and arm64.  I will try x86, as I guess that is
> where you tried your test build.

x86-64.

> There is, somewhat of, a method behind the madness here.
> 
> In order to use MSI-X interrupts, we need a corresponding PCI
> device. Now, this driver doesn't currently use interrupts, but other
> devices in the SoC do, so they must be PCI devices.

"I need this thing, which isn't needed, therefore I'm making this
change."

Sorry, that's not a good argument.

ACPI nodes have names and whatnot as well.

So I haven't heard a compelling argument so far.

So why not just implement this cleanly and using the existing
framework now, and then when you have a legitimate reason for making a
major change to the probing scheme you can do it then.
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
David Miller Sept. 24, 2015, 10:16 p.m. UTC | #5
From: David Daney <ddaney@caviumnetworks.com>
Date: Thu, 24 Sep 2015 15:12:03 -0700

> Sorry for the breakage, I will fix it and resubmit.

Don't bother, I told you that using PCI probing is unacceptable.
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
David Daney Sept. 24, 2015, 10:45 p.m. UTC | #6
On 09/24/2015 03:14 PM, David Miller wrote:
> From: David Daney <ddaney@caviumnetworks.com>
> Date: Thu, 24 Sep 2015 15:04:23 -0700
>
>> On 09/24/2015 02:52 PM, David Miller wrote:
>>> From: David Daney <ddaney.cavm@gmail.com>
>>> Date: Tue, 22 Sep 2015 17:41:36 -0700
>>>
>>>> From: David Daney <david.daney@cavium.com>
>>>>
>>>> When the Cavium mdio-octeon devices appear in the Thunder family of
>>>> arm64 based SoCs, they show up as PCI devices.  Add PCI driver
>>>> wrapping so the driver is bound in the standard PCI device scan.
>>>>
>>>> When in this form, a single PCI device may have more than a single
>>>> bus, we call this a "nexus" of buses.  The standard firmware
>>>> device_for_each_child_node() iterator is used to find the individual
>>>> buses underneath the "nexus".
>>>>
>>>> Update the device tree binding documentation for the new PCI driver
>>>> binding.
>>>>
>>>> Signed-off-by: David Daney <david.daney@cavium.com>
>>>
>>> This patch breaks the build:
>>
>> For which architecture?
>>
>> I tested it on mips and arm64.  I will try x86, as I guess that is
>> where you tried your test build.
>
> x86-64.
>
>> There is, somewhat of, a method behind the madness here.
>>
>> In order to use MSI-X interrupts, we need a corresponding PCI
>> device. Now, this driver doesn't currently use interrupts, but other
>> devices in the SoC do, so they must be PCI devices.
>
> "I need this thing, which isn't needed, therefore I'm making this
> change."
>

That is not the exact argument.  It is really more like this:

1) The firmware is supplying a uniform view of the devices by making 
them all PCI devices.  This is done because:

    a) Devices that use interrupts must be PCI.

    b) Uniformity is good.

2) The OF device tree nodes for PCI devices do not result in the 
creation of a platform device.

3) If there is no platform device, platform device driver binding does 
not occur, and the device is useless to the kernel.

So, we think it is a good change.  I don't really want to argue about 
the  semantics of it being a "needed change".

> Sorry, that's not a good argument.
>
> ACPI nodes have names and whatnot as well.
>
> So I haven't heard a compelling argument so far.
>
> So why not just implement this cleanly and using the existing
> framework now, and then when you have a legitimate reason for making a
> major change to the probing scheme you can do it then.
>

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
David Miller Sept. 24, 2015, 10:50 p.m. UTC | #7
From: David Daney <ddaney@caviumnetworks.com>
Date: Thu, 24 Sep 2015 15:45:41 -0700

> 2) The OF device tree nodes for PCI devices do not result in the
> creation of a platform device.

But they are created for the children right?  And that's the one
you need them for probing.

I'm still not convinced, sorry.
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
David Daney Sept. 24, 2015, 10:54 p.m. UTC | #8
On 09/24/2015 03:50 PM, David Miller wrote:
> From: David Daney <ddaney@caviumnetworks.com>
> Date: Thu, 24 Sep 2015 15:45:41 -0700
>
>> 2) The OF device tree nodes for PCI devices do not result in the
>> creation of a platform device.
>
> But they are created for the children right?  And that's the one
> you need them for probing.
>
> I'm still not convinced, sorry.
>

Let's let this topic rest for a few days.  My original patch was 
defective, so it cannot be merged.  I will sleep on this, try a few 
things and perhaps revisit it if I still think it is advisable.

Thanks,
David Daney
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
David Miller Sept. 24, 2015, 11:07 p.m. UTC | #9
From: David Daney <ddaney@caviumnetworks.com>
Date: Thu, 24 Sep 2015 15:54:30 -0700

> On 09/24/2015 03:50 PM, David Miller wrote:
>> From: David Daney <ddaney@caviumnetworks.com>
>> Date: Thu, 24 Sep 2015 15:45:41 -0700
>>
>>> 2) The OF device tree nodes for PCI devices do not result in the
>>> creation of a platform device.
>>
>> But they are created for the children right?  And that's the one
>> you need them for probing.
>>
>> I'm still not convinced, sorry.
>>
> 
> Let's let this topic rest for a few days.  My original patch was
> defective, so it cannot be merged.  I will sleep on this, try a few
> things and perhaps revisit it if I still think it is advisable.

Ok.
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/Documentation/devicetree/bindings/net/cavium-mdio.txt b/Documentation/devicetree/bindings/net/cavium-mdio.txt
index 04cb749..020df08 100644
--- a/Documentation/devicetree/bindings/net/cavium-mdio.txt
+++ b/Documentation/devicetree/bindings/net/cavium-mdio.txt
@@ -1,9 +1,12 @@ 
 * System Management Interface (SMI) / MDIO
 
 Properties:
-- compatible: "cavium,octeon-3860-mdio"
+- compatible: One of:
 
-  Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs.
+   "cavium,octeon-3860-mdio": Compatibility with all cn3XXX, cn5XXX
+                       and cn6XXX SOCs.
+
+   "cavium,thunder-8890-mdio": Compatibility with all cn8XXX SOCs.
 
 - reg: The base address of the MDIO bus controller register bank.
 
@@ -25,3 +28,57 @@  Example:
 			reg = <0>;
 		};
 	};
+
+
+* System Management Interface (SMI) / MDIO Nexus
+
+  Several mdio buses may be gathered as children of a single PCI
+  device, this PCI device is the nexus of the buses.
+
+Properties:
+
+- compatible: "cavium,thunder-8890-mdio-nexus";
+
+- reg: The PCI device and function numbers of the nexus device.
+
+- #address-cells: Must be <2>.
+
+- #size-cells: Must be <2>.
+
+- ranges: As needed for mapping of the MDIO bus device registers.
+
+- assigned-addresses: As needed for mapping of the MDIO bus device registers.
+
+Example:
+
+        mdio-nexus@1,3 {
+                compatible = "cavium,thunder-8890-mdio-nexus";
+                #address-cells = <2>;
+                #size-cells = <2>;
+                reg = <0x0b00 0 0 0 0>; /* DEVFN = 0x0b (1:3) */
+                assigned-addresses = <0x03000000 0x87e0 0x05000000 0x0 0x800000>;
+                ranges = <0x87e0 0x05000000 0x03000000 0x87e0 0x05000000 0x0 0x800000>;
+
+                mdio0@87e0,05003800 {
+                        compatible = "cavium,thunder-8890-mdio";
+                        #address-cells = <1>;
+                        #size-cells = <0>;
+                        reg = <0x87e0 0x05003800 0x0 0x30>;
+
+                        ethernet-phy@0 {
+                                ...
+                                reg = <0>;
+                        };
+                };
+                mdio0@87e0,05003880 {
+                        compatible = "cavium,thunder-8890-mdio";
+                        #address-cells = <1>;
+                        #size-cells = <0>;
+                        reg = <0x87e0 0x05003880 0x0 0x30>;
+
+                        ethernet-phy@0 {
+                                ...
+                                reg = <0>;
+                        };
+                };
+        };
diff --git a/drivers/net/phy/mdio-octeon.c b/drivers/net/phy/mdio-octeon.c
index fcf4e4d..21eca35 100644
--- a/drivers/net/phy/mdio-octeon.c
+++ b/drivers/net/phy/mdio-octeon.c
@@ -3,7 +3,7 @@ 
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2009-2012 Cavium, Inc.
+ * Copyright (C) 2009-2015 Cavium, Inc.
  */
 
 #include <linux/platform_device.h>
@@ -14,6 +14,7 @@ 
 #include <linux/gfp.h>
 #include <linux/phy.h>
 #include <linux/io.h>
+#include <linux/pci.h>
 
 #ifdef CONFIG_CAVIUM_OCTEON_SOC
 #include <asm/octeon/octeon.h>
@@ -110,8 +111,6 @@  enum octeon_mdiobus_mode {
 struct octeon_mdiobus {
 	struct mii_bus *mii_bus;
 	u64 register_base;
-	resource_size_t mdio_phys;
-	resource_size_t regsize;
 	enum octeon_mdiobus_mode mode;
 	int phy_irq[PHY_MAX_ADDR];
 };
@@ -269,6 +268,8 @@  static int octeon_mdiobus_probe(struct platform_device *pdev)
 {
 	struct octeon_mdiobus *bus;
 	struct resource *res_mem;
+	resource_size_t mdio_phys;
+	resource_size_t regsize;
 	union cvmx_smix_en smi_en;
 	int err = -ENOENT;
 
@@ -282,17 +283,17 @@  static int octeon_mdiobus_probe(struct platform_device *pdev)
 		return -ENXIO;
 	}
 
-	bus->mdio_phys = res_mem->start;
-	bus->regsize = resource_size(res_mem);
+	mdio_phys = res_mem->start;
+	regsize = resource_size(res_mem);
 
-	if (!devm_request_mem_region(&pdev->dev, bus->mdio_phys, bus->regsize,
+	if (!devm_request_mem_region(&pdev->dev, mdio_phys, regsize,
 				     res_mem->name)) {
 		dev_err(&pdev->dev, "request_mem_region failed\n");
 		return -ENXIO;
 	}
 
 	bus->register_base =
-		(u64)devm_ioremap(&pdev->dev, bus->mdio_phys, bus->regsize);
+		(u64)devm_ioremap(&pdev->dev, mdio_phys, regsize);
 	if (!bus->register_base) {
 		dev_err(&pdev->dev, "dev_ioremap failed\n");
 		return -ENOMEM;
@@ -308,7 +309,7 @@  static int octeon_mdiobus_probe(struct platform_device *pdev)
 
 	bus->mii_bus->priv = bus;
 	bus->mii_bus->irq = bus->phy_irq;
-	bus->mii_bus->name = "mdio-octeon";
+	bus->mii_bus->name = KBUILD_MODNAME;
 	snprintf(bus->mii_bus->id, MII_BUS_ID_SIZE, "%llx", bus->register_base);
 	bus->mii_bus->parent = &pdev->dev;
 
@@ -356,7 +357,7 @@  MODULE_DEVICE_TABLE(of, octeon_mdiobus_match);
 
 static struct platform_driver octeon_mdiobus_driver = {
 	.driver = {
-		.name		= "mdio-octeon",
+		.name		= KBUILD_MODNAME,
 		.of_match_table = octeon_mdiobus_match,
 	},
 	.probe		= octeon_mdiobus_probe,
@@ -371,6 +372,146 @@  EXPORT_SYMBOL(octeon_mdiobus_force_mod_depencency);
 
 module_platform_driver(octeon_mdiobus_driver);
 
+#ifdef CONFIG_PCI
+
+struct thunder_mdiobus_nexus {
+	void __iomem *bar0;
+	struct octeon_mdiobus *buses[4];
+};
+
+static int thunder_mdiobus_pci_probe(struct pci_dev *pdev,
+				     const struct pci_device_id *ent)
+{
+	struct device_node *node;
+	struct fwnode_handle *fwn;
+	struct thunder_mdiobus_nexus *nexus;
+	int err;
+	int i;
+
+	nexus = devm_kzalloc(&pdev->dev, sizeof(*nexus), GFP_KERNEL);
+	if (!nexus)
+		return -ENOMEM;
+
+	pci_set_drvdata(pdev, nexus);
+
+	err = pcim_enable_device(pdev);
+	if (err) {
+		dev_err(&pdev->dev, "Failed to enable PCI device\n");
+		pci_set_drvdata(pdev, NULL);
+		return err;
+	}
+
+	err = pci_request_regions(pdev, KBUILD_MODNAME);
+	if (err) {
+		dev_err(&pdev->dev, "pci_request_regions failed\n");
+		goto err_disable_device;
+	}
+
+	nexus->bar0 = pcim_iomap(pdev, 0, pci_resource_len(pdev, 0));
+	if (!nexus->bar0) {
+		err = -ENOMEM;
+		goto err_release_regions;
+	}
+
+	i = 0;
+	device_for_each_child_node(&pdev->dev, fwn) {
+		struct resource r;
+		struct octeon_mdiobus *bus;
+		union cvmx_smix_en smi_en;
+
+		/* If it is not an OF node we cannot handle it yet, so
+		 * exit the loop.
+		 */
+		node = to_of_node(fwn);
+		if (!node)
+			break;
+
+		err = of_address_to_resource(node, 0, &r);
+		if (err) {
+			dev_err(&pdev->dev,
+				"Couldn't translate address for \"%s\"\n",
+				node->name);
+			break;
+		}
+		bus = devm_kzalloc(&pdev->dev, sizeof(struct octeon_mdiobus),
+				   GFP_KERNEL);
+
+		if (!bus)
+			break;
+
+		nexus->buses[i] = bus;
+		i++;
+
+		bus->register_base = (u64)nexus->bar0 +
+			r.start - pci_resource_start(pdev, 0);
+
+		bus->mii_bus = mdiobus_alloc();
+		if (!bus->mii_bus)
+			break;
+
+		smi_en.u64 = 0;
+		smi_en.s.en = 1;
+		oct_mdio_writeq(smi_en.u64, bus->register_base + SMI_EN);
+		bus->mii_bus->priv = bus;
+		bus->mii_bus->irq = bus->phy_irq;
+		bus->mii_bus->name = KBUILD_MODNAME;
+		snprintf(bus->mii_bus->id, MII_BUS_ID_SIZE, "%llx", r.start);
+		bus->mii_bus->parent = &pdev->dev;
+		bus->mii_bus->read = octeon_mdiobus_read;
+		bus->mii_bus->write = octeon_mdiobus_write;
+
+		err = of_mdiobus_register(bus->mii_bus, node);
+		if (err)
+			dev_err(&pdev->dev, "of_mdiobus_register failed\n");
+
+		dev_info(&pdev->dev, "Added bus at %llx\n", r.start);
+		if (i >= ARRAY_SIZE(nexus->buses))
+			break;
+	}
+	return 0;
+
+err_release_regions:
+	pci_release_regions(pdev);
+
+err_disable_device:
+	pci_set_drvdata(pdev, NULL);
+	return err;
+}
+
+static void thunder_mdiobus_pci_remove(struct pci_dev *pdev)
+{
+	int i;
+	union cvmx_smix_en smi_en;
+	struct thunder_mdiobus_nexus *nexus = pci_get_drvdata(pdev);
+
+	for (i = 0; i < ARRAY_SIZE(nexus->buses); i++) {
+		struct octeon_mdiobus *bus = nexus->buses[i];
+
+		if (!bus)
+			continue;
+
+		mdiobus_unregister(bus->mii_bus);
+		mdiobus_free(bus->mii_bus);
+		smi_en.u64 = 0;
+		oct_mdio_writeq(smi_en.u64, bus->register_base + SMI_EN);
+	}
+	pci_set_drvdata(pdev, NULL);
+}
+
+static const struct pci_device_id thunder_mdiobus_id_table[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, 0xa02b) },
+	{ 0, } /* End of table. */
+};
+MODULE_DEVICE_TABLE(pci, thunder_mdiobus_id_table);
+
+static struct pci_driver thunder_mdiobus_driver = {
+	.name = KBUILD_MODNAME,
+	.id_table = thunder_mdiobus_id_table,
+	.probe = thunder_mdiobus_pci_probe,
+	.remove = thunder_mdiobus_pci_remove,
+};
+module_pci_driver(thunder_mdiobus_driver);
+#endif /* CONFIG_PCI */
 MODULE_DESCRIPTION(DRV_DESCRIPTION);
 MODULE_VERSION(DRV_VERSION);
 MODULE_AUTHOR("David Daney");