* Re: [PATCH V2 00/16] Squashfs: compressed read-only filesystem
From: Phillip Lougher @ 2008-10-31 0:29 UTC (permalink / raw)
To: Matt Mackall; +Cc: akpm, linux-embedded, linux-fsdevel, linux-kernel, tim.bird
In-Reply-To: <1225316373.3199.276.camel@calx>
Matt Mackall wrote:
> On Wed, 2008-10-29 at 01:49 +0000, Phillip Lougher wrote:
>> Hi,
>>
>> This a respin of the Squashfs patches incorporating the review comments
>> received. Thanks to everyone who have sent comments.
>
> I read over the v3 source a few weeks ago and must say this looks
> greatly improved.
>
Yes thanks. The v3 source was a bit of a mess, it had grown organically
from the earliest version of Squashfs, and long needed restructuring,
closer attention to coding standards, and commenting. I think the v4
source is a major improvement, it's partially thanks to CELF that I got
the necessary time off work to knock it into shape.
Phillip
^ permalink raw reply
* Re: [PATCH V2 10/16] Squashfs: cache operations
From: Phillip Lougher @ 2008-10-31 4:43 UTC (permalink / raw)
To: Jörn Engel
Cc: akpm, linux-embedded, linux-fsdevel, linux-kernel, tim.bird
In-Reply-To: <20081029093218.GA26456@logfs.org>
Jörn Engel wrote:
> On Wed, 29 October 2008 01:49:56 +0000, Phillip Lougher wrote:
>> +/*
>> + * Blocks in Squashfs are compressed. To avoid repeatedly decompressing
>> + * recently accessed data Squashfs uses two small metadata and fragment caches.
>> + *
>> + * This file implements a generic cache implementation used for both caches,
>> + * plus functions layered ontop of the generic cache implementation to
>> + * access the metadata and fragment caches.
>> + */
>
> I tend to agree with Andrew that a lot of this should be done by the
> page cache instead. One of the problems seems to be that your blocksize
> can exceed page size and there really isn't any infrastructure to deal
> with such cases yet. Bufferheads deal with blocks smaller than a page,
> not the other way around.
>
I thought about using the page cache, but, the fact that blocksizes
exceed the page cache size is only one of a number of reasons why I
prefer the current solution, there is also simplicity and speed to consider.
There are three types of compressed block in Squashfs: datablocks,
fragments, and metadata blocks. Of these datablocks (by far the largest
number of blocks) are decompressed and pushed into the page cache, and
are not otherwise cached by Squashfs. This, obviously (?), is because
they contain data for only one file, and so at time of access there is a
readily available address space to push the data into.
Metadata and fragment blocks are different in that when accessed and
decompressed (say for an inode or for a particular tail-end block) they
will contain metadata or tail-ends for other files. This data could be
thrown away but due to locality of reference it makes sense to
temporarily cache it in-case a near future file access references the
data. But it doesn't make much sense to cache it more than temporarily,
much of the data will probably not be reused, and it exists compressed
in the buffer cache.
The squashfs cache is therefore designed to cache only the last couple
of metadata and fragment blocks. It is also designed to be simple and
extremely fast. The maximum size of the metadata cache is only 64 KiB.
Simplicity and speed is extremely important. The
squashfs_metadata_read() wrapper around the cache is designed to step
through the metadata a structure at a time (20 or so bytes), updating
the read position in the metadata each call, with more metadata cache
blocks being read and decompressed as necessary. The common case where
the metadata is already in the cache (because we're stepping through it
20 or so bytes at a time), is designed to be extremely fast - a spinlock
and array search only. I recently optimised the cache to use spinlocks
rather than mutexes and reduced the lock holding time (necessary to move
to spinlocks), and this resulted in a 20%+ speed improvement in reading
squashfs filesystems.
Given the above using an address space in the page cache will result in
greater complexity, more memory overhead, and much slower operation.
There's a number of reasons for this.
1. The amount and life-span of the data stored in the page cache is
outside of Squashfs' control. As explained above it only makes sense to
temporarily cache the last couple of metadata and fragment blocks.
Using the page cache (if a 'large' address space is used) for these
keeps more of them around for longer than necessary, and will
potentially cause more worthy datablocks to be flushed on memory pressure.
2. The address space will be caching uncompressed data, the squashfs
references to this data are the compressed locations within the
filesystem. There doesn't exist a one-to-one linear mapping from
compressed location to decompressed location in the address space. This
means a lookup table still needs to be used to store the mapping from
compressed location to decompressed location in the address space. Now
this lookup table (however implemented) is itself at least as complex as
my current cache implementation.
3. Once the locations of the decompressed pages in the address space
have been found, they'll need to be looked up in the page cache, and
this has to be done for every 4K page. With the default fragment size
of 128 KiB this means 32 separate lookups. Somewhat slower than one
spinlock and array search per 128 KiB block in the squashfs cache
implementation.
Comments, especially those of the form "you've got this completely
wrong, and you can use the page cache like this, which will be simpler
and faster than your current implementation" welcome :) I'm not adverse
to using the page cache, but I can't see how it will be simpler or
faster than the current implementation.
Phillip
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH V2 10/16] Squashfs: cache operations
From: Jörn Engel @ 2008-10-31 7:29 UTC (permalink / raw)
To: Phillip Lougher
Cc: akpm, linux-embedded, linux-fsdevel, linux-kernel, tim.bird
In-Reply-To: <490A8D02.4090407@lougher.demon.co.uk>
On Fri, 31 October 2008 04:43:46 +0000, Phillip Lougher wrote:
>
> Simplicity and speed is extremely important. The
> squashfs_metadata_read() wrapper around the cache is designed to step
> through the metadata a structure at a time (20 or so bytes), updating
> the read position in the metadata each call, with more metadata cache
> blocks being read and decompressed as necessary. The common case where
> the metadata is already in the cache (because we're stepping through it
> 20 or so bytes at a time), is designed to be extremely fast - a spinlock
> and array search only. I recently optimised the cache to use spinlocks
> rather than mutexes and reduced the lock holding time (necessary to move
> to spinlocks), and this resulted in a 20%+ speed improvement in reading
> squashfs filesystems.
For the page cache, you can use read_cache_page() and
page_cache_release(). This does not even take a spinlock, hence
multiple readers can work in parallel. The radix tree walk will take a
similar time to your array search.
You are aware that multiple cpus will play pingpong with your spinlock?
> Given the above using an address space in the page cache will result in
> greater complexity, more memory overhead, and much slower operation.
> There's a number of reasons for this.
>
> 1. The amount and life-span of the data stored in the page cache is
> outside of Squashfs' control. As explained above it only makes sense to
> temporarily cache the last couple of metadata and fragment blocks.
> Using the page cache (if a 'large' address space is used) for these
> keeps more of them around for longer than necessary, and will
> potentially cause more worthy datablocks to be flushed on memory pressure.
I personally find it hard to guess access patterns. If I constructed a
workload just large enough that your cache is slightly too small, it
will start thrashing. Hit rates will go close to zero. And unless I
missed something, such a workload can be constructed and may even be
used in real life. With growing numbers of cores, this becomes
increasingly likely.
In other cases, an idle squashfs will still hold the 64k of unused cache
for ransom. By giving up control, you allow your cache to grow and
shrink as desired and can avoid both cases.
> 2. The address space will be caching uncompressed data, the squashfs
> references to this data are the compressed locations within the
> filesystem. There doesn't exist a one-to-one linear mapping from
> compressed location to decompressed location in the address space. This
> means a lookup table still needs to be used to store the mapping from
> compressed location to decompressed location in the address space. Now
> this lookup table (however implemented) is itself at least as complex as
> my current cache implementation.
You are currently using physical offset of the medium to address blocks
in the cache, which are 64bit. Page cache may use 32bit to address
pages. And since blocks can be larger than pages, you effectively need
some bits extra. This is indeed a problem.
> 3. Once the locations of the decompressed pages in the address space
> have been found, they'll need to be looked up in the page cache, and
> this has to be done for every 4K page. With the default fragment size
> of 128 KiB this means 32 separate lookups. Somewhat slower than one
> spinlock and array search per 128 KiB block in the squashfs cache
> implementation.
Above you claimed the complete cache to be just 64k in size. How can
you access 128k blocks that way? One of the numbers appears wrong.
Ignoring that, you don't need to take either the spinlock or do a lookup
in a fast path. If you currently have this code:
for (some condition) {
err = squashfs_read_metadata(address, ...);
}
You can transform it to:
void *handle = squashfs_get_metadata(address, ...);
for (some condition) {
err = squashfs_read_metadata(handle, address, ...);
}
squashfs_put_metadata(handle);
With the handle you can keep a reference count to your cached object.
squashfs_read_metadata() only has to call squashfs_cache_get() or
squashfs_cache_put() when moving across object boundaries. In the
common case it simply returns data from the object referenced through
the handle.
This might be a worthwhile optimization independently of whether you use
the page cache or not.
> Comments, especially those of the form "you've got this completely
> wrong, and you can use the page cache like this, which will be simpler
> and faster than your current implementation" welcome :) I'm not adverse
> to using the page cache, but I can't see how it will be simpler or
> faster than the current implementation.
Only one of your problems seems to be real. Not sure if or how we can
solve that one, though.
Jörn
--
"Security vulnerabilities are here to stay."
-- Scott Culp, Manager of the Microsoft Security Response Center, 2001
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH V2 10/16] Squashfs: cache operations
From: Phillip Lougher @ 2008-10-31 15:03 UTC (permalink / raw)
To: Jörn Engel
Cc: akpm, linux-embedded, linux-fsdevel, linux-kernel, tim.bird
In-Reply-To: <20081031072923.GA18182@logfs.org>
Jörn Engel wrote:
>
> Only one of your problems seems to be real. Not sure if or how we can
> solve that one, though.
>
Sorry don't agree. But I'm not going to argue this like a couple of old
maids.
I'll keep what I currently do unless Andrew Morton or someone else says
it's not getting mainlined unless it's changed.
Phillip
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH] phylib: mdio-ofgpio ---> mdio-gpio
From: Paulius Zaleckas @ 2008-10-31 15:53 UTC (permalink / raw)
To: netdev
Cc: linux-arm-kernel, linux-embedded, Paulius Zaleckas,
Laurent Pinchart, Grant Likely, Mike Frysinger
Rename mdio-ofgpio driver to mdio-gpio and make it work with
non OpenFirmware gpio implementation.
Aditional changes to mdio-ofgpio:
- use gpio_request() and gpio_free()
- place irq[] array in struct mdio_gpio_info
- add module description, author and license
- if NO_IRQ is not defined define it to 0
- add note about compiling this driver as module
- rename mdc and mdio function (were ugly names)
- change MII to MDIO in bus name
- add __init __exit to module (un)loading functions
- probe fails if no phys added to the bus
- kzalloc bitbang with sizeof(*bitbang)
Laurent, please test this driver under OF.
Signed-off-by: Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
Cc: Laurent Pinchart <laurentp@cse-semaphore.com>
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: Mike Frysinger <vapier.adi@gmail.com>
---
drivers/net/phy/Kconfig | 7 +
drivers/net/phy/Makefile | 2
drivers/net/phy/mdio-gpio.c | 308 +++++++++++++++++++++++++++++++++++++++++
drivers/net/phy/mdio-ofgpio.c | 204 ---------------------------
include/linux/mdio-gpio.h | 30 ++++
5 files changed, 344 insertions(+), 207 deletions(-)
create mode 100644 drivers/net/phy/mdio-gpio.c
delete mode 100644 drivers/net/phy/mdio-ofgpio.c
create mode 100644 include/linux/mdio-gpio.h
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index d55932a..c4c5a2f 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -84,10 +84,13 @@ config MDIO_BITBANG
If in doubt, say N.
-config MDIO_OF_GPIO
+config MDIO_GPIO
tristate "Support for GPIO lib-based bitbanged MDIO buses"
- depends on MDIO_BITBANG && OF_GPIO
+ depends on MDIO_BITBANG && GENERIC_GPIO
---help---
Supports GPIO lib-based MDIO busses.
+ To compile this driver as a module, choose M here: the module
+ will be called mdio-gpio.
+
endif # PHYLIB
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index eee329f..9ae5d30 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -15,4 +15,4 @@ obj-$(CONFIG_ICPLUS_PHY) += icplus.o
obj-$(CONFIG_REALTEK_PHY) += realtek.o
obj-$(CONFIG_FIXED_PHY) += fixed.o
obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o
-obj-$(CONFIG_MDIO_OF_GPIO) += mdio-ofgpio.o
+obj-$(CONFIG_MDIO_GPIO) += mdio-gpio.o
diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c
new file mode 100644
index 0000000..a7b94ac
--- /dev/null
+++ b/drivers/net/phy/mdio-gpio.c
@@ -0,0 +1,308 @@
+/*
+ * GPIO based MDIO bitbang driver.
+ * Supports OpenFirmware.
+ *
+ * Copyright (c) 2008 CSE Semaphore Belgium.
+ * by Laurent Pinchart <laurentp@cse-semaphore.com>
+ *
+ * Copyright (C) 2008, Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ *
+ * Based on earlier work by
+ *
+ * Copyright (c) 2003 Intracom S.A.
+ * by Pantelis Antoniou <panto@intracom.gr>
+ *
+ * 2005 (c) MontaVista Software, Inc.
+ * Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/mdio-bitbang.h>
+#ifdef CONFIG_OF_GPIO
+# include <linux/of_gpio.h>
+# include <linux/of_platform.h>
+#else
+# include <linux/platform_device.h>
+# include <linux/gpio.h>
+# include <linux/mdio-gpio.h>
+#endif
+
+#ifndef NO_IRQ
+#define NO_IRQ 0
+#endif
+
+struct mdio_gpio_info {
+ struct mdiobb_ctrl ctrl;
+ int mdc, mdio;
+ int irq[PHY_MAX_ADDR];
+};
+
+static void mdio_dir(struct mdiobb_ctrl *ctrl, int dir)
+{
+ struct mdio_gpio_info *bitbang =
+ container_of(ctrl, struct mdio_gpio_info, ctrl);
+
+ if (dir)
+ gpio_direction_output(bitbang->mdio, 1);
+ else
+ gpio_direction_input(bitbang->mdio);
+}
+
+static int mdio_get(struct mdiobb_ctrl *ctrl)
+{
+ struct mdio_gpio_info *bitbang =
+ container_of(ctrl, struct mdio_gpio_info, ctrl);
+
+ return gpio_get_value(bitbang->mdio);
+}
+
+static void mdio_set(struct mdiobb_ctrl *ctrl, int what)
+{
+ struct mdio_gpio_info *bitbang =
+ container_of(ctrl, struct mdio_gpio_info, ctrl);
+
+ gpio_set_value(bitbang->mdio, what);
+}
+
+static void mdc_set(struct mdiobb_ctrl *ctrl, int what)
+{
+ struct mdio_gpio_info *bitbang =
+ container_of(ctrl, struct mdio_gpio_info, ctrl);
+
+ gpio_set_value(bitbang->mdc, what);
+}
+
+static struct mdiobb_ops mdio_gpio_ops = {
+ .owner = THIS_MODULE,
+ .set_mdc = mdc_set,
+ .set_mdio_dir = mdio_dir,
+ .set_mdio_data = mdio_set,
+ .get_mdio_data = mdio_get,
+};
+
+#ifdef CONFIG_OF_GPIO
+static int __devinit mdio_ofgpio_bitbang_init(struct mii_bus *bus,
+ struct device_node *np)
+{
+ struct mdio_gpio_info *bitbang = bus->priv;
+
+ bitbang->mdc = of_get_gpio(np, 0);
+ bitbang->mdio = of_get_gpio(np, 1);
+
+ if (bitbang->mdc < 0 || bitbang->mdio < 0)
+ return -ENODEV;
+
+ snprintf(bus->id, MII_BUS_ID_SIZE, "%x", bitbang->mdc);
+ return 0;
+}
+#else
+static void __devinit mdio_gpio_bitbang_init(struct mii_bus *bus,
+ struct mdio_gpio_platform_data *pdata,
+ int bus_id)
+{
+ struct mdio_gpio_info *bitbang = bus->priv;
+
+ bitbang->mdc = pdata->mdc;
+ bitbang->mdio = pdata->mdio;
+
+ snprintf(bus->id, MII_BUS_ID_SIZE, "phy%i", bus_id);
+}
+#endif
+
+static void __devinit add_phy(struct mii_bus *bus, unsigned int phy_addr,
+ int phy_irq)
+{
+ if (phy_addr >= PHY_MAX_ADDR) {
+ dev_err(bus->parent,
+ "Failed to add phy with invalid address: 0x%x",
+ phy_addr);
+ return;
+ }
+
+ bus->phy_mask &= ~(1 << phy_addr);
+
+ if (phy_irq != NO_IRQ)
+ bus->irq[phy_addr] = phy_irq;
+}
+
+#ifdef CONFIG_OF_GPIO
+static int __devinit mdio_ofgpio_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ struct device_node *np = NULL;
+ struct device *dev = &ofdev->dev;
+#else
+static int __devinit mdio_gpio_probe(struct platform_device *pdev)
+{
+ struct mdio_gpio_platform_data *pdata;
+ struct device *dev = &pdev->dev;
+#endif
+ struct mii_bus *new_bus;
+ struct mdio_gpio_info *bitbang;
+ int ret = -ENOMEM;
+ int i;
+
+#ifndef CONFIG_OF_GPIO
+ pdata = dev->platform_data;
+ if (pdata == NULL)
+ goto out;
+#endif
+
+ bitbang = kzalloc(sizeof(*bitbang), GFP_KERNEL);
+ if (!bitbang)
+ goto out;
+
+ bitbang->ctrl.ops = &mdio_gpio_ops;
+
+ new_bus = alloc_mdio_bitbang(&bitbang->ctrl);
+ if (!new_bus)
+ goto out_free_bitbang;
+
+ new_bus->name = "GPIO Bitbanged MDIO",
+
+#ifdef CONFIG_OF_GPIO
+ ret = mdio_ofgpio_bitbang_init(new_bus, ofdev->node);
+ if (ret)
+ goto out_free_bus;
+#else
+ mdio_gpio_bitbang_init(new_bus, pdata, pdev->id);
+#endif
+
+ ret = -ENODEV;
+
+ if (gpio_request(bitbang->mdc, "mdc"))
+ goto out_free_bus;
+
+ if (gpio_request(bitbang->mdio, "mdio"))
+ goto out_free_mdc;
+
+ new_bus->phy_mask = ~0;
+ new_bus->irq = bitbang->irq;
+ new_bus->parent = dev;
+
+ for (i = 0; i < PHY_MAX_ADDR; i++)
+ new_bus->irq[i] = PHY_POLL;
+
+#ifdef CONFIG_OF_GPIO
+ while ((np = of_get_next_child(ofdev->node, np)))
+ if (!strcmp(np->type, "ethernet-phy")) {
+ const u32 *data;
+ int len;
+
+ data = of_get_property(np, "reg", &len);
+ if (!data || len != 4)
+ continue;
+
+ add_phy(new_bus, *data,
+ of_irq_to_resource(np, 0, NULL));
+ }
+#else
+ for (i = 0; i < pdata->nr_phys; i++)
+ add_phy(new_bus, pdata->phys[i].addr, pdata->phys[i].irq);
+#endif
+
+ if (new_bus->phy_mask == ~0)
+ goto out_free_gpio;
+
+ dev_set_drvdata(dev, new_bus);
+
+ ret = mdiobus_register(new_bus);
+ if (ret)
+ goto out_free_all;
+
+ return 0;
+
+out_free_all:
+ dev_set_drvdata(dev, NULL);
+out_free_gpio:
+ gpio_free(bitbang->mdio);
+out_free_mdc:
+ gpio_free(bitbang->mdc);
+out_free_bus:
+ free_mdio_bitbang(new_bus);
+out_free_bitbang:
+ kfree(bitbang);
+out:
+ return ret;
+}
+
+#ifdef CONFIG_OF_GPIO
+static int mdio_ofgpio_remove(struct of_device *ofdev)
+{
+ struct device *dev = &ofdev->dev;
+#else
+static int __devexit mdio_gpio_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+#endif
+ struct mii_bus *bus = dev_get_drvdata(dev);
+ struct mdio_gpio_info *bitbang = bus->priv;
+
+ mdiobus_unregister(bus);
+ free_mdio_bitbang(bus);
+ dev_set_drvdata(dev, NULL);
+ gpio_free(bitbang->mdc);
+ gpio_free(bitbang->mdio);
+ kfree(bitbang);
+
+ return 0;
+}
+
+#ifdef CONFIG_OF_GPIO
+static struct of_device_id mdio_ofgpio_match[] = {
+ {
+ .compatible = "virtual,mdio-gpio",
+ },
+ {},
+};
+
+static struct of_platform_driver mdio_ofgpio_driver = {
+ .name = "mdio-gpio",
+ .match_table = mdio_ofgpio_match,
+ .probe = mdio_ofgpio_probe,
+ .remove = mdio_ofgpio_remove,
+};
+#else
+static struct platform_driver mdio_gpio_driver = {
+ .probe = mdio_gpio_probe,
+ .remove = __devexit_p(mdio_gpio_remove),
+ .driver = {
+ .name = "mdio-gpio",
+ .owner = THIS_MODULE,
+ },
+};
+#endif
+
+static int __init mdio_gpio_init(void)
+{
+#ifdef CONFIG_OF_GPIO
+ return of_register_platform_driver(&mdio_ofgpio_driver);
+#else
+ return platform_driver_register(&mdio_gpio_driver);
+#endif
+}
+module_init(mdio_gpio_init);
+
+static void __exit mdio_gpio_exit(void)
+{
+#ifdef CONFIG_OF_GPIO
+ of_unregister_platform_driver(&mdio_ofgpio_driver);
+#else
+ platform_driver_unregister(&mdio_gpio_driver);
+#endif
+}
+module_exit(mdio_gpio_exit);
+
+#ifndef CONFIG_OF_GPIO
+MODULE_ALIAS("platform:mdio-gpio");
+#endif
+MODULE_AUTHOR("Laurent Pinchart, Paulius Zaleckas");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Generic driver for MDIO bus emulation using GPIO");
diff --git a/drivers/net/phy/mdio-ofgpio.c b/drivers/net/phy/mdio-ofgpio.c
deleted file mode 100644
index 2ff9775..0000000
--- a/drivers/net/phy/mdio-ofgpio.c
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * OpenFirmware GPIO based MDIO bitbang driver.
- *
- * Copyright (c) 2008 CSE Semaphore Belgium.
- * by Laurent Pinchart <laurentp@cse-semaphore.com>
- *
- * Based on earlier work by
- *
- * Copyright (c) 2003 Intracom S.A.
- * by Pantelis Antoniou <panto@intracom.gr>
- *
- * 2005 (c) MontaVista Software, Inc.
- * Vitaly Bordug <vbordug@ru.mvista.com>
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/mdio-bitbang.h>
-#include <linux/of_gpio.h>
-#include <linux/of_platform.h>
-
-struct mdio_gpio_info {
- struct mdiobb_ctrl ctrl;
- int mdc, mdio;
-};
-
-static void mdio_dir(struct mdiobb_ctrl *ctrl, int dir)
-{
- struct mdio_gpio_info *bitbang =
- container_of(ctrl, struct mdio_gpio_info, ctrl);
-
- if (dir)
- gpio_direction_output(bitbang->mdio, 1);
- else
- gpio_direction_input(bitbang->mdio);
-}
-
-static int mdio_read(struct mdiobb_ctrl *ctrl)
-{
- struct mdio_gpio_info *bitbang =
- container_of(ctrl, struct mdio_gpio_info, ctrl);
-
- return gpio_get_value(bitbang->mdio);
-}
-
-static void mdio(struct mdiobb_ctrl *ctrl, int what)
-{
- struct mdio_gpio_info *bitbang =
- container_of(ctrl, struct mdio_gpio_info, ctrl);
-
- gpio_set_value(bitbang->mdio, what);
-}
-
-static void mdc(struct mdiobb_ctrl *ctrl, int what)
-{
- struct mdio_gpio_info *bitbang =
- container_of(ctrl, struct mdio_gpio_info, ctrl);
-
- gpio_set_value(bitbang->mdc, what);
-}
-
-static struct mdiobb_ops mdio_gpio_ops = {
- .owner = THIS_MODULE,
- .set_mdc = mdc,
- .set_mdio_dir = mdio_dir,
- .set_mdio_data = mdio,
- .get_mdio_data = mdio_read,
-};
-
-static int __devinit mdio_ofgpio_bitbang_init(struct mii_bus *bus,
- struct device_node *np)
-{
- struct mdio_gpio_info *bitbang = bus->priv;
-
- bitbang->mdc = of_get_gpio(np, 0);
- bitbang->mdio = of_get_gpio(np, 1);
-
- if (bitbang->mdc < 0 || bitbang->mdio < 0)
- return -ENODEV;
-
- snprintf(bus->id, MII_BUS_ID_SIZE, "%x", bitbang->mdc);
- return 0;
-}
-
-static void __devinit add_phy(struct mii_bus *bus, struct device_node *np)
-{
- const u32 *data;
- int len, id, irq;
-
- data = of_get_property(np, "reg", &len);
- if (!data || len != 4)
- return;
-
- id = *data;
- bus->phy_mask &= ~(1 << id);
-
- irq = of_irq_to_resource(np, 0, NULL);
- if (irq != NO_IRQ)
- bus->irq[id] = irq;
-}
-
-static int __devinit mdio_ofgpio_probe(struct of_device *ofdev,
- const struct of_device_id *match)
-{
- struct device_node *np = NULL;
- struct mii_bus *new_bus;
- struct mdio_gpio_info *bitbang;
- int ret = -ENOMEM;
- int i;
-
- bitbang = kzalloc(sizeof(struct mdio_gpio_info), GFP_KERNEL);
- if (!bitbang)
- goto out;
-
- bitbang->ctrl.ops = &mdio_gpio_ops;
-
- new_bus = alloc_mdio_bitbang(&bitbang->ctrl);
- if (!new_bus)
- goto out_free_bitbang;
-
- new_bus->name = "GPIO Bitbanged MII",
-
- ret = mdio_ofgpio_bitbang_init(new_bus, ofdev->node);
- if (ret)
- goto out_free_bus;
-
- new_bus->phy_mask = ~0;
- new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
- if (!new_bus->irq)
- goto out_free_bus;
-
- for (i = 0; i < PHY_MAX_ADDR; i++)
- new_bus->irq[i] = -1;
-
- while ((np = of_get_next_child(ofdev->node, np)))
- if (!strcmp(np->type, "ethernet-phy"))
- add_phy(new_bus, np);
-
- new_bus->parent = &ofdev->dev;
- dev_set_drvdata(&ofdev->dev, new_bus);
-
- ret = mdiobus_register(new_bus);
- if (ret)
- goto out_free_irqs;
-
- return 0;
-
-out_free_irqs:
- dev_set_drvdata(&ofdev->dev, NULL);
- kfree(new_bus->irq);
-out_free_bus:
- free_mdio_bitbang(new_bus);
-out_free_bitbang:
- kfree(bitbang);
-out:
- return ret;
-}
-
-static int mdio_ofgpio_remove(struct of_device *ofdev)
-{
- struct mii_bus *bus = dev_get_drvdata(&ofdev->dev);
- struct mdio_gpio_info *bitbang = bus->priv;
-
- mdiobus_unregister(bus);
- kfree(bus->irq);
- free_mdio_bitbang(bus);
- dev_set_drvdata(&ofdev->dev, NULL);
- kfree(bitbang);
-
- return 0;
-}
-
-static struct of_device_id mdio_ofgpio_match[] = {
- {
- .compatible = "virtual,mdio-gpio",
- },
- {},
-};
-
-static struct of_platform_driver mdio_ofgpio_driver = {
- .name = "mdio-gpio",
- .match_table = mdio_ofgpio_match,
- .probe = mdio_ofgpio_probe,
- .remove = mdio_ofgpio_remove,
-};
-
-static int mdio_ofgpio_init(void)
-{
- return of_register_platform_driver(&mdio_ofgpio_driver);
-}
-
-static void mdio_ofgpio_exit(void)
-{
- of_unregister_platform_driver(&mdio_ofgpio_driver);
-}
-
-module_init(mdio_ofgpio_init);
-module_exit(mdio_ofgpio_exit);
diff --git a/include/linux/mdio-gpio.h b/include/linux/mdio-gpio.h
new file mode 100644
index 0000000..5ca24ed
--- /dev/null
+++ b/include/linux/mdio-gpio.h
@@ -0,0 +1,30 @@
+/*
+ * MDIO-GPIO bus platform data structures
+ *
+ * Copyright (C) 2008, Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef __LINUX_MDIO_GPIO_H
+#define __LINUX_MDIO_GPIO_H
+
+struct mdio_gpio_phy {
+ /* PHY address on MDIO bus */
+ unsigned int addr;
+ /* preconfigured irq connected to PHY or -1 if no irq */
+ int irq;
+};
+
+struct mdio_gpio_platform_data {
+ /* GPIO numbers for bus pins */
+ unsigned int mdc;
+ unsigned int mdio;
+
+ unsigned int nr_phys;
+ struct mdio_gpio_phy *phys;
+};
+
+#endif /* __LINUX_MDIO_GPIO_H */
^ permalink raw reply related
* Re: [PATCH] phylib: mdio-ofgpio ---> mdio-gpio
From: Grant Likely @ 2008-10-31 16:06 UTC (permalink / raw)
To: Paulius Zaleckas
Cc: netdev, linux-arm-kernel, linux-embedded, Laurent Pinchart,
Mike Frysinger
In-Reply-To: <20081031155335.19905.14186.stgit@Programuotojas.82-135-208-232.ip.zebra.lt>
On Fri, Oct 31, 2008 at 9:53 AM, Paulius Zaleckas
<paulius.zaleckas@teltonika.lt> wrote:
> Rename mdio-ofgpio driver to mdio-gpio and make it work with
> non OpenFirmware gpio implementation.
Please respin this patch in 2 pieces; 1 patch to move the file and 1
patch to make the changes. It is difficult to review as a single
patch.
g.
>
> Aditional changes to mdio-ofgpio:
> - use gpio_request() and gpio_free()
> - place irq[] array in struct mdio_gpio_info
> - add module description, author and license
> - if NO_IRQ is not defined define it to 0
> - add note about compiling this driver as module
> - rename mdc and mdio function (were ugly names)
> - change MII to MDIO in bus name
> - add __init __exit to module (un)loading functions
> - probe fails if no phys added to the bus
> - kzalloc bitbang with sizeof(*bitbang)
>
> Laurent, please test this driver under OF.
>
> Signed-off-by: Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
> Cc: Laurent Pinchart <laurentp@cse-semaphore.com>
> Cc: Grant Likely <grant.likely@secretlab.ca>
> Cc: Mike Frysinger <vapier.adi@gmail.com>
> ---
>
> drivers/net/phy/Kconfig | 7 +
> drivers/net/phy/Makefile | 2
> drivers/net/phy/mdio-gpio.c | 308 +++++++++++++++++++++++++++++++++++++++++
> drivers/net/phy/mdio-ofgpio.c | 204 ---------------------------
> include/linux/mdio-gpio.h | 30 ++++
> 5 files changed, 344 insertions(+), 207 deletions(-)
> create mode 100644 drivers/net/phy/mdio-gpio.c
> delete mode 100644 drivers/net/phy/mdio-ofgpio.c
> create mode 100644 include/linux/mdio-gpio.h
>
>
> diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
> index d55932a..c4c5a2f 100644
> --- a/drivers/net/phy/Kconfig
> +++ b/drivers/net/phy/Kconfig
> @@ -84,10 +84,13 @@ config MDIO_BITBANG
>
> If in doubt, say N.
>
> -config MDIO_OF_GPIO
> +config MDIO_GPIO
> tristate "Support for GPIO lib-based bitbanged MDIO buses"
> - depends on MDIO_BITBANG && OF_GPIO
> + depends on MDIO_BITBANG && GENERIC_GPIO
> ---help---
> Supports GPIO lib-based MDIO busses.
>
> + To compile this driver as a module, choose M here: the module
> + will be called mdio-gpio.
> +
> endif # PHYLIB
> diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
> index eee329f..9ae5d30 100644
> --- a/drivers/net/phy/Makefile
> +++ b/drivers/net/phy/Makefile
> @@ -15,4 +15,4 @@ obj-$(CONFIG_ICPLUS_PHY) += icplus.o
> obj-$(CONFIG_REALTEK_PHY) += realtek.o
> obj-$(CONFIG_FIXED_PHY) += fixed.o
> obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o
> -obj-$(CONFIG_MDIO_OF_GPIO) += mdio-ofgpio.o
> +obj-$(CONFIG_MDIO_GPIO) += mdio-gpio.o
> diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c
> new file mode 100644
> index 0000000..a7b94ac
> --- /dev/null
> +++ b/drivers/net/phy/mdio-gpio.c
> @@ -0,0 +1,308 @@
> +/*
> + * GPIO based MDIO bitbang driver.
> + * Supports OpenFirmware.
> + *
> + * Copyright (c) 2008 CSE Semaphore Belgium.
> + * by Laurent Pinchart <laurentp@cse-semaphore.com>
> + *
> + * Copyright (C) 2008, Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
> + *
> + * Based on earlier work by
> + *
> + * Copyright (c) 2003 Intracom S.A.
> + * by Pantelis Antoniou <panto@intracom.gr>
> + *
> + * 2005 (c) MontaVista Software, Inc.
> + * Vitaly Bordug <vbordug@ru.mvista.com>
> + *
> + * This file is licensed under the terms of the GNU General Public License
> + * version 2. This program is licensed "as is" without any warranty of any
> + * kind, whether express or implied.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/mdio-bitbang.h>
> +#ifdef CONFIG_OF_GPIO
> +# include <linux/of_gpio.h>
> +# include <linux/of_platform.h>
> +#else
> +# include <linux/platform_device.h>
> +# include <linux/gpio.h>
> +# include <linux/mdio-gpio.h>
> +#endif
> +
> +#ifndef NO_IRQ
> +#define NO_IRQ 0
> +#endif
> +
> +struct mdio_gpio_info {
> + struct mdiobb_ctrl ctrl;
> + int mdc, mdio;
> + int irq[PHY_MAX_ADDR];
> +};
> +
> +static void mdio_dir(struct mdiobb_ctrl *ctrl, int dir)
> +{
> + struct mdio_gpio_info *bitbang =
> + container_of(ctrl, struct mdio_gpio_info, ctrl);
> +
> + if (dir)
> + gpio_direction_output(bitbang->mdio, 1);
> + else
> + gpio_direction_input(bitbang->mdio);
> +}
> +
> +static int mdio_get(struct mdiobb_ctrl *ctrl)
> +{
> + struct mdio_gpio_info *bitbang =
> + container_of(ctrl, struct mdio_gpio_info, ctrl);
> +
> + return gpio_get_value(bitbang->mdio);
> +}
> +
> +static void mdio_set(struct mdiobb_ctrl *ctrl, int what)
> +{
> + struct mdio_gpio_info *bitbang =
> + container_of(ctrl, struct mdio_gpio_info, ctrl);
> +
> + gpio_set_value(bitbang->mdio, what);
> +}
> +
> +static void mdc_set(struct mdiobb_ctrl *ctrl, int what)
> +{
> + struct mdio_gpio_info *bitbang =
> + container_of(ctrl, struct mdio_gpio_info, ctrl);
> +
> + gpio_set_value(bitbang->mdc, what);
> +}
> +
> +static struct mdiobb_ops mdio_gpio_ops = {
> + .owner = THIS_MODULE,
> + .set_mdc = mdc_set,
> + .set_mdio_dir = mdio_dir,
> + .set_mdio_data = mdio_set,
> + .get_mdio_data = mdio_get,
> +};
> +
> +#ifdef CONFIG_OF_GPIO
> +static int __devinit mdio_ofgpio_bitbang_init(struct mii_bus *bus,
> + struct device_node *np)
> +{
> + struct mdio_gpio_info *bitbang = bus->priv;
> +
> + bitbang->mdc = of_get_gpio(np, 0);
> + bitbang->mdio = of_get_gpio(np, 1);
> +
> + if (bitbang->mdc < 0 || bitbang->mdio < 0)
> + return -ENODEV;
> +
> + snprintf(bus->id, MII_BUS_ID_SIZE, "%x", bitbang->mdc);
> + return 0;
> +}
> +#else
> +static void __devinit mdio_gpio_bitbang_init(struct mii_bus *bus,
> + struct mdio_gpio_platform_data *pdata,
> + int bus_id)
> +{
> + struct mdio_gpio_info *bitbang = bus->priv;
> +
> + bitbang->mdc = pdata->mdc;
> + bitbang->mdio = pdata->mdio;
> +
> + snprintf(bus->id, MII_BUS_ID_SIZE, "phy%i", bus_id);
> +}
> +#endif
> +
> +static void __devinit add_phy(struct mii_bus *bus, unsigned int phy_addr,
> + int phy_irq)
> +{
> + if (phy_addr >= PHY_MAX_ADDR) {
> + dev_err(bus->parent,
> + "Failed to add phy with invalid address: 0x%x",
> + phy_addr);
> + return;
> + }
> +
> + bus->phy_mask &= ~(1 << phy_addr);
> +
> + if (phy_irq != NO_IRQ)
> + bus->irq[phy_addr] = phy_irq;
> +}
> +
> +#ifdef CONFIG_OF_GPIO
> +static int __devinit mdio_ofgpio_probe(struct of_device *ofdev,
> + const struct of_device_id *match)
> +{
> + struct device_node *np = NULL;
> + struct device *dev = &ofdev->dev;
> +#else
> +static int __devinit mdio_gpio_probe(struct platform_device *pdev)
> +{
> + struct mdio_gpio_platform_data *pdata;
> + struct device *dev = &pdev->dev;
> +#endif
> + struct mii_bus *new_bus;
> + struct mdio_gpio_info *bitbang;
> + int ret = -ENOMEM;
> + int i;
> +
> +#ifndef CONFIG_OF_GPIO
> + pdata = dev->platform_data;
> + if (pdata == NULL)
> + goto out;
> +#endif
> +
> + bitbang = kzalloc(sizeof(*bitbang), GFP_KERNEL);
> + if (!bitbang)
> + goto out;
> +
> + bitbang->ctrl.ops = &mdio_gpio_ops;
> +
> + new_bus = alloc_mdio_bitbang(&bitbang->ctrl);
> + if (!new_bus)
> + goto out_free_bitbang;
> +
> + new_bus->name = "GPIO Bitbanged MDIO",
> +
> +#ifdef CONFIG_OF_GPIO
> + ret = mdio_ofgpio_bitbang_init(new_bus, ofdev->node);
> + if (ret)
> + goto out_free_bus;
> +#else
> + mdio_gpio_bitbang_init(new_bus, pdata, pdev->id);
> +#endif
> +
> + ret = -ENODEV;
> +
> + if (gpio_request(bitbang->mdc, "mdc"))
> + goto out_free_bus;
> +
> + if (gpio_request(bitbang->mdio, "mdio"))
> + goto out_free_mdc;
> +
> + new_bus->phy_mask = ~0;
> + new_bus->irq = bitbang->irq;
> + new_bus->parent = dev;
> +
> + for (i = 0; i < PHY_MAX_ADDR; i++)
> + new_bus->irq[i] = PHY_POLL;
> +
> +#ifdef CONFIG_OF_GPIO
> + while ((np = of_get_next_child(ofdev->node, np)))
> + if (!strcmp(np->type, "ethernet-phy")) {
> + const u32 *data;
> + int len;
> +
> + data = of_get_property(np, "reg", &len);
> + if (!data || len != 4)
> + continue;
> +
> + add_phy(new_bus, *data,
> + of_irq_to_resource(np, 0, NULL));
> + }
> +#else
> + for (i = 0; i < pdata->nr_phys; i++)
> + add_phy(new_bus, pdata->phys[i].addr, pdata->phys[i].irq);
> +#endif
> +
> + if (new_bus->phy_mask == ~0)
> + goto out_free_gpio;
> +
> + dev_set_drvdata(dev, new_bus);
> +
> + ret = mdiobus_register(new_bus);
> + if (ret)
> + goto out_free_all;
> +
> + return 0;
> +
> +out_free_all:
> + dev_set_drvdata(dev, NULL);
> +out_free_gpio:
> + gpio_free(bitbang->mdio);
> +out_free_mdc:
> + gpio_free(bitbang->mdc);
> +out_free_bus:
> + free_mdio_bitbang(new_bus);
> +out_free_bitbang:
> + kfree(bitbang);
> +out:
> + return ret;
> +}
> +
> +#ifdef CONFIG_OF_GPIO
> +static int mdio_ofgpio_remove(struct of_device *ofdev)
> +{
> + struct device *dev = &ofdev->dev;
> +#else
> +static int __devexit mdio_gpio_remove(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> +#endif
> + struct mii_bus *bus = dev_get_drvdata(dev);
> + struct mdio_gpio_info *bitbang = bus->priv;
> +
> + mdiobus_unregister(bus);
> + free_mdio_bitbang(bus);
> + dev_set_drvdata(dev, NULL);
> + gpio_free(bitbang->mdc);
> + gpio_free(bitbang->mdio);
> + kfree(bitbang);
> +
> + return 0;
> +}
> +
> +#ifdef CONFIG_OF_GPIO
> +static struct of_device_id mdio_ofgpio_match[] = {
> + {
> + .compatible = "virtual,mdio-gpio",
> + },
> + {},
> +};
> +
> +static struct of_platform_driver mdio_ofgpio_driver = {
> + .name = "mdio-gpio",
> + .match_table = mdio_ofgpio_match,
> + .probe = mdio_ofgpio_probe,
> + .remove = mdio_ofgpio_remove,
> +};
> +#else
> +static struct platform_driver mdio_gpio_driver = {
> + .probe = mdio_gpio_probe,
> + .remove = __devexit_p(mdio_gpio_remove),
> + .driver = {
> + .name = "mdio-gpio",
> + .owner = THIS_MODULE,
> + },
> +};
> +#endif
> +
> +static int __init mdio_gpio_init(void)
> +{
> +#ifdef CONFIG_OF_GPIO
> + return of_register_platform_driver(&mdio_ofgpio_driver);
> +#else
> + return platform_driver_register(&mdio_gpio_driver);
> +#endif
> +}
> +module_init(mdio_gpio_init);
> +
> +static void __exit mdio_gpio_exit(void)
> +{
> +#ifdef CONFIG_OF_GPIO
> + of_unregister_platform_driver(&mdio_ofgpio_driver);
> +#else
> + platform_driver_unregister(&mdio_gpio_driver);
> +#endif
> +}
> +module_exit(mdio_gpio_exit);
> +
> +#ifndef CONFIG_OF_GPIO
> +MODULE_ALIAS("platform:mdio-gpio");
> +#endif
> +MODULE_AUTHOR("Laurent Pinchart, Paulius Zaleckas");
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Generic driver for MDIO bus emulation using GPIO");
> diff --git a/drivers/net/phy/mdio-ofgpio.c b/drivers/net/phy/mdio-ofgpio.c
> deleted file mode 100644
> index 2ff9775..0000000
> --- a/drivers/net/phy/mdio-ofgpio.c
> +++ /dev/null
> @@ -1,204 +0,0 @@
> -/*
> - * OpenFirmware GPIO based MDIO bitbang driver.
> - *
> - * Copyright (c) 2008 CSE Semaphore Belgium.
> - * by Laurent Pinchart <laurentp@cse-semaphore.com>
> - *
> - * Based on earlier work by
> - *
> - * Copyright (c) 2003 Intracom S.A.
> - * by Pantelis Antoniou <panto@intracom.gr>
> - *
> - * 2005 (c) MontaVista Software, Inc.
> - * Vitaly Bordug <vbordug@ru.mvista.com>
> - *
> - * This file is licensed under the terms of the GNU General Public License
> - * version 2. This program is licensed "as is" without any warranty of any
> - * kind, whether express or implied.
> - */
> -
> -#include <linux/module.h>
> -#include <linux/slab.h>
> -#include <linux/init.h>
> -#include <linux/interrupt.h>
> -#include <linux/mdio-bitbang.h>
> -#include <linux/of_gpio.h>
> -#include <linux/of_platform.h>
> -
> -struct mdio_gpio_info {
> - struct mdiobb_ctrl ctrl;
> - int mdc, mdio;
> -};
> -
> -static void mdio_dir(struct mdiobb_ctrl *ctrl, int dir)
> -{
> - struct mdio_gpio_info *bitbang =
> - container_of(ctrl, struct mdio_gpio_info, ctrl);
> -
> - if (dir)
> - gpio_direction_output(bitbang->mdio, 1);
> - else
> - gpio_direction_input(bitbang->mdio);
> -}
> -
> -static int mdio_read(struct mdiobb_ctrl *ctrl)
> -{
> - struct mdio_gpio_info *bitbang =
> - container_of(ctrl, struct mdio_gpio_info, ctrl);
> -
> - return gpio_get_value(bitbang->mdio);
> -}
> -
> -static void mdio(struct mdiobb_ctrl *ctrl, int what)
> -{
> - struct mdio_gpio_info *bitbang =
> - container_of(ctrl, struct mdio_gpio_info, ctrl);
> -
> - gpio_set_value(bitbang->mdio, what);
> -}
> -
> -static void mdc(struct mdiobb_ctrl *ctrl, int what)
> -{
> - struct mdio_gpio_info *bitbang =
> - container_of(ctrl, struct mdio_gpio_info, ctrl);
> -
> - gpio_set_value(bitbang->mdc, what);
> -}
> -
> -static struct mdiobb_ops mdio_gpio_ops = {
> - .owner = THIS_MODULE,
> - .set_mdc = mdc,
> - .set_mdio_dir = mdio_dir,
> - .set_mdio_data = mdio,
> - .get_mdio_data = mdio_read,
> -};
> -
> -static int __devinit mdio_ofgpio_bitbang_init(struct mii_bus *bus,
> - struct device_node *np)
> -{
> - struct mdio_gpio_info *bitbang = bus->priv;
> -
> - bitbang->mdc = of_get_gpio(np, 0);
> - bitbang->mdio = of_get_gpio(np, 1);
> -
> - if (bitbang->mdc < 0 || bitbang->mdio < 0)
> - return -ENODEV;
> -
> - snprintf(bus->id, MII_BUS_ID_SIZE, "%x", bitbang->mdc);
> - return 0;
> -}
> -
> -static void __devinit add_phy(struct mii_bus *bus, struct device_node *np)
> -{
> - const u32 *data;
> - int len, id, irq;
> -
> - data = of_get_property(np, "reg", &len);
> - if (!data || len != 4)
> - return;
> -
> - id = *data;
> - bus->phy_mask &= ~(1 << id);
> -
> - irq = of_irq_to_resource(np, 0, NULL);
> - if (irq != NO_IRQ)
> - bus->irq[id] = irq;
> -}
> -
> -static int __devinit mdio_ofgpio_probe(struct of_device *ofdev,
> - const struct of_device_id *match)
> -{
> - struct device_node *np = NULL;
> - struct mii_bus *new_bus;
> - struct mdio_gpio_info *bitbang;
> - int ret = -ENOMEM;
> - int i;
> -
> - bitbang = kzalloc(sizeof(struct mdio_gpio_info), GFP_KERNEL);
> - if (!bitbang)
> - goto out;
> -
> - bitbang->ctrl.ops = &mdio_gpio_ops;
> -
> - new_bus = alloc_mdio_bitbang(&bitbang->ctrl);
> - if (!new_bus)
> - goto out_free_bitbang;
> -
> - new_bus->name = "GPIO Bitbanged MII",
> -
> - ret = mdio_ofgpio_bitbang_init(new_bus, ofdev->node);
> - if (ret)
> - goto out_free_bus;
> -
> - new_bus->phy_mask = ~0;
> - new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
> - if (!new_bus->irq)
> - goto out_free_bus;
> -
> - for (i = 0; i < PHY_MAX_ADDR; i++)
> - new_bus->irq[i] = -1;
> -
> - while ((np = of_get_next_child(ofdev->node, np)))
> - if (!strcmp(np->type, "ethernet-phy"))
> - add_phy(new_bus, np);
> -
> - new_bus->parent = &ofdev->dev;
> - dev_set_drvdata(&ofdev->dev, new_bus);
> -
> - ret = mdiobus_register(new_bus);
> - if (ret)
> - goto out_free_irqs;
> -
> - return 0;
> -
> -out_free_irqs:
> - dev_set_drvdata(&ofdev->dev, NULL);
> - kfree(new_bus->irq);
> -out_free_bus:
> - free_mdio_bitbang(new_bus);
> -out_free_bitbang:
> - kfree(bitbang);
> -out:
> - return ret;
> -}
> -
> -static int mdio_ofgpio_remove(struct of_device *ofdev)
> -{
> - struct mii_bus *bus = dev_get_drvdata(&ofdev->dev);
> - struct mdio_gpio_info *bitbang = bus->priv;
> -
> - mdiobus_unregister(bus);
> - kfree(bus->irq);
> - free_mdio_bitbang(bus);
> - dev_set_drvdata(&ofdev->dev, NULL);
> - kfree(bitbang);
> -
> - return 0;
> -}
> -
> -static struct of_device_id mdio_ofgpio_match[] = {
> - {
> - .compatible = "virtual,mdio-gpio",
> - },
> - {},
> -};
> -
> -static struct of_platform_driver mdio_ofgpio_driver = {
> - .name = "mdio-gpio",
> - .match_table = mdio_ofgpio_match,
> - .probe = mdio_ofgpio_probe,
> - .remove = mdio_ofgpio_remove,
> -};
> -
> -static int mdio_ofgpio_init(void)
> -{
> - return of_register_platform_driver(&mdio_ofgpio_driver);
> -}
> -
> -static void mdio_ofgpio_exit(void)
> -{
> - of_unregister_platform_driver(&mdio_ofgpio_driver);
> -}
> -
> -module_init(mdio_ofgpio_init);
> -module_exit(mdio_ofgpio_exit);
> diff --git a/include/linux/mdio-gpio.h b/include/linux/mdio-gpio.h
> new file mode 100644
> index 0000000..5ca24ed
> --- /dev/null
> +++ b/include/linux/mdio-gpio.h
> @@ -0,0 +1,30 @@
> +/*
> + * MDIO-GPIO bus platform data structures
> + *
> + * Copyright (C) 2008, Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
> + *
> + * This file is licensed under the terms of the GNU General Public License
> + * version 2. This program is licensed "as is" without any warranty of any
> + * kind, whether express or implied.
> + */
> +
> +#ifndef __LINUX_MDIO_GPIO_H
> +#define __LINUX_MDIO_GPIO_H
> +
> +struct mdio_gpio_phy {
> + /* PHY address on MDIO bus */
> + unsigned int addr;
> + /* preconfigured irq connected to PHY or -1 if no irq */
> + int irq;
> +};
> +
> +struct mdio_gpio_platform_data {
> + /* GPIO numbers for bus pins */
> + unsigned int mdc;
> + unsigned int mdio;
> +
> + unsigned int nr_phys;
> + struct mdio_gpio_phy *phys;
> +};
> +
> +#endif /* __LINUX_MDIO_GPIO_H */
>
>
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* [PATCH 0/2] phylib: mdio-ofgpio ---> mdio-gpio (v2)
From: Paulius Zaleckas @ 2008-10-31 16:45 UTC (permalink / raw)
To: netdev; +Cc: linux-arm-kernel, linux-embedded
Changes since v1:
- broken to rename patch and mdio-gpio rework
---
Paulius Zaleckas (2):
phylib: make mdio-gpio work without OF
phylib: rename mdio-ofgpio to mdio-gpio
drivers/net/phy/Kconfig | 7 +
drivers/net/phy/Makefile | 2
drivers/net/phy/mdio-gpio.c | 308 +++++++++++++++++++++++++++++++++++++++++
drivers/net/phy/mdio-ofgpio.c | 204 ---------------------------
include/linux/mdio-gpio.h | 30 ++++
5 files changed, 344 insertions(+), 207 deletions(-)
create mode 100644 drivers/net/phy/mdio-gpio.c
delete mode 100644 drivers/net/phy/mdio-ofgpio.c
create mode 100644 include/linux/mdio-gpio.h
^ permalink raw reply
* [PATCH 1/2] phylib: rename mdio-ofgpio to mdio-gpio
From: Paulius Zaleckas @ 2008-10-31 16:49 UTC (permalink / raw)
To: netdev
Cc: linux-arm-kernel, linux-embedded, Paulius Zaleckas,
Laurent Pinchart, Grant Likely, Mike Frysinger
In-Reply-To: <20081031164132.20490.27608.stgit@Programuotojas.82-135-208-232.ip.zebra.lt>
Signed-off-by: Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
Cc: Laurent Pinchart <laurentp@cse-semaphore.com>
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: Mike Frysinger <vapier.adi@gmail.com>
---
drivers/net/phy/Kconfig | 2
drivers/net/phy/Makefile | 2
drivers/net/phy/mdio-gpio.c | 204 +++++++++++++++++++++++++++++++++++++++++
drivers/net/phy/mdio-ofgpio.c | 204 -----------------------------------------
4 files changed, 206 insertions(+), 206 deletions(-)
create mode 100644 drivers/net/phy/mdio-gpio.c
delete mode 100644 drivers/net/phy/mdio-ofgpio.c
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index d55932a..0318077 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -84,7 +84,7 @@ config MDIO_BITBANG
If in doubt, say N.
-config MDIO_OF_GPIO
+config MDIO_GPIO
tristate "Support for GPIO lib-based bitbanged MDIO buses"
depends on MDIO_BITBANG && OF_GPIO
---help---
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index eee329f..9ae5d30 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -15,4 +15,4 @@ obj-$(CONFIG_ICPLUS_PHY) += icplus.o
obj-$(CONFIG_REALTEK_PHY) += realtek.o
obj-$(CONFIG_FIXED_PHY) += fixed.o
obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o
-obj-$(CONFIG_MDIO_OF_GPIO) += mdio-ofgpio.o
+obj-$(CONFIG_MDIO_GPIO) += mdio-gpio.o
diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c
new file mode 100644
index 0000000..2ff9775
--- /dev/null
+++ b/drivers/net/phy/mdio-gpio.c
@@ -0,0 +1,204 @@
+/*
+ * OpenFirmware GPIO based MDIO bitbang driver.
+ *
+ * Copyright (c) 2008 CSE Semaphore Belgium.
+ * by Laurent Pinchart <laurentp@cse-semaphore.com>
+ *
+ * Based on earlier work by
+ *
+ * Copyright (c) 2003 Intracom S.A.
+ * by Pantelis Antoniou <panto@intracom.gr>
+ *
+ * 2005 (c) MontaVista Software, Inc.
+ * Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/mdio-bitbang.h>
+#include <linux/of_gpio.h>
+#include <linux/of_platform.h>
+
+struct mdio_gpio_info {
+ struct mdiobb_ctrl ctrl;
+ int mdc, mdio;
+};
+
+static void mdio_dir(struct mdiobb_ctrl *ctrl, int dir)
+{
+ struct mdio_gpio_info *bitbang =
+ container_of(ctrl, struct mdio_gpio_info, ctrl);
+
+ if (dir)
+ gpio_direction_output(bitbang->mdio, 1);
+ else
+ gpio_direction_input(bitbang->mdio);
+}
+
+static int mdio_read(struct mdiobb_ctrl *ctrl)
+{
+ struct mdio_gpio_info *bitbang =
+ container_of(ctrl, struct mdio_gpio_info, ctrl);
+
+ return gpio_get_value(bitbang->mdio);
+}
+
+static void mdio(struct mdiobb_ctrl *ctrl, int what)
+{
+ struct mdio_gpio_info *bitbang =
+ container_of(ctrl, struct mdio_gpio_info, ctrl);
+
+ gpio_set_value(bitbang->mdio, what);
+}
+
+static void mdc(struct mdiobb_ctrl *ctrl, int what)
+{
+ struct mdio_gpio_info *bitbang =
+ container_of(ctrl, struct mdio_gpio_info, ctrl);
+
+ gpio_set_value(bitbang->mdc, what);
+}
+
+static struct mdiobb_ops mdio_gpio_ops = {
+ .owner = THIS_MODULE,
+ .set_mdc = mdc,
+ .set_mdio_dir = mdio_dir,
+ .set_mdio_data = mdio,
+ .get_mdio_data = mdio_read,
+};
+
+static int __devinit mdio_ofgpio_bitbang_init(struct mii_bus *bus,
+ struct device_node *np)
+{
+ struct mdio_gpio_info *bitbang = bus->priv;
+
+ bitbang->mdc = of_get_gpio(np, 0);
+ bitbang->mdio = of_get_gpio(np, 1);
+
+ if (bitbang->mdc < 0 || bitbang->mdio < 0)
+ return -ENODEV;
+
+ snprintf(bus->id, MII_BUS_ID_SIZE, "%x", bitbang->mdc);
+ return 0;
+}
+
+static void __devinit add_phy(struct mii_bus *bus, struct device_node *np)
+{
+ const u32 *data;
+ int len, id, irq;
+
+ data = of_get_property(np, "reg", &len);
+ if (!data || len != 4)
+ return;
+
+ id = *data;
+ bus->phy_mask &= ~(1 << id);
+
+ irq = of_irq_to_resource(np, 0, NULL);
+ if (irq != NO_IRQ)
+ bus->irq[id] = irq;
+}
+
+static int __devinit mdio_ofgpio_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ struct device_node *np = NULL;
+ struct mii_bus *new_bus;
+ struct mdio_gpio_info *bitbang;
+ int ret = -ENOMEM;
+ int i;
+
+ bitbang = kzalloc(sizeof(struct mdio_gpio_info), GFP_KERNEL);
+ if (!bitbang)
+ goto out;
+
+ bitbang->ctrl.ops = &mdio_gpio_ops;
+
+ new_bus = alloc_mdio_bitbang(&bitbang->ctrl);
+ if (!new_bus)
+ goto out_free_bitbang;
+
+ new_bus->name = "GPIO Bitbanged MII",
+
+ ret = mdio_ofgpio_bitbang_init(new_bus, ofdev->node);
+ if (ret)
+ goto out_free_bus;
+
+ new_bus->phy_mask = ~0;
+ new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
+ if (!new_bus->irq)
+ goto out_free_bus;
+
+ for (i = 0; i < PHY_MAX_ADDR; i++)
+ new_bus->irq[i] = -1;
+
+ while ((np = of_get_next_child(ofdev->node, np)))
+ if (!strcmp(np->type, "ethernet-phy"))
+ add_phy(new_bus, np);
+
+ new_bus->parent = &ofdev->dev;
+ dev_set_drvdata(&ofdev->dev, new_bus);
+
+ ret = mdiobus_register(new_bus);
+ if (ret)
+ goto out_free_irqs;
+
+ return 0;
+
+out_free_irqs:
+ dev_set_drvdata(&ofdev->dev, NULL);
+ kfree(new_bus->irq);
+out_free_bus:
+ free_mdio_bitbang(new_bus);
+out_free_bitbang:
+ kfree(bitbang);
+out:
+ return ret;
+}
+
+static int mdio_ofgpio_remove(struct of_device *ofdev)
+{
+ struct mii_bus *bus = dev_get_drvdata(&ofdev->dev);
+ struct mdio_gpio_info *bitbang = bus->priv;
+
+ mdiobus_unregister(bus);
+ kfree(bus->irq);
+ free_mdio_bitbang(bus);
+ dev_set_drvdata(&ofdev->dev, NULL);
+ kfree(bitbang);
+
+ return 0;
+}
+
+static struct of_device_id mdio_ofgpio_match[] = {
+ {
+ .compatible = "virtual,mdio-gpio",
+ },
+ {},
+};
+
+static struct of_platform_driver mdio_ofgpio_driver = {
+ .name = "mdio-gpio",
+ .match_table = mdio_ofgpio_match,
+ .probe = mdio_ofgpio_probe,
+ .remove = mdio_ofgpio_remove,
+};
+
+static int mdio_ofgpio_init(void)
+{
+ return of_register_platform_driver(&mdio_ofgpio_driver);
+}
+
+static void mdio_ofgpio_exit(void)
+{
+ of_unregister_platform_driver(&mdio_ofgpio_driver);
+}
+
+module_init(mdio_ofgpio_init);
+module_exit(mdio_ofgpio_exit);
diff --git a/drivers/net/phy/mdio-ofgpio.c b/drivers/net/phy/mdio-ofgpio.c
deleted file mode 100644
index 2ff9775..0000000
--- a/drivers/net/phy/mdio-ofgpio.c
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * OpenFirmware GPIO based MDIO bitbang driver.
- *
- * Copyright (c) 2008 CSE Semaphore Belgium.
- * by Laurent Pinchart <laurentp@cse-semaphore.com>
- *
- * Based on earlier work by
- *
- * Copyright (c) 2003 Intracom S.A.
- * by Pantelis Antoniou <panto@intracom.gr>
- *
- * 2005 (c) MontaVista Software, Inc.
- * Vitaly Bordug <vbordug@ru.mvista.com>
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/mdio-bitbang.h>
-#include <linux/of_gpio.h>
-#include <linux/of_platform.h>
-
-struct mdio_gpio_info {
- struct mdiobb_ctrl ctrl;
- int mdc, mdio;
-};
-
-static void mdio_dir(struct mdiobb_ctrl *ctrl, int dir)
-{
- struct mdio_gpio_info *bitbang =
- container_of(ctrl, struct mdio_gpio_info, ctrl);
-
- if (dir)
- gpio_direction_output(bitbang->mdio, 1);
- else
- gpio_direction_input(bitbang->mdio);
-}
-
-static int mdio_read(struct mdiobb_ctrl *ctrl)
-{
- struct mdio_gpio_info *bitbang =
- container_of(ctrl, struct mdio_gpio_info, ctrl);
-
- return gpio_get_value(bitbang->mdio);
-}
-
-static void mdio(struct mdiobb_ctrl *ctrl, int what)
-{
- struct mdio_gpio_info *bitbang =
- container_of(ctrl, struct mdio_gpio_info, ctrl);
-
- gpio_set_value(bitbang->mdio, what);
-}
-
-static void mdc(struct mdiobb_ctrl *ctrl, int what)
-{
- struct mdio_gpio_info *bitbang =
- container_of(ctrl, struct mdio_gpio_info, ctrl);
-
- gpio_set_value(bitbang->mdc, what);
-}
-
-static struct mdiobb_ops mdio_gpio_ops = {
- .owner = THIS_MODULE,
- .set_mdc = mdc,
- .set_mdio_dir = mdio_dir,
- .set_mdio_data = mdio,
- .get_mdio_data = mdio_read,
-};
-
-static int __devinit mdio_ofgpio_bitbang_init(struct mii_bus *bus,
- struct device_node *np)
-{
- struct mdio_gpio_info *bitbang = bus->priv;
-
- bitbang->mdc = of_get_gpio(np, 0);
- bitbang->mdio = of_get_gpio(np, 1);
-
- if (bitbang->mdc < 0 || bitbang->mdio < 0)
- return -ENODEV;
-
- snprintf(bus->id, MII_BUS_ID_SIZE, "%x", bitbang->mdc);
- return 0;
-}
-
-static void __devinit add_phy(struct mii_bus *bus, struct device_node *np)
-{
- const u32 *data;
- int len, id, irq;
-
- data = of_get_property(np, "reg", &len);
- if (!data || len != 4)
- return;
-
- id = *data;
- bus->phy_mask &= ~(1 << id);
-
- irq = of_irq_to_resource(np, 0, NULL);
- if (irq != NO_IRQ)
- bus->irq[id] = irq;
-}
-
-static int __devinit mdio_ofgpio_probe(struct of_device *ofdev,
- const struct of_device_id *match)
-{
- struct device_node *np = NULL;
- struct mii_bus *new_bus;
- struct mdio_gpio_info *bitbang;
- int ret = -ENOMEM;
- int i;
-
- bitbang = kzalloc(sizeof(struct mdio_gpio_info), GFP_KERNEL);
- if (!bitbang)
- goto out;
-
- bitbang->ctrl.ops = &mdio_gpio_ops;
-
- new_bus = alloc_mdio_bitbang(&bitbang->ctrl);
- if (!new_bus)
- goto out_free_bitbang;
-
- new_bus->name = "GPIO Bitbanged MII",
-
- ret = mdio_ofgpio_bitbang_init(new_bus, ofdev->node);
- if (ret)
- goto out_free_bus;
-
- new_bus->phy_mask = ~0;
- new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
- if (!new_bus->irq)
- goto out_free_bus;
-
- for (i = 0; i < PHY_MAX_ADDR; i++)
- new_bus->irq[i] = -1;
-
- while ((np = of_get_next_child(ofdev->node, np)))
- if (!strcmp(np->type, "ethernet-phy"))
- add_phy(new_bus, np);
-
- new_bus->parent = &ofdev->dev;
- dev_set_drvdata(&ofdev->dev, new_bus);
-
- ret = mdiobus_register(new_bus);
- if (ret)
- goto out_free_irqs;
-
- return 0;
-
-out_free_irqs:
- dev_set_drvdata(&ofdev->dev, NULL);
- kfree(new_bus->irq);
-out_free_bus:
- free_mdio_bitbang(new_bus);
-out_free_bitbang:
- kfree(bitbang);
-out:
- return ret;
-}
-
-static int mdio_ofgpio_remove(struct of_device *ofdev)
-{
- struct mii_bus *bus = dev_get_drvdata(&ofdev->dev);
- struct mdio_gpio_info *bitbang = bus->priv;
-
- mdiobus_unregister(bus);
- kfree(bus->irq);
- free_mdio_bitbang(bus);
- dev_set_drvdata(&ofdev->dev, NULL);
- kfree(bitbang);
-
- return 0;
-}
-
-static struct of_device_id mdio_ofgpio_match[] = {
- {
- .compatible = "virtual,mdio-gpio",
- },
- {},
-};
-
-static struct of_platform_driver mdio_ofgpio_driver = {
- .name = "mdio-gpio",
- .match_table = mdio_ofgpio_match,
- .probe = mdio_ofgpio_probe,
- .remove = mdio_ofgpio_remove,
-};
-
-static int mdio_ofgpio_init(void)
-{
- return of_register_platform_driver(&mdio_ofgpio_driver);
-}
-
-static void mdio_ofgpio_exit(void)
-{
- of_unregister_platform_driver(&mdio_ofgpio_driver);
-}
-
-module_init(mdio_ofgpio_init);
-module_exit(mdio_ofgpio_exit);
^ permalink raw reply related
* [PATCH 2/2] phylib: make mdio-gpio work without OF
From: Paulius Zaleckas @ 2008-10-31 16:49 UTC (permalink / raw)
To: netdev
Cc: linux-arm-kernel, linux-embedded, Paulius Zaleckas,
Laurent Pinchart, Grant Likely, Mike Frysinger
In-Reply-To: <20081031164132.20490.27608.stgit@Programuotojas.82-135-208-232.ip.zebra.lt>
make mdio-gpio work with non OpenFirmware gpio implementation.
Aditional changes to mdio-gpio:
- use gpio_request() and gpio_free()
- place irq[] array in struct mdio_gpio_info
- add module description, author and license
- if NO_IRQ is not defined define it to 0
- add note about compiling this driver as module
- rename mdc and mdio function (were ugly names)
- change MII to MDIO in bus name
- add __init __exit to module (un)loading functions
- probe fails if no phys added to the bus
- kzalloc bitbang with sizeof(*bitbang)
Laurent, please test this driver under OF.
Signed-off-by: Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
Cc: Laurent Pinchart <laurentp@cse-semaphore.com>
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: Mike Frysinger <vapier.adi@gmail.com>
---
drivers/net/phy/Kconfig | 5 +
drivers/net/phy/mdio-gpio.c | 188 +++++++++++++++++++++++++++++++++----------
include/linux/mdio-gpio.h | 30 +++++++
3 files changed, 180 insertions(+), 43 deletions(-)
create mode 100644 include/linux/mdio-gpio.h
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 0318077..c4c5a2f 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -86,8 +86,11 @@ config MDIO_BITBANG
config MDIO_GPIO
tristate "Support for GPIO lib-based bitbanged MDIO buses"
- depends on MDIO_BITBANG && OF_GPIO
+ depends on MDIO_BITBANG && GENERIC_GPIO
---help---
Supports GPIO lib-based MDIO busses.
+ To compile this driver as a module, choose M here: the module
+ will be called mdio-gpio.
+
endif # PHYLIB
diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c
index 2ff9775..a7b94ac 100644
--- a/drivers/net/phy/mdio-gpio.c
+++ b/drivers/net/phy/mdio-gpio.c
@@ -1,9 +1,12 @@
/*
- * OpenFirmware GPIO based MDIO bitbang driver.
+ * GPIO based MDIO bitbang driver.
+ * Supports OpenFirmware.
*
* Copyright (c) 2008 CSE Semaphore Belgium.
* by Laurent Pinchart <laurentp@cse-semaphore.com>
*
+ * Copyright (C) 2008, Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ *
* Based on earlier work by
*
* Copyright (c) 2003 Intracom S.A.
@@ -22,12 +25,23 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/mdio-bitbang.h>
-#include <linux/of_gpio.h>
-#include <linux/of_platform.h>
+#ifdef CONFIG_OF_GPIO
+# include <linux/of_gpio.h>
+# include <linux/of_platform.h>
+#else
+# include <linux/platform_device.h>
+# include <linux/gpio.h>
+# include <linux/mdio-gpio.h>
+#endif
+
+#ifndef NO_IRQ
+#define NO_IRQ 0
+#endif
struct mdio_gpio_info {
struct mdiobb_ctrl ctrl;
int mdc, mdio;
+ int irq[PHY_MAX_ADDR];
};
static void mdio_dir(struct mdiobb_ctrl *ctrl, int dir)
@@ -41,7 +55,7 @@ static void mdio_dir(struct mdiobb_ctrl *ctrl, int dir)
gpio_direction_input(bitbang->mdio);
}
-static int mdio_read(struct mdiobb_ctrl *ctrl)
+static int mdio_get(struct mdiobb_ctrl *ctrl)
{
struct mdio_gpio_info *bitbang =
container_of(ctrl, struct mdio_gpio_info, ctrl);
@@ -49,7 +63,7 @@ static int mdio_read(struct mdiobb_ctrl *ctrl)
return gpio_get_value(bitbang->mdio);
}
-static void mdio(struct mdiobb_ctrl *ctrl, int what)
+static void mdio_set(struct mdiobb_ctrl *ctrl, int what)
{
struct mdio_gpio_info *bitbang =
container_of(ctrl, struct mdio_gpio_info, ctrl);
@@ -57,7 +71,7 @@ static void mdio(struct mdiobb_ctrl *ctrl, int what)
gpio_set_value(bitbang->mdio, what);
}
-static void mdc(struct mdiobb_ctrl *ctrl, int what)
+static void mdc_set(struct mdiobb_ctrl *ctrl, int what)
{
struct mdio_gpio_info *bitbang =
container_of(ctrl, struct mdio_gpio_info, ctrl);
@@ -67,12 +81,13 @@ static void mdc(struct mdiobb_ctrl *ctrl, int what)
static struct mdiobb_ops mdio_gpio_ops = {
.owner = THIS_MODULE,
- .set_mdc = mdc,
+ .set_mdc = mdc_set,
.set_mdio_dir = mdio_dir,
- .set_mdio_data = mdio,
- .get_mdio_data = mdio_read,
+ .set_mdio_data = mdio_set,
+ .get_mdio_data = mdio_get,
};
+#ifdef CONFIG_OF_GPIO
static int __devinit mdio_ofgpio_bitbang_init(struct mii_bus *bus,
struct device_node *np)
{
@@ -87,34 +102,60 @@ static int __devinit mdio_ofgpio_bitbang_init(struct mii_bus *bus,
snprintf(bus->id, MII_BUS_ID_SIZE, "%x", bitbang->mdc);
return 0;
}
-
-static void __devinit add_phy(struct mii_bus *bus, struct device_node *np)
+#else
+static void __devinit mdio_gpio_bitbang_init(struct mii_bus *bus,
+ struct mdio_gpio_platform_data *pdata,
+ int bus_id)
{
- const u32 *data;
- int len, id, irq;
+ struct mdio_gpio_info *bitbang = bus->priv;
+
+ bitbang->mdc = pdata->mdc;
+ bitbang->mdio = pdata->mdio;
+
+ snprintf(bus->id, MII_BUS_ID_SIZE, "phy%i", bus_id);
+}
+#endif
- data = of_get_property(np, "reg", &len);
- if (!data || len != 4)
+static void __devinit add_phy(struct mii_bus *bus, unsigned int phy_addr,
+ int phy_irq)
+{
+ if (phy_addr >= PHY_MAX_ADDR) {
+ dev_err(bus->parent,
+ "Failed to add phy with invalid address: 0x%x",
+ phy_addr);
return;
+ }
- id = *data;
- bus->phy_mask &= ~(1 << id);
+ bus->phy_mask &= ~(1 << phy_addr);
- irq = of_irq_to_resource(np, 0, NULL);
- if (irq != NO_IRQ)
- bus->irq[id] = irq;
+ if (phy_irq != NO_IRQ)
+ bus->irq[phy_addr] = phy_irq;
}
+#ifdef CONFIG_OF_GPIO
static int __devinit mdio_ofgpio_probe(struct of_device *ofdev,
const struct of_device_id *match)
{
struct device_node *np = NULL;
+ struct device *dev = &ofdev->dev;
+#else
+static int __devinit mdio_gpio_probe(struct platform_device *pdev)
+{
+ struct mdio_gpio_platform_data *pdata;
+ struct device *dev = &pdev->dev;
+#endif
struct mii_bus *new_bus;
struct mdio_gpio_info *bitbang;
int ret = -ENOMEM;
int i;
- bitbang = kzalloc(sizeof(struct mdio_gpio_info), GFP_KERNEL);
+#ifndef CONFIG_OF_GPIO
+ pdata = dev->platform_data;
+ if (pdata == NULL)
+ goto out;
+#endif
+
+ bitbang = kzalloc(sizeof(*bitbang), GFP_KERNEL);
if (!bitbang)
goto out;
@@ -124,36 +165,66 @@ static int __devinit mdio_ofgpio_probe(struct of_device *ofdev,
if (!new_bus)
goto out_free_bitbang;
- new_bus->name = "GPIO Bitbanged MII",
+ new_bus->name = "GPIO Bitbanged MDIO",
+#ifdef CONFIG_OF_GPIO
ret = mdio_ofgpio_bitbang_init(new_bus, ofdev->node);
if (ret)
goto out_free_bus;
+#else
+ mdio_gpio_bitbang_init(new_bus, pdata, pdev->id);
+#endif
- new_bus->phy_mask = ~0;
- new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
- if (!new_bus->irq)
+ ret = -ENODEV;
+
+ if (gpio_request(bitbang->mdc, "mdc"))
goto out_free_bus;
+ if (gpio_request(bitbang->mdio, "mdio"))
+ goto out_free_mdc;
+
+ new_bus->phy_mask = ~0;
+ new_bus->irq = bitbang->irq;
+ new_bus->parent = dev;
+
for (i = 0; i < PHY_MAX_ADDR; i++)
- new_bus->irq[i] = -1;
+ new_bus->irq[i] = PHY_POLL;
+#ifdef CONFIG_OF_GPIO
while ((np = of_get_next_child(ofdev->node, np)))
- if (!strcmp(np->type, "ethernet-phy"))
- add_phy(new_bus, np);
+ if (!strcmp(np->type, "ethernet-phy")) {
+ const u32 *data;
+ int len;
+
+ data = of_get_property(np, "reg", &len);
+ if (!data || len != 4)
+ continue;
+
+ add_phy(new_bus, *data,
+ of_irq_to_resource(np, 0, NULL));
+ }
+#else
+ for (i = 0; i < pdata->nr_phys; i++)
+ add_phy(new_bus, pdata->phys[i].addr, pdata->phys[i].irq);
+#endif
- new_bus->parent = &ofdev->dev;
- dev_set_drvdata(&ofdev->dev, new_bus);
+ if (new_bus->phy_mask == ~0)
+ goto out_free_gpio;
+
+ dev_set_drvdata(dev, new_bus);
ret = mdiobus_register(new_bus);
if (ret)
- goto out_free_irqs;
+ goto out_free_all;
return 0;
-out_free_irqs:
- dev_set_drvdata(&ofdev->dev, NULL);
- kfree(new_bus->irq);
+out_free_all:
+ dev_set_drvdata(dev, NULL);
+out_free_gpio:
+ gpio_free(bitbang->mdio);
+out_free_mdc:
+ gpio_free(bitbang->mdc);
out_free_bus:
free_mdio_bitbang(new_bus);
out_free_bitbang:
@@ -162,20 +233,29 @@ out:
return ret;
}
+#ifdef CONFIG_OF_GPIO
static int mdio_ofgpio_remove(struct of_device *ofdev)
{
- struct mii_bus *bus = dev_get_drvdata(&ofdev->dev);
+ struct device *dev = &ofdev->dev;
+#else
+static int __devexit mdio_gpio_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+#endif
+ struct mii_bus *bus = dev_get_drvdata(dev);
struct mdio_gpio_info *bitbang = bus->priv;
mdiobus_unregister(bus);
- kfree(bus->irq);
free_mdio_bitbang(bus);
- dev_set_drvdata(&ofdev->dev, NULL);
+ dev_set_drvdata(dev, NULL);
+ gpio_free(bitbang->mdc);
+ gpio_free(bitbang->mdio);
kfree(bitbang);
return 0;
}
+#ifdef CONFIG_OF_GPIO
static struct of_device_id mdio_ofgpio_match[] = {
{
.compatible = "virtual,mdio-gpio",
@@ -189,16 +269,40 @@ static struct of_platform_driver mdio_ofgpio_driver = {
.probe = mdio_ofgpio_probe,
.remove = mdio_ofgpio_remove,
};
+#else
+static struct platform_driver mdio_gpio_driver = {
+ .probe = mdio_gpio_probe,
+ .remove = __devexit_p(mdio_gpio_remove),
+ .driver = {
+ .name = "mdio-gpio",
+ .owner = THIS_MODULE,
+ },
+};
+#endif
-static int mdio_ofgpio_init(void)
+static int __init mdio_gpio_init(void)
{
+#ifdef CONFIG_OF_GPIO
return of_register_platform_driver(&mdio_ofgpio_driver);
+#else
+ return platform_driver_register(&mdio_gpio_driver);
+#endif
}
+module_init(mdio_gpio_init);
-static void mdio_ofgpio_exit(void)
+static void __exit mdio_gpio_exit(void)
{
+#ifdef CONFIG_OF_GPIO
of_unregister_platform_driver(&mdio_ofgpio_driver);
+#else
+ platform_driver_unregister(&mdio_gpio_driver);
+#endif
}
-
-module_init(mdio_ofgpio_init);
-module_exit(mdio_ofgpio_exit);
+module_exit(mdio_gpio_exit);
+
+#ifndef CONFIG_OF_GPIO
+MODULE_ALIAS("platform:mdio-gpio");
+#endif
+MODULE_AUTHOR("Laurent Pinchart, Paulius Zaleckas");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Generic driver for MDIO bus emulation using GPIO");
diff --git a/include/linux/mdio-gpio.h b/include/linux/mdio-gpio.h
new file mode 100644
index 0000000..5ca24ed
--- /dev/null
+++ b/include/linux/mdio-gpio.h
@@ -0,0 +1,30 @@
+/*
+ * MDIO-GPIO bus platform data structures
+ *
+ * Copyright (C) 2008, Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef __LINUX_MDIO_GPIO_H
+#define __LINUX_MDIO_GPIO_H
+
+struct mdio_gpio_phy {
+ /* PHY address on MDIO bus */
+ unsigned int addr;
+ /* preconfigured irq connected to PHY or -1 if no irq */
+ int irq;
+};
+
+struct mdio_gpio_platform_data {
+ /* GPIO numbers for bus pins */
+ unsigned int mdc;
+ unsigned int mdio;
+
+ unsigned int nr_phys;
+ struct mdio_gpio_phy *phys;
+};
+
+#endif /* __LINUX_MDIO_GPIO_H */
^ permalink raw reply related
* Re: [PATCH] phylib: mdio-ofgpio ---> mdio-gpio
From: Russell King - ARM Linux @ 2008-10-31 16:49 UTC (permalink / raw)
To: Grant Likely
Cc: Paulius Zaleckas, netdev, linux-arm-kernel, linux-embedded,
Laurent Pinchart, Mike Frysinger
In-Reply-To: <fa686aa40810310906j6845dd59kc9ccdce5c8213a0c@mail.gmail.com>
On Fri, Oct 31, 2008 at 10:06:26AM -0600, Grant Likely wrote:
> On Fri, Oct 31, 2008 at 9:53 AM, Paulius Zaleckas
> <paulius.zaleckas@teltonika.lt> wrote:
> > Rename mdio-ofgpio driver to mdio-gpio and make it work with
> > non OpenFirmware gpio implementation.
>
> Please respin this patch in 2 pieces; 1 patch to move the file and 1
> patch to make the changes. It is difficult to review as a single
> patch.
Or ask for the diffs to be in git format (iow, using git diff -M).
Don't know if git-send-email can do that.
^ permalink raw reply
* Re: [PATCH 1/2] phylib: rename mdio-ofgpio to mdio-gpio
From: Grant Likely @ 2008-10-31 16:52 UTC (permalink / raw)
To: Paulius Zaleckas
Cc: netdev, linux-arm-kernel, linux-embedded, Laurent Pinchart,
Mike Frysinger
In-Reply-To: <20081031164924.20490.44681.stgit@Programuotojas.82-135-208-232.ip.zebra.lt>
On Fri, Oct 31, 2008 at 10:49 AM, Paulius Zaleckas
<paulius.zaleckas@teltonika.lt> wrote:
> Signed-off-by: Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
> Cc: Laurent Pinchart <laurentp@cse-semaphore.com>
> Cc: Grant Likely <grant.likely@secretlab.ca>
> Cc: Mike Frysinger <vapier.adi@gmail.com>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
> ---
>
> drivers/net/phy/Kconfig | 2
> drivers/net/phy/Makefile | 2
> drivers/net/phy/mdio-gpio.c | 204 +++++++++++++++++++++++++++++++++++++++++
> drivers/net/phy/mdio-ofgpio.c | 204 -----------------------------------------
> 4 files changed, 206 insertions(+), 206 deletions(-)
> create mode 100644 drivers/net/phy/mdio-gpio.c
> delete mode 100644 drivers/net/phy/mdio-ofgpio.c
>
>
> diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
> index d55932a..0318077 100644
> --- a/drivers/net/phy/Kconfig
> +++ b/drivers/net/phy/Kconfig
> @@ -84,7 +84,7 @@ config MDIO_BITBANG
>
> If in doubt, say N.
>
> -config MDIO_OF_GPIO
> +config MDIO_GPIO
> tristate "Support for GPIO lib-based bitbanged MDIO buses"
> depends on MDIO_BITBANG && OF_GPIO
> ---help---
> diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
> index eee329f..9ae5d30 100644
> --- a/drivers/net/phy/Makefile
> +++ b/drivers/net/phy/Makefile
> @@ -15,4 +15,4 @@ obj-$(CONFIG_ICPLUS_PHY) += icplus.o
> obj-$(CONFIG_REALTEK_PHY) += realtek.o
> obj-$(CONFIG_FIXED_PHY) += fixed.o
> obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o
> -obj-$(CONFIG_MDIO_OF_GPIO) += mdio-ofgpio.o
> +obj-$(CONFIG_MDIO_GPIO) += mdio-gpio.o
> diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c
> new file mode 100644
> index 0000000..2ff9775
> --- /dev/null
> +++ b/drivers/net/phy/mdio-gpio.c
> @@ -0,0 +1,204 @@
> +/*
> + * OpenFirmware GPIO based MDIO bitbang driver.
> + *
> + * Copyright (c) 2008 CSE Semaphore Belgium.
> + * by Laurent Pinchart <laurentp@cse-semaphore.com>
> + *
> + * Based on earlier work by
> + *
> + * Copyright (c) 2003 Intracom S.A.
> + * by Pantelis Antoniou <panto@intracom.gr>
> + *
> + * 2005 (c) MontaVista Software, Inc.
> + * Vitaly Bordug <vbordug@ru.mvista.com>
> + *
> + * This file is licensed under the terms of the GNU General Public License
> + * version 2. This program is licensed "as is" without any warranty of any
> + * kind, whether express or implied.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/mdio-bitbang.h>
> +#include <linux/of_gpio.h>
> +#include <linux/of_platform.h>
> +
> +struct mdio_gpio_info {
> + struct mdiobb_ctrl ctrl;
> + int mdc, mdio;
> +};
> +
> +static void mdio_dir(struct mdiobb_ctrl *ctrl, int dir)
> +{
> + struct mdio_gpio_info *bitbang =
> + container_of(ctrl, struct mdio_gpio_info, ctrl);
> +
> + if (dir)
> + gpio_direction_output(bitbang->mdio, 1);
> + else
> + gpio_direction_input(bitbang->mdio);
> +}
> +
> +static int mdio_read(struct mdiobb_ctrl *ctrl)
> +{
> + struct mdio_gpio_info *bitbang =
> + container_of(ctrl, struct mdio_gpio_info, ctrl);
> +
> + return gpio_get_value(bitbang->mdio);
> +}
> +
> +static void mdio(struct mdiobb_ctrl *ctrl, int what)
> +{
> + struct mdio_gpio_info *bitbang =
> + container_of(ctrl, struct mdio_gpio_info, ctrl);
> +
> + gpio_set_value(bitbang->mdio, what);
> +}
> +
> +static void mdc(struct mdiobb_ctrl *ctrl, int what)
> +{
> + struct mdio_gpio_info *bitbang =
> + container_of(ctrl, struct mdio_gpio_info, ctrl);
> +
> + gpio_set_value(bitbang->mdc, what);
> +}
> +
> +static struct mdiobb_ops mdio_gpio_ops = {
> + .owner = THIS_MODULE,
> + .set_mdc = mdc,
> + .set_mdio_dir = mdio_dir,
> + .set_mdio_data = mdio,
> + .get_mdio_data = mdio_read,
> +};
> +
> +static int __devinit mdio_ofgpio_bitbang_init(struct mii_bus *bus,
> + struct device_node *np)
> +{
> + struct mdio_gpio_info *bitbang = bus->priv;
> +
> + bitbang->mdc = of_get_gpio(np, 0);
> + bitbang->mdio = of_get_gpio(np, 1);
> +
> + if (bitbang->mdc < 0 || bitbang->mdio < 0)
> + return -ENODEV;
> +
> + snprintf(bus->id, MII_BUS_ID_SIZE, "%x", bitbang->mdc);
> + return 0;
> +}
> +
> +static void __devinit add_phy(struct mii_bus *bus, struct device_node *np)
> +{
> + const u32 *data;
> + int len, id, irq;
> +
> + data = of_get_property(np, "reg", &len);
> + if (!data || len != 4)
> + return;
> +
> + id = *data;
> + bus->phy_mask &= ~(1 << id);
> +
> + irq = of_irq_to_resource(np, 0, NULL);
> + if (irq != NO_IRQ)
> + bus->irq[id] = irq;
> +}
> +
> +static int __devinit mdio_ofgpio_probe(struct of_device *ofdev,
> + const struct of_device_id *match)
> +{
> + struct device_node *np = NULL;
> + struct mii_bus *new_bus;
> + struct mdio_gpio_info *bitbang;
> + int ret = -ENOMEM;
> + int i;
> +
> + bitbang = kzalloc(sizeof(struct mdio_gpio_info), GFP_KERNEL);
> + if (!bitbang)
> + goto out;
> +
> + bitbang->ctrl.ops = &mdio_gpio_ops;
> +
> + new_bus = alloc_mdio_bitbang(&bitbang->ctrl);
> + if (!new_bus)
> + goto out_free_bitbang;
> +
> + new_bus->name = "GPIO Bitbanged MII",
> +
> + ret = mdio_ofgpio_bitbang_init(new_bus, ofdev->node);
> + if (ret)
> + goto out_free_bus;
> +
> + new_bus->phy_mask = ~0;
> + new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
> + if (!new_bus->irq)
> + goto out_free_bus;
> +
> + for (i = 0; i < PHY_MAX_ADDR; i++)
> + new_bus->irq[i] = -1;
> +
> + while ((np = of_get_next_child(ofdev->node, np)))
> + if (!strcmp(np->type, "ethernet-phy"))
> + add_phy(new_bus, np);
> +
> + new_bus->parent = &ofdev->dev;
> + dev_set_drvdata(&ofdev->dev, new_bus);
> +
> + ret = mdiobus_register(new_bus);
> + if (ret)
> + goto out_free_irqs;
> +
> + return 0;
> +
> +out_free_irqs:
> + dev_set_drvdata(&ofdev->dev, NULL);
> + kfree(new_bus->irq);
> +out_free_bus:
> + free_mdio_bitbang(new_bus);
> +out_free_bitbang:
> + kfree(bitbang);
> +out:
> + return ret;
> +}
> +
> +static int mdio_ofgpio_remove(struct of_device *ofdev)
> +{
> + struct mii_bus *bus = dev_get_drvdata(&ofdev->dev);
> + struct mdio_gpio_info *bitbang = bus->priv;
> +
> + mdiobus_unregister(bus);
> + kfree(bus->irq);
> + free_mdio_bitbang(bus);
> + dev_set_drvdata(&ofdev->dev, NULL);
> + kfree(bitbang);
> +
> + return 0;
> +}
> +
> +static struct of_device_id mdio_ofgpio_match[] = {
> + {
> + .compatible = "virtual,mdio-gpio",
> + },
> + {},
> +};
> +
> +static struct of_platform_driver mdio_ofgpio_driver = {
> + .name = "mdio-gpio",
> + .match_table = mdio_ofgpio_match,
> + .probe = mdio_ofgpio_probe,
> + .remove = mdio_ofgpio_remove,
> +};
> +
> +static int mdio_ofgpio_init(void)
> +{
> + return of_register_platform_driver(&mdio_ofgpio_driver);
> +}
> +
> +static void mdio_ofgpio_exit(void)
> +{
> + of_unregister_platform_driver(&mdio_ofgpio_driver);
> +}
> +
> +module_init(mdio_ofgpio_init);
> +module_exit(mdio_ofgpio_exit);
> diff --git a/drivers/net/phy/mdio-ofgpio.c b/drivers/net/phy/mdio-ofgpio.c
> deleted file mode 100644
> index 2ff9775..0000000
> --- a/drivers/net/phy/mdio-ofgpio.c
> +++ /dev/null
> @@ -1,204 +0,0 @@
> -/*
> - * OpenFirmware GPIO based MDIO bitbang driver.
> - *
> - * Copyright (c) 2008 CSE Semaphore Belgium.
> - * by Laurent Pinchart <laurentp@cse-semaphore.com>
> - *
> - * Based on earlier work by
> - *
> - * Copyright (c) 2003 Intracom S.A.
> - * by Pantelis Antoniou <panto@intracom.gr>
> - *
> - * 2005 (c) MontaVista Software, Inc.
> - * Vitaly Bordug <vbordug@ru.mvista.com>
> - *
> - * This file is licensed under the terms of the GNU General Public License
> - * version 2. This program is licensed "as is" without any warranty of any
> - * kind, whether express or implied.
> - */
> -
> -#include <linux/module.h>
> -#include <linux/slab.h>
> -#include <linux/init.h>
> -#include <linux/interrupt.h>
> -#include <linux/mdio-bitbang.h>
> -#include <linux/of_gpio.h>
> -#include <linux/of_platform.h>
> -
> -struct mdio_gpio_info {
> - struct mdiobb_ctrl ctrl;
> - int mdc, mdio;
> -};
> -
> -static void mdio_dir(struct mdiobb_ctrl *ctrl, int dir)
> -{
> - struct mdio_gpio_info *bitbang =
> - container_of(ctrl, struct mdio_gpio_info, ctrl);
> -
> - if (dir)
> - gpio_direction_output(bitbang->mdio, 1);
> - else
> - gpio_direction_input(bitbang->mdio);
> -}
> -
> -static int mdio_read(struct mdiobb_ctrl *ctrl)
> -{
> - struct mdio_gpio_info *bitbang =
> - container_of(ctrl, struct mdio_gpio_info, ctrl);
> -
> - return gpio_get_value(bitbang->mdio);
> -}
> -
> -static void mdio(struct mdiobb_ctrl *ctrl, int what)
> -{
> - struct mdio_gpio_info *bitbang =
> - container_of(ctrl, struct mdio_gpio_info, ctrl);
> -
> - gpio_set_value(bitbang->mdio, what);
> -}
> -
> -static void mdc(struct mdiobb_ctrl *ctrl, int what)
> -{
> - struct mdio_gpio_info *bitbang =
> - container_of(ctrl, struct mdio_gpio_info, ctrl);
> -
> - gpio_set_value(bitbang->mdc, what);
> -}
> -
> -static struct mdiobb_ops mdio_gpio_ops = {
> - .owner = THIS_MODULE,
> - .set_mdc = mdc,
> - .set_mdio_dir = mdio_dir,
> - .set_mdio_data = mdio,
> - .get_mdio_data = mdio_read,
> -};
> -
> -static int __devinit mdio_ofgpio_bitbang_init(struct mii_bus *bus,
> - struct device_node *np)
> -{
> - struct mdio_gpio_info *bitbang = bus->priv;
> -
> - bitbang->mdc = of_get_gpio(np, 0);
> - bitbang->mdio = of_get_gpio(np, 1);
> -
> - if (bitbang->mdc < 0 || bitbang->mdio < 0)
> - return -ENODEV;
> -
> - snprintf(bus->id, MII_BUS_ID_SIZE, "%x", bitbang->mdc);
> - return 0;
> -}
> -
> -static void __devinit add_phy(struct mii_bus *bus, struct device_node *np)
> -{
> - const u32 *data;
> - int len, id, irq;
> -
> - data = of_get_property(np, "reg", &len);
> - if (!data || len != 4)
> - return;
> -
> - id = *data;
> - bus->phy_mask &= ~(1 << id);
> -
> - irq = of_irq_to_resource(np, 0, NULL);
> - if (irq != NO_IRQ)
> - bus->irq[id] = irq;
> -}
> -
> -static int __devinit mdio_ofgpio_probe(struct of_device *ofdev,
> - const struct of_device_id *match)
> -{
> - struct device_node *np = NULL;
> - struct mii_bus *new_bus;
> - struct mdio_gpio_info *bitbang;
> - int ret = -ENOMEM;
> - int i;
> -
> - bitbang = kzalloc(sizeof(struct mdio_gpio_info), GFP_KERNEL);
> - if (!bitbang)
> - goto out;
> -
> - bitbang->ctrl.ops = &mdio_gpio_ops;
> -
> - new_bus = alloc_mdio_bitbang(&bitbang->ctrl);
> - if (!new_bus)
> - goto out_free_bitbang;
> -
> - new_bus->name = "GPIO Bitbanged MII",
> -
> - ret = mdio_ofgpio_bitbang_init(new_bus, ofdev->node);
> - if (ret)
> - goto out_free_bus;
> -
> - new_bus->phy_mask = ~0;
> - new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
> - if (!new_bus->irq)
> - goto out_free_bus;
> -
> - for (i = 0; i < PHY_MAX_ADDR; i++)
> - new_bus->irq[i] = -1;
> -
> - while ((np = of_get_next_child(ofdev->node, np)))
> - if (!strcmp(np->type, "ethernet-phy"))
> - add_phy(new_bus, np);
> -
> - new_bus->parent = &ofdev->dev;
> - dev_set_drvdata(&ofdev->dev, new_bus);
> -
> - ret = mdiobus_register(new_bus);
> - if (ret)
> - goto out_free_irqs;
> -
> - return 0;
> -
> -out_free_irqs:
> - dev_set_drvdata(&ofdev->dev, NULL);
> - kfree(new_bus->irq);
> -out_free_bus:
> - free_mdio_bitbang(new_bus);
> -out_free_bitbang:
> - kfree(bitbang);
> -out:
> - return ret;
> -}
> -
> -static int mdio_ofgpio_remove(struct of_device *ofdev)
> -{
> - struct mii_bus *bus = dev_get_drvdata(&ofdev->dev);
> - struct mdio_gpio_info *bitbang = bus->priv;
> -
> - mdiobus_unregister(bus);
> - kfree(bus->irq);
> - free_mdio_bitbang(bus);
> - dev_set_drvdata(&ofdev->dev, NULL);
> - kfree(bitbang);
> -
> - return 0;
> -}
> -
> -static struct of_device_id mdio_ofgpio_match[] = {
> - {
> - .compatible = "virtual,mdio-gpio",
> - },
> - {},
> -};
> -
> -static struct of_platform_driver mdio_ofgpio_driver = {
> - .name = "mdio-gpio",
> - .match_table = mdio_ofgpio_match,
> - .probe = mdio_ofgpio_probe,
> - .remove = mdio_ofgpio_remove,
> -};
> -
> -static int mdio_ofgpio_init(void)
> -{
> - return of_register_platform_driver(&mdio_ofgpio_driver);
> -}
> -
> -static void mdio_ofgpio_exit(void)
> -{
> - of_unregister_platform_driver(&mdio_ofgpio_driver);
> -}
> -
> -module_init(mdio_ofgpio_init);
> -module_exit(mdio_ofgpio_exit);
>
>
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* Re: [PATCH 2/2] phylib: make mdio-gpio work without OF
From: Grant Likely @ 2008-10-31 17:18 UTC (permalink / raw)
To: Paulius Zaleckas
Cc: netdev, linux-arm-kernel, linux-embedded, Laurent Pinchart,
Mike Frysinger
In-Reply-To: <20081031164934.20490.67539.stgit@Programuotojas.82-135-208-232.ip.zebra.lt>
On Fri, Oct 31, 2008 at 10:49 AM, Paulius Zaleckas
<paulius.zaleckas@teltonika.lt> wrote:
> make mdio-gpio work with non OpenFirmware gpio implementation.
>
Looking good, but it has too many #ifdef blocks for my taste. In
particular, if the driver is refactored a bit then all the OF stuff
can be contained within a single ifdef block, as can all the non-OF
stuff. Comments below...
> +#ifdef CONFIG_OF_GPIO
> static int __devinit mdio_ofgpio_bitbang_init(struct mii_bus *bus,
> struct device_node *np)
> {
> @@ -87,34 +102,60 @@ static int __devinit mdio_ofgpio_bitbang_init(struct mii_bus *bus,
> snprintf(bus->id, MII_BUS_ID_SIZE, "%x", bitbang->mdc);
> return 0;
> }
> -
> -static void __devinit add_phy(struct mii_bus *bus, struct device_node *np)
> +#else
> +static void __devinit mdio_gpio_bitbang_init(struct mii_bus *bus,
> + struct mdio_gpio_platform_data *pdata,
> + int bus_id)
> {
> - const u32 *data;
> - int len, id, irq;
> + struct mdio_gpio_info *bitbang = bus->priv;
> +
> + bitbang->mdc = pdata->mdc;
> + bitbang->mdio = pdata->mdio;
> +
> + snprintf(bus->id, MII_BUS_ID_SIZE, "phy%i", bus_id);
> +}
> +#endif
mdio_ofgpio_bitbang_init() is such short function and it is only
called once inside the probe() function. Rather than duplicate it, it
can probably be moved inside the OF probe function and do the same
thing for the non-OF probe().
>
> - data = of_get_property(np, "reg", &len);
> - if (!data || len != 4)
> +static void __devinit add_phy(struct mii_bus *bus, unsigned int phy_addr,
> + int phy_irq)
> +{
> + if (phy_addr >= PHY_MAX_ADDR) {
> + dev_err(bus->parent,
> + "Failed to add phy with invalid address: 0x%x",
> + phy_addr);
> return;
> + }
>
> - id = *data;
> - bus->phy_mask &= ~(1 << id);
> + bus->phy_mask &= ~(1 << phy_addr);
>
> - irq = of_irq_to_resource(np, 0, NULL);
> - if (irq != NO_IRQ)
> - bus->irq[id] = irq;
> + if (phy_irq != NO_IRQ)
> + bus->irq[phy_addr] = phy_irq;
> }
I like the refactoring of add_phy
>
> +#ifdef CONFIG_OF_GPIO
> static int __devinit mdio_ofgpio_probe(struct of_device *ofdev,
> const struct of_device_id *match)
> {
> struct device_node *np = NULL;
> + struct device *dev = &ofdev->dev;
> +#else
> +static int __devinit mdio_gpio_probe(struct platform_device *pdev)
> +{
> + struct mdio_gpio_platform_data *pdata;
> + struct device *dev = &pdev->dev;
> +#endif
Instead of doing multiple #ifdef sections throughout the probe
function, use one #ifdef block for the OF stuff and another for all
the non-OF stuff. You can factor out any non-trivial common code
blocks into shared helper functions.
Otherwise, looking good.
Thanks,
g.
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* Re: [PATCH] phylib: mdio-ofgpio ---> mdio-gpio
From: David Brownell @ 2008-10-31 17:26 UTC (permalink / raw)
To: Paulius Zaleckas
Cc: netdev, linux-arm-kernel, linux-embedded, Laurent Pinchart,
Grant Likely, Mike Frysinger
In-Reply-To: <20081031155335.19905.14186.stgit@Programuotojas.82-135-208-232.ip.zebra.lt>
On Friday 31 October 2008, Paulius Zaleckas wrote:
> - if NO_IRQ is not defined define it to 0
Better yet, stop using that symbol entirely...
^ permalink raw reply
* Re: [PATCH 2/2] phylib: make mdio-gpio work without OF
From: Mike Frysinger @ 2008-10-31 22:07 UTC (permalink / raw)
To: Paulius Zaleckas
Cc: netdev, linux-arm-kernel, linux-embedded, Laurent Pinchart,
Grant Likely
In-Reply-To: <20081031164934.20490.67539.stgit@Programuotojas.82-135-208-232.ip.zebra.lt>
On Fri, Oct 31, 2008 at 12:49, Paulius Zaleckas wrote:
> +#ifndef NO_IRQ
> +#define NO_IRQ 0
> +#endif
discussions elsewhere indicate this should die.
-if (irq != NO_IRQ)
+if (irq)
-mike
^ permalink raw reply
* Re: [PATCH V2 10/16] Squashfs: cache operations
From: Evgeniy Polyakov @ 2008-11-03 14:11 UTC (permalink / raw)
To: Phillip Lougher
Cc: akpm, linux-embedded, linux-fsdevel, linux-kernel, tim.bird
In-Reply-To: <E1Kv0C4-0006HO-BC@dylan>
Hi.
Couple comments below.
On Wed, Oct 29, 2008 at 01:49:56AM +0000, Phillip Lougher (phillip@lougher.demon.co.uk) wrote:
> +struct squashfs_cache_entry *squashfs_cache_get(struct super_block *sb,
> + struct squashfs_cache *cache, long long block, int length)
> +{
> + int i, n;
> + struct squashfs_cache_entry *entry;
> +
> + spin_lock(&cache->lock);
> +
> + while (1) {
> + for (i = 0; i < cache->entries; i++)
> + if (cache->entry[i].block == block)
> + break;
> +
> + if (i == cache->entries) {
> + /*
> + * Block not in cache, if all cache entries are locked
> + * go to sleep waiting for one to become available.
> + */
> + if (cache->unused == 0) {
> + cache->waiting++;
> + spin_unlock(&cache->lock);
> + wait_event(cache->wait_queue, cache->unused);
> + spin_lock(&cache->lock);
> + cache->waiting--;
> + continue;
> + }
> +
> + /*
> + * At least one unlocked cache entry. A simple
> + * round-robin strategy is used to choose the entry to
> + * be evicted from the cache.
> + */
> + i = cache->next_blk;
> + for (n = 0; n < cache->entries; n++) {
> + if (cache->entry[i].locked == 0)
> + break;
> + i = (i + 1) % cache->entries;
> + }
> +
> + cache->next_blk = (i + 1) % cache->entries;
> + entry = &cache->entry[i];
This is invoked for every read when cache is filled, if I understood
correctly, and having a modulo in this path is an additional overhead.
This may be hidden on behalf of compression overhead, but stil.
Also what happens when there are no unlocked entries? I.e. you will try
to work with existing one, while it is already locked and processed by
another thread?
--
Evgeniy Polyakov
^ permalink raw reply
* Re: [PATCH V2 11/16] Squashfs: block operations
From: Evgeniy Polyakov @ 2008-11-03 14:11 UTC (permalink / raw)
To: Phillip Lougher
Cc: akpm, linux-embedded, linux-fsdevel, linux-kernel, tim.bird
In-Reply-To: <E1Kv0C4-0006HV-DN@dylan>
Hi.
On Wed, Oct 29, 2008 at 01:49:56AM +0000, Phillip Lougher (phillip@lougher.demon.co.uk) wrote:
> +int squashfs_read_data(struct super_block *sb, void *buffer,
> + long long index, int length, long long *next_index,
> + int srclength)
> +{
> + struct squashfs_sb_info *msblk = sb->s_fs_info;
> + struct buffer_head **bh;
> + int offset = index & ((1 << msblk->devblksize_log2) - 1);
> + long long cur_index = index >> msblk->devblksize_log2;
> + int avail, bytes, compressed, b = 0, k = 0;
> + int c_byte = length;
> +
> + bh = kcalloc((msblk->block_size >> msblk->devblksize_log2) + 1,
> + sizeof(*bh), GFP_KERNEL);
Could be great to have a memory pool though...
--
Evgeniy Polyakov
^ permalink raw reply
* Re: [PATCH V2 00/16] Squashfs: compressed read-only filesystem
From: Evgeniy Polyakov @ 2008-11-03 14:14 UTC (permalink / raw)
To: Phillip Lougher
Cc: akpm, linux-embedded, linux-fsdevel, linux-kernel, tim.bird
In-Reply-To: <E1Kv0C3-0006GU-ES@dylan>
Hi.
On Wed, Oct 29, 2008 at 01:49:55AM +0000, Phillip Lougher (phillip@lougher.demon.co.uk) wrote:
> Summary of changes in patch respin:
>
> 1. Functions changed to return 0 on success and -ESOMETHING on error
> 2. Header files moved from include/linux to fs/squashfs
> 3. Variables changed to use sb and inode
> 4. Number of squashfs_read_metadata() parameters reduced
> 5. Xattr placeholder code tweaked
> 6. TRACE and ERROR macros fixed to use pr_debug and pr_warning
> 7. Some obsolete macros in squashfs_fs.h removed
> 8. A number of gotos to return statements replaced with direct returns
> 9. Sparse with endian checking (make C=2 CHECKFLAGS="-D__CHECK_ENDIAN__")
> errors fixed
> 10. get_dir_index_using_name() misaligned access fixed
> 11. Fix a couple of printk warnings on PPC64
> 12. Shorten a number of variable names
Looks very good.
As a generic comment of the style: imho u64 is more appropriate than
long long, at least it is less keys to press when typing :)
--
Evgeniy Polyakov
^ permalink raw reply
* [PATCH] phylib: make mdio-gpio work without OF (v2)
From: Paulius Zaleckas @ 2008-11-04 14:45 UTC (permalink / raw)
To: netdev
Cc: linux-arm-kernel, linux-embedded, Paulius Zaleckas,
Laurent Pinchart, Grant Likely, Mike Frysinger
make mdio-gpio work with non OpenFirmware gpio implementation.
Aditional changes to mdio-gpio:
- use gpio_request() and gpio_free()
- place irq[] array in struct mdio_gpio_info
- add module description, author and license
- add note about compiling this driver as module
- rename mdc and mdio function (were ugly names)
- change MII to MDIO in bus name
- add __init __exit to module (un)loading functions
- probe fails if no phys added to the bus
- kzalloc bitbang with sizeof(*bitbang)
Changes since v1:
- removed NO_IRQ
- reduced #idefs
Laurent, please test this driver under OF.
Signed-off-by: Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
Cc: Laurent Pinchart <laurentp@cse-semaphore.com>
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: Mike Frysinger <vapier.adi@gmail.com>
---
drivers/net/phy/Kconfig | 5 +
drivers/net/phy/mdio-gpio.c | 194 ++++++++++++++++++++++++++++++-------------
include/linux/mdio-gpio.h | 30 +++++++
3 files changed, 169 insertions(+), 60 deletions(-)
create mode 100644 include/linux/mdio-gpio.h
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 0318077..c4c5a2f 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -86,8 +86,11 @@ config MDIO_BITBANG
config MDIO_GPIO
tristate "Support for GPIO lib-based bitbanged MDIO buses"
- depends on MDIO_BITBANG && OF_GPIO
+ depends on MDIO_BITBANG && GENERIC_GPIO
---help---
Supports GPIO lib-based MDIO busses.
+ To compile this driver as a module, choose M here: the module
+ will be called mdio-gpio.
+
endif # PHYLIB
diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c
index 2ff9775..bcc2cb7 100644
--- a/drivers/net/phy/mdio-gpio.c
+++ b/drivers/net/phy/mdio-gpio.c
@@ -1,9 +1,12 @@
/*
- * OpenFirmware GPIO based MDIO bitbang driver.
+ * GPIO based MDIO bitbang driver.
+ * Supports OpenFirmware.
*
* Copyright (c) 2008 CSE Semaphore Belgium.
* by Laurent Pinchart <laurentp@cse-semaphore.com>
*
+ * Copyright (C) 2008, Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ *
* Based on earlier work by
*
* Copyright (c) 2003 Intracom S.A.
@@ -22,12 +25,19 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/mdio-bitbang.h>
-#include <linux/of_gpio.h>
-#include <linux/of_platform.h>
+#ifdef CONFIG_OF_GPIO
+# include <linux/of_gpio.h>
+# include <linux/of_platform.h>
+#else
+# include <linux/platform_device.h>
+# include <linux/gpio.h>
+# include <linux/mdio-gpio.h>
+#endif
struct mdio_gpio_info {
struct mdiobb_ctrl ctrl;
int mdc, mdio;
+ int irq[PHY_MAX_ADDR];
};
static void mdio_dir(struct mdiobb_ctrl *ctrl, int dir)
@@ -41,7 +51,7 @@ static void mdio_dir(struct mdiobb_ctrl *ctrl, int dir)
gpio_direction_input(bitbang->mdio);
}
-static int mdio_read(struct mdiobb_ctrl *ctrl)
+static int mdio_get(struct mdiobb_ctrl *ctrl)
{
struct mdio_gpio_info *bitbang =
container_of(ctrl, struct mdio_gpio_info, ctrl);
@@ -49,7 +59,7 @@ static int mdio_read(struct mdiobb_ctrl *ctrl)
return gpio_get_value(bitbang->mdio);
}
-static void mdio(struct mdiobb_ctrl *ctrl, int what)
+static void mdio_set(struct mdiobb_ctrl *ctrl, int what)
{
struct mdio_gpio_info *bitbang =
container_of(ctrl, struct mdio_gpio_info, ctrl);
@@ -57,7 +67,7 @@ static void mdio(struct mdiobb_ctrl *ctrl, int what)
gpio_set_value(bitbang->mdio, what);
}
-static void mdc(struct mdiobb_ctrl *ctrl, int what)
+static void mdc_set(struct mdiobb_ctrl *ctrl, int what)
{
struct mdio_gpio_info *bitbang =
container_of(ctrl, struct mdio_gpio_info, ctrl);
@@ -67,54 +77,46 @@ static void mdc(struct mdiobb_ctrl *ctrl, int what)
static struct mdiobb_ops mdio_gpio_ops = {
.owner = THIS_MODULE,
- .set_mdc = mdc,
+ .set_mdc = mdc_set,
.set_mdio_dir = mdio_dir,
- .set_mdio_data = mdio,
- .get_mdio_data = mdio_read,
+ .set_mdio_data = mdio_set,
+ .get_mdio_data = mdio_get,
};
-static int __devinit mdio_ofgpio_bitbang_init(struct mii_bus *bus,
- struct device_node *np)
+static void __devinit add_phy(struct mii_bus *bus, unsigned int phy_addr,
+ int phy_irq)
{
- struct mdio_gpio_info *bitbang = bus->priv;
-
- bitbang->mdc = of_get_gpio(np, 0);
- bitbang->mdio = of_get_gpio(np, 1);
-
- if (bitbang->mdc < 0 || bitbang->mdio < 0)
- return -ENODEV;
-
- snprintf(bus->id, MII_BUS_ID_SIZE, "%x", bitbang->mdc);
- return 0;
-}
-
-static void __devinit add_phy(struct mii_bus *bus, struct device_node *np)
-{
- const u32 *data;
- int len, id, irq;
-
- data = of_get_property(np, "reg", &len);
- if (!data || len != 4)
+ if (phy_addr >= PHY_MAX_ADDR) {
+ dev_err(bus->parent,
+ "Failed to add phy with invalid address: 0x%x",
+ phy_addr);
return;
+ }
- id = *data;
- bus->phy_mask &= ~(1 << id);
+ bus->phy_mask &= ~(1 << phy_addr);
- irq = of_irq_to_resource(np, 0, NULL);
- if (irq != NO_IRQ)
- bus->irq[id] = irq;
+ if (phy_irq)
+ bus->irq[phy_addr] = phy_irq;
}
+#ifdef CONFIG_OF_GPIO
static int __devinit mdio_ofgpio_probe(struct of_device *ofdev,
const struct of_device_id *match)
{
struct device_node *np = NULL;
+ struct device *dev = &ofdev->dev;
+#else
+static int __devinit mdio_gpio_probe(struct platform_device *pdev)
+{
+ struct mdio_gpio_platform_data *pdata;
+ struct device *dev = &pdev->dev;
+#endif
struct mii_bus *new_bus;
struct mdio_gpio_info *bitbang;
int ret = -ENOMEM;
int i;
- bitbang = kzalloc(sizeof(struct mdio_gpio_info), GFP_KERNEL);
+ bitbang = kzalloc(sizeof(*bitbang), GFP_KERNEL);
if (!bitbang)
goto out;
@@ -124,36 +126,74 @@ static int __devinit mdio_ofgpio_probe(struct of_device *ofdev,
if (!new_bus)
goto out_free_bitbang;
- new_bus->name = "GPIO Bitbanged MII",
+ new_bus->name = "GPIO Bitbanged MDIO",
- ret = mdio_ofgpio_bitbang_init(new_bus, ofdev->node);
- if (ret)
- goto out_free_bus;
+ ret = -ENODEV;
new_bus->phy_mask = ~0;
- new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
- if (!new_bus->irq)
- goto out_free_bus;
+ new_bus->irq = bitbang->irq;
+ new_bus->parent = dev;
for (i = 0; i < PHY_MAX_ADDR; i++)
- new_bus->irq[i] = -1;
+ new_bus->irq[i] = PHY_POLL;
+
+#ifdef CONFIG_OF_GPIO
+ bitbang->mdc = of_get_gpio(ofdev->node, 0);
+ bitbang->mdio = of_get_gpio(ofdev->node, 1);
+
+ if (bitbang->mdc < 0 || bitbang->mdio < 0)
+ goto out_free_bus;
+
+ snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", bitbang->mdc);
while ((np = of_get_next_child(ofdev->node, np)))
- if (!strcmp(np->type, "ethernet-phy"))
- add_phy(new_bus, np);
+ if (!strcmp(np->type, "ethernet-phy")) {
+ const u32 *data;
+ int len;
+
+ data = of_get_property(np, "reg", &len);
+ if (!data || len != 4)
+ continue;
+
+ add_phy(new_bus, *data,
+ of_irq_to_resource(np, 0, NULL));
+ }
+#else
+ pdata = dev->platform_data;
+ if (pdata == NULL)
+ goto out_free_bus;
+
+ bitbang->mdc = pdata->mdc;
+ bitbang->mdio = pdata->mdio;
- new_bus->parent = &ofdev->dev;
- dev_set_drvdata(&ofdev->dev, new_bus);
+ snprintf(new_bus->id, MII_BUS_ID_SIZE, "phy%i", pdev->id);
+
+ for (i = 0; i < pdata->nr_phys; i++)
+ add_phy(new_bus, pdata->phys[i].addr, pdata->phys[i].irq);
+#endif
+
+ if (new_bus->phy_mask == ~0)
+ goto out_free_bus;
+
+ if (gpio_request(bitbang->mdc, "mdc"))
+ goto out_free_bus;
+
+ if (gpio_request(bitbang->mdio, "mdio"))
+ goto out_free_mdc;
+
+ dev_set_drvdata(dev, new_bus);
ret = mdiobus_register(new_bus);
if (ret)
- goto out_free_irqs;
+ goto out_free_all;
return 0;
-out_free_irqs:
- dev_set_drvdata(&ofdev->dev, NULL);
- kfree(new_bus->irq);
+out_free_all:
+ dev_set_drvdata(dev, NULL);
+ gpio_free(bitbang->mdio);
+out_free_mdc:
+ gpio_free(bitbang->mdc);
out_free_bus:
free_mdio_bitbang(new_bus);
out_free_bitbang:
@@ -162,20 +202,29 @@ out:
return ret;
}
+#ifdef CONFIG_OF_GPIO
static int mdio_ofgpio_remove(struct of_device *ofdev)
{
- struct mii_bus *bus = dev_get_drvdata(&ofdev->dev);
+ struct device *dev = &ofdev->dev;
+#else
+static int __devexit mdio_gpio_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+#endif
+ struct mii_bus *bus = dev_get_drvdata(dev);
struct mdio_gpio_info *bitbang = bus->priv;
mdiobus_unregister(bus);
- kfree(bus->irq);
free_mdio_bitbang(bus);
- dev_set_drvdata(&ofdev->dev, NULL);
+ dev_set_drvdata(dev, NULL);
+ gpio_free(bitbang->mdc);
+ gpio_free(bitbang->mdio);
kfree(bitbang);
return 0;
}
+#ifdef CONFIG_OF_GPIO
static struct of_device_id mdio_ofgpio_match[] = {
{
.compatible = "virtual,mdio-gpio",
@@ -190,15 +239,42 @@ static struct of_platform_driver mdio_ofgpio_driver = {
.remove = mdio_ofgpio_remove,
};
-static int mdio_ofgpio_init(void)
+static int __init mdio_ofgpio_init(void)
{
return of_register_platform_driver(&mdio_ofgpio_driver);
}
+module_init(mdio_ofgpio_init);
-static void mdio_ofgpio_exit(void)
+static void __exit mdio_ofgpio_exit(void)
{
of_unregister_platform_driver(&mdio_ofgpio_driver);
}
-
-module_init(mdio_ofgpio_init);
module_exit(mdio_ofgpio_exit);
+#else
+static struct platform_driver mdio_gpio_driver = {
+ .probe = mdio_gpio_probe,
+ .remove = __devexit_p(mdio_gpio_remove),
+ .driver = {
+ .name = "mdio-gpio",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init mdio_gpio_init(void)
+{
+ return platform_driver_register(&mdio_gpio_driver);
+}
+module_init(mdio_gpio_init);
+
+static void __exit mdio_gpio_exit(void)
+{
+ platform_driver_unregister(&mdio_gpio_driver);
+}
+module_exit(mdio_gpio_exit);
+
+MODULE_ALIAS("platform:mdio-gpio");
+#endif /* CONFIG_OF_GPIO */
+
+MODULE_AUTHOR("Laurent Pinchart, Paulius Zaleckas");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Generic driver for MDIO bus emulation using GPIO");
diff --git a/include/linux/mdio-gpio.h b/include/linux/mdio-gpio.h
new file mode 100644
index 0000000..6a8258d
--- /dev/null
+++ b/include/linux/mdio-gpio.h
@@ -0,0 +1,30 @@
+/*
+ * MDIO-GPIO bus platform data structures
+ *
+ * Copyright (C) 2008, Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef __LINUX_MDIO_GPIO_H
+#define __LINUX_MDIO_GPIO_H
+
+struct mdio_gpio_phy {
+ /* PHY address on MDIO bus */
+ unsigned int addr;
+ /* preconfigured irq connected to PHY */
+ int irq;
+};
+
+struct mdio_gpio_platform_data {
+ /* GPIO numbers for bus pins */
+ unsigned int mdc;
+ unsigned int mdio;
+
+ unsigned int nr_phys;
+ struct mdio_gpio_phy *phys;
+};
+
+#endif /* __LINUX_MDIO_GPIO_H */
^ permalink raw reply related
* Re: [PATCH] phylib: make mdio-gpio work without OF (v2)
From: Marc Pignat @ 2008-11-04 15:45 UTC (permalink / raw)
To: Paulius Zaleckas
Cc: netdev, linux-arm-kernel, linux-embedded, Laurent Pinchart,
Grant Likely, Mike Frysinger
In-Reply-To: <20081104144518.4429.37325.stgit@Programuotojas.82-135-208-232.ip.zebra.lt>
Hiü
On Tuesday 04 November 2008, Paulius Zaleckas wrote:
> make mdio-gpio work with non OpenFirmware gpio implementation.
of_gpio.c provides generic gpio compatible gpios.
Why not remove all OF specific code from this file and add another one
creating the struct mdio_gpio_platform_data using OF specific functions?
Best regards
Marc
^ permalink raw reply
* Re: [PATCH] phylib: make mdio-gpio work without OF (v2)
From: Grant Likely @ 2008-11-04 15:57 UTC (permalink / raw)
To: Marc Pignat
Cc: Paulius Zaleckas, netdev, linux-arm-kernel, linux-embedded,
Laurent Pinchart, Mike Frysinger
In-Reply-To: <200811041645.39953.marc.pignat@hevs.ch>
On Tue, Nov 4, 2008 at 8:45 AM, Marc Pignat <marc.pignat@hevs.ch> wrote:
> Hiü
>
> On Tuesday 04 November 2008, Paulius Zaleckas wrote:
>> make mdio-gpio work with non OpenFirmware gpio implementation.
>
> of_gpio.c provides generic gpio compatible gpios.
>
> Why not remove all OF specific code from this file and add another one
> creating the struct mdio_gpio_platform_data using OF specific functions?
This is a very simple driver. There is no need to split it into two
files. Have two sections of bus binding (OF and non-OF) is just fine.
g.
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* Re: [PATCH] phylib: make mdio-gpio work without OF (v2)
From: Grant Likely @ 2008-11-04 16:24 UTC (permalink / raw)
To: Paulius Zaleckas
Cc: netdev, linux-arm-kernel, linux-embedded, Laurent Pinchart,
Mike Frysinger
In-Reply-To: <20081104144518.4429.37325.stgit@Programuotojas.82-135-208-232.ip.zebra.lt>
On Tue, Nov 4, 2008 at 7:45 AM, Paulius Zaleckas
<paulius.zaleckas@teltonika.lt> wrote:
> make mdio-gpio work with non OpenFirmware gpio implementation.
>
> Aditional changes to mdio-gpio:
> - use gpio_request() and gpio_free()
> - place irq[] array in struct mdio_gpio_info
> - add module description, author and license
> - add note about compiling this driver as module
> - rename mdc and mdio function (were ugly names)
> - change MII to MDIO in bus name
> - add __init __exit to module (un)loading functions
> - probe fails if no phys added to the bus
> - kzalloc bitbang with sizeof(*bitbang)
>
> Changes since v1:
> - removed NO_IRQ
> - reduced #idefs
I like this better, but I have a few more comments below. I'd like to
see the #ifdefs reduced even more.
> +#ifdef CONFIG_OF_GPIO
> static int __devinit mdio_ofgpio_probe(struct of_device *ofdev,
> const struct of_device_id *match)
> {
> struct device_node *np = NULL;
> + struct device *dev = &ofdev->dev;
> +#else
> +static int __devinit mdio_gpio_probe(struct platform_device *pdev)
> +{
> + struct mdio_gpio_platform_data *pdata;
> + struct device *dev = &pdev->dev;
> +#endif
At this point, instead of #ifdeffing the function signature, I would
much rather see this generalized as something like
'mdio_gpio_setup()'. Then move the OF and non-OF specific bits into
two new functions; mdio_ofgpio_probe() and mdio_gpio_probe(). The two
new functions should be placed with the appropriate bus binding in the
#ifdef/#else block at the bottom of the file.
Separating it in this way will keep the two separate binding code
paths easier to read and understand.
> +#ifdef CONFIG_OF_GPIO
> + bitbang->mdc = of_get_gpio(ofdev->node, 0);
> + bitbang->mdio = of_get_gpio(ofdev->node, 1);
> +
> + if (bitbang->mdc < 0 || bitbang->mdio < 0)
> + goto out_free_bus;
> +
> + snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", bitbang->mdc);
>
> while ((np = of_get_next_child(ofdev->node, np)))
> - if (!strcmp(np->type, "ethernet-phy"))
> - add_phy(new_bus, np);
> + if (!strcmp(np->type, "ethernet-phy")) {
> + const u32 *data;
> + int len;
> +
> + data = of_get_property(np, "reg", &len);
> + if (!data || len != 4)
> + continue;
> +
> + add_phy(new_bus, *data,
> + of_irq_to_resource(np, 0, NULL));
> + }
> +#else
> + pdata = dev->platform_data;
> + if (pdata == NULL)
> + goto out_free_bus;
> +
> + bitbang->mdc = pdata->mdc;
> + bitbang->mdio = pdata->mdio;
>
> - new_bus->parent = &ofdev->dev;
> - dev_set_drvdata(&ofdev->dev, new_bus);
> + snprintf(new_bus->id, MII_BUS_ID_SIZE, "phy%i", pdev->id);
> +
> + for (i = 0; i < pdata->nr_phys; i++)
> + add_phy(new_bus, pdata->phys[i].addr, pdata->phys[i].irq);
> +#endif
These are the bits to factor out into binding specific probe()
functions. I want to see the data interpretation code (probe)
separated from the driver setup code.
Otherwise, this looks good to me.
g.
> +
> + if (new_bus->phy_mask == ~0)
> + goto out_free_bus;
> +
> + if (gpio_request(bitbang->mdc, "mdc"))
> + goto out_free_bus;
> +
> + if (gpio_request(bitbang->mdio, "mdio"))
> + goto out_free_mdc;
> +
> + dev_set_drvdata(dev, new_bus);
>
> ret = mdiobus_register(new_bus);
> if (ret)
> - goto out_free_irqs;
> + goto out_free_all;
>
> return 0;
>
> -out_free_irqs:
> - dev_set_drvdata(&ofdev->dev, NULL);
> - kfree(new_bus->irq);
> +out_free_all:
> + dev_set_drvdata(dev, NULL);
> + gpio_free(bitbang->mdio);
> +out_free_mdc:
> + gpio_free(bitbang->mdc);
> out_free_bus:
> free_mdio_bitbang(new_bus);
> out_free_bitbang:
> @@ -162,20 +202,29 @@ out:
> return ret;
> }
>
> +#ifdef CONFIG_OF_GPIO
> static int mdio_ofgpio_remove(struct of_device *ofdev)
> {
> - struct mii_bus *bus = dev_get_drvdata(&ofdev->dev);
> + struct device *dev = &ofdev->dev;
> +#else
> +static int __devexit mdio_gpio_remove(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> +#endif
Ditto here my comments on the probe functions; create binding specific
*_remove() functions and refactor this into a common
mdio_gpio_teardown() function.
> + struct mii_bus *bus = dev_get_drvdata(dev);
> struct mdio_gpio_info *bitbang = bus->priv;
>
> mdiobus_unregister(bus);
> - kfree(bus->irq);
> free_mdio_bitbang(bus);
> - dev_set_drvdata(&ofdev->dev, NULL);
> + dev_set_drvdata(dev, NULL);
> + gpio_free(bitbang->mdc);
> + gpio_free(bitbang->mdio);
> kfree(bitbang);
>
> return 0;
> }
>
> +#ifdef CONFIG_OF_GPIO
> static struct of_device_id mdio_ofgpio_match[] = {
> {
> .compatible = "virtual,mdio-gpio",
> @@ -190,15 +239,42 @@ static struct of_platform_driver mdio_ofgpio_driver = {
> .remove = mdio_ofgpio_remove,
> };
>
> -static int mdio_ofgpio_init(void)
> +static int __init mdio_ofgpio_init(void)
> {
> return of_register_platform_driver(&mdio_ofgpio_driver);
> }
> +module_init(mdio_ofgpio_init);
>
> -static void mdio_ofgpio_exit(void)
> +static void __exit mdio_ofgpio_exit(void)
> {
> of_unregister_platform_driver(&mdio_ofgpio_driver);
> }
> -
> -module_init(mdio_ofgpio_init);
> module_exit(mdio_ofgpio_exit);
> +#else
> +static struct platform_driver mdio_gpio_driver = {
> + .probe = mdio_gpio_probe,
> + .remove = __devexit_p(mdio_gpio_remove),
> + .driver = {
> + .name = "mdio-gpio",
> + .owner = THIS_MODULE,
> + },
> +};
> +
> +static int __init mdio_gpio_init(void)
> +{
> + return platform_driver_register(&mdio_gpio_driver);
> +}
> +module_init(mdio_gpio_init);
> +
> +static void __exit mdio_gpio_exit(void)
> +{
> + platform_driver_unregister(&mdio_gpio_driver);
> +}
> +module_exit(mdio_gpio_exit);
> +
> +MODULE_ALIAS("platform:mdio-gpio");
> +#endif /* CONFIG_OF_GPIO */
> +
> +MODULE_AUTHOR("Laurent Pinchart, Paulius Zaleckas");
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Generic driver for MDIO bus emulation using GPIO");
> diff --git a/include/linux/mdio-gpio.h b/include/linux/mdio-gpio.h
> new file mode 100644
> index 0000000..6a8258d
> --- /dev/null
> +++ b/include/linux/mdio-gpio.h
> @@ -0,0 +1,30 @@
> +/*
> + * MDIO-GPIO bus platform data structures
> + *
> + * Copyright (C) 2008, Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
> + *
> + * This file is licensed under the terms of the GNU General Public License
> + * version 2. This program is licensed "as is" without any warranty of any
> + * kind, whether express or implied.
> + */
> +
> +#ifndef __LINUX_MDIO_GPIO_H
> +#define __LINUX_MDIO_GPIO_H
> +
> +struct mdio_gpio_phy {
> + /* PHY address on MDIO bus */
> + unsigned int addr;
> + /* preconfigured irq connected to PHY */
> + int irq;
> +};
> +
> +struct mdio_gpio_platform_data {
> + /* GPIO numbers for bus pins */
> + unsigned int mdc;
> + unsigned int mdio;
> +
> + unsigned int nr_phys;
> + struct mdio_gpio_phy *phys;
> +};
> +
> +#endif /* __LINUX_MDIO_GPIO_H */
>
>
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* Re: [PATCH 1/6] [PWM] Generic PWM API implementation
From: Bill Gatliff @ 2008-11-04 20:16 UTC (permalink / raw)
To: linux-embedded
In-Reply-To: <8bd0f97a0810170859k72dc1bc5o34ed2388f95c3bc8@mail.gmail.com>
Mike Frysinger wrote:
> On Wed, Oct 15, 2008 at 14:14, Bill Gatliff wrote:
>> +int pwm_register(struct pwm_device *pwm)
>> +{
>> + struct pwm_channel *p;
>> + int wchan;
>> + int ret = 0;
>
> the initialization to 0 here isnt needed
This is literally the only feedback I have received. I take that to mean that
the code basically works as advertised, and nobody else has any problems with it
(it continues to work fine for me here).
So, what's the next step? How do I advocate for getting this API into mainline?
b.g.
--
Bill Gatliff
bgat@billgatliff.com
^ permalink raw reply
* Re: [PATCH 1/6] [PWM] Generic PWM API implementation
From: Mike Frysinger @ 2008-11-04 20:51 UTC (permalink / raw)
To: Bill Gatliff; +Cc: linux-embedded
In-Reply-To: <4910AD88.2000200@billgatliff.com>
On Tue, Nov 4, 2008 at 15:16, Bill Gatliff wrote:
> Mike Frysinger wrote:
>> On Wed, Oct 15, 2008 at 14:14, Bill Gatliff wrote:
>>> +int pwm_register(struct pwm_device *pwm)
>>> +{
>>> + struct pwm_channel *p;
>>> + int wchan;
>>> + int ret = 0;
>>
>> the initialization to 0 here isnt needed
>
> This is literally the only feedback I have received. I take that to mean that
> the code basically works as advertised, and nobody else has any problems with it
> (it continues to work fine for me here).
>
> So, what's the next step? How do I advocate for getting this API into mainline?
you looking to be maintainer ? if so, i imagine you start a git tree
(on kernel.org?) for people to pull from, post patches to mainline now
and indicate you'd ask for a 2.6.29 merge ...
-mike
^ permalink raw reply
* Re: [PATCH 1/6] [PWM] Generic PWM API implementation
From: David Brownell @ 2008-11-04 23:55 UTC (permalink / raw)
To: Bill Gatliff; +Cc: linux-embedded
In-Reply-To: <4910AD88.2000200@billgatliff.com>
On Tuesday 04 November 2008, Bill Gatliff wrote:
> This is literally the only feedback I have received.
I was waiting for followup too. I finally get onto this
list (for some reason the list management software dropped
several previous "please add me" requests) and ... nothing!!
Patches #1 and #2 seem to be in the wrong order ... and
#2 shouldn't give the header's full pathname. I'd have
merged the two, myself.
Patch #6 seems to remove LEDS_ATMEL_PWM from Kconfig but
leave the driver around ... and restore the now-deleted
LEDS_CORGI support (leds-gpio suffices). If you're going
to remove LEDS_ATMEL_PWM you should update the code in
mach-at91/leds.c which sets up for that driver...
> So, what's the next step? How do I advocate for getting
> this API into mainline?
The number of backing implementations seemed a bit low ...
just one. And that's switching Atmel's dedicated PWM, but
not the other PWM driver in the tree (for PXA); so it's
not terrifically accessible.
And even for Atmel's SOC's it seemed a bit light: the TC
blocks will do PWM quite happily, and are found on many
more chips than the dedicated PWM hardware.
My rule of thumb is that it's not worth considering a
framework as being general enough until it's got three
fairly different backing implementations. Two is enough
to consider merging, especially with complicated drivers.
Plus the number of framework users is an issue. The
PWM led driver is a good demo for two basic features,
and it's useful: brightness (duty cycle beyond visual
perception) and blink rate (duty cycle easily seen with
the eye). But it's still only really one API customer,
even given that new LED trigger...
So I'd suggest fleshing it out a bit more, so it works
on some non-Atmel hardware as well as more Atmel SOCs.
And fix the goofs I noted above. :)
- Dave
^ permalink raw reply
* Re: [PATCH] phylib: make mdio-gpio work without OF (v2)
From: David Brownell @ 2008-11-05 0:04 UTC (permalink / raw)
To: Grant Likely
Cc: Paulius Zaleckas, netdev, linux-arm-kernel, linux-embedded,
Laurent Pinchart, Mike Frysinger
In-Reply-To: <fa686aa40811040824x52dab7fel9f76567cb6d49c8@mail.gmail.com>
On Tuesday 04 November 2008, Grant Likely wrote:
> At this point, instead of #ifdeffing the function signature, I would
> much rather see this generalized as something like
> 'mdio_gpio_setup()'. Then move the OF and non-OF specific bits into
> two new functions; mdio_ofgpio_probe() and mdio_gpio_probe(). The two
> new functions should be placed with the appropriate bus binding in the
> #ifdef/#else block at the bottom of the file.
Or if possible something that creates a single #ifdef that
ensures dead code elimination will remove the "other" branch,
but ensures all platforms will build both versions:
#ifdef OF
#define using_of true
#else
#define using_of false
#endif
...
static int __init mdio_gpio_init(void)
{
if (using_of)
return register mdio_ofgpio driver;
else
return register mdio_gpio driver;
}
subsys_initcall(mdio_gpio_init);
...
That's generally the preferred way to handle #ifdeffery.
But I could imagine OF isn't (yet?) set up to handle it.
- Dave
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox