* Re: [PATCH v2] qmi_wwan, cdc-ether: add ADU960S
From: David Miller @ 2013-02-19 5:54 UTC (permalink / raw)
To: dcbw-H+wXaHxf7aLQT0dZR+AlfA
Cc: bjorn-yOkvZcmFvRU, linux-usb-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1361244309.29695.12.camel-wKZy7rqYPVb5EHUCmHmTqw@public.gmane.org>
From: Dan Williams <dcbw-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Date: Mon, 18 Feb 2013 21:25:09 -0600
> It advertises a standard CDC-ETHER interface, which actually should be
> driven by qmi_wwan.
>
> Signed-off-by: Dan Williams <dcbw-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Applied.
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v2 net-next 0/6] qlcnic: bug fixes and feature updates
From: David Miller @ 2013-02-19 5:54 UTC (permalink / raw)
To: jitendra.kalsaria; +Cc: netdev, sony.chacko, Dept_NX_Linux_NIC_Driver
In-Reply-To: <1361225178-4363-1-git-send-email-jitendra.kalsaria@qlogic.com>
From: Jitendra Kalsaria <jitendra.kalsaria@qlogic.com>
Date: Mon, 18 Feb 2013 17:06:12 -0500
> From: Jitendra Kalsaria <jitendra.kalsaria@qlogic.com>
>
> Patch#1 "qlcnic: fix unsupported CDRP command error message" with commit id
> "e42ede226c067fef541e4240f919ed2baf25d268" is a re-submission and also respin
> as suggested by Joe Perches. We are re-submitting the same patch because this
> patch got undone by the recent driver refactoring.
>
> Patch#5 did not get through in the last submission.
>
> Please apply to net-next.
Series applied, thanks.
^ permalink raw reply
* [PATCH v2 3/5] usb: otg: twl4030: use the new generic PHY framework
From: Kishon Vijay Abraham I @ 2013-02-19 5:53 UTC (permalink / raw)
To: rob, tony, linux, eballetbo, javier, kishon, balbi, gregkh, akpm,
mchehab, cesarb, davem, arnd, santosh.shilimkar, broonie, swarren,
linux-doc, linux-kernel, linux-arm-kernel, linux-omap, linux-usb,
netdev
In-Reply-To: <1361253198-7401-1-git-send-email-kishon@ti.com>
Used the generic PHY framework API to create the PHY. twl4030_usb_suspend
and twl4030_usb_resume is added to phy_ops in order to align
with the new framework.
However using the old USB PHY library cannot be completely removed
because OTG is intertwined with PHY and moving to the new
framework completely will break OTG. Once we have a separate OTG state machine,
we can get rid of the USB PHY library.
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
drivers/usb/otg/twl4030-usb.c | 41 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 41 insertions(+)
diff --git a/drivers/usb/otg/twl4030-usb.c b/drivers/usb/otg/twl4030-usb.c
index a994715..b79c319 100644
--- a/drivers/usb/otg/twl4030-usb.c
+++ b/drivers/usb/otg/twl4030-usb.c
@@ -33,6 +33,7 @@
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/usb/otg.h>
+#include <linux/phy/phy.h>
#include <linux/usb/musb-omap.h>
#include <linux/usb/ulpi.h>
#include <linux/i2c/twl.h>
@@ -145,6 +146,7 @@
struct twl4030_usb {
struct usb_phy phy;
+ struct phy_descriptor desc;
struct device *dev;
/* TWL4030 internal USB regulator supplies */
@@ -167,6 +169,7 @@ struct twl4030_usb {
/* internal define on top of container_of */
#define phy_to_twl(x) container_of((x), struct twl4030_usb, phy)
+#define desc_to_twl(x) container_of((x), struct twl4030_usb, desc)
/*-------------------------------------------------------------------------*/
@@ -575,10 +578,38 @@ static int twl4030_set_host(struct usb_otg *otg, struct usb_bus *host)
return 0;
}
+static int twl4030_usb_suspend(struct phy_descriptor *desc)
+{
+ struct twl4030_usb *twl = desc_to_twl(desc);
+
+ twl4030_phy_suspend(twl, 1);
+
+ return 0;
+}
+
+static int twl4030_usb_resume(struct phy_descriptor *desc)
+{
+ struct twl4030_usb *twl = desc_to_twl(desc);
+
+ if (!twl->asleep)
+ return -EBUSY;
+ __twl4030_phy_resume(twl);
+ twl->asleep = 0;
+
+ return 0;
+}
+
+static struct phy_ops ops = {
+ .suspend = twl4030_usb_suspend,
+ .resume = twl4030_usb_resume,
+ .owner = THIS_MODULE,
+};
+
static int twl4030_usb_probe(struct platform_device *pdev)
{
struct twl4030_usb_data *pdata = pdev->dev.platform_data;
struct twl4030_usb *twl;
+ struct phy *phy;
int status, err;
struct usb_otg *otg;
struct device_node *np = pdev->dev.of_node;
@@ -617,6 +648,16 @@ static int twl4030_usb_probe(struct platform_device *pdev)
otg->set_host = twl4030_set_host;
otg->set_peripheral = twl4030_set_peripheral;
+ twl->desc.ops = &ops;
+ twl->desc.label = "twl4030";
+ twl->desc.of_node = pdev->dev.of_node;
+
+ phy = devm_phy_create(twl->dev, &twl->desc);
+ if (IS_ERR(phy)) {
+ dev_dbg(&pdev->dev, "Failed to create PHY\n");
+ return PTR_ERR(phy);
+ }
+
/* init spinlock for workqueue */
spin_lock_init(&twl->lock);
--
1.7.10.4
^ permalink raw reply related
* Re: [PATCH] b44: use netdev_alloc_skb_ip_align()
From: David Miller @ 2013-02-19 5:54 UTC (permalink / raw)
To: hauke; +Cc: zambrano, netdev
In-Reply-To: <1361220596-26478-1-git-send-email-hauke@hauke-m.de>
From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Mon, 18 Feb 2013 21:49:56 +0100
> Without this patch b44 always allocates the 2 bytes needed for aligned
> access on every platform, now it uses netdev_alloc_skb_ip_align().
>
> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
Applied.
^ permalink raw reply
* Re: [PATCH] xen: netback: remove redundant xenvif_put
From: David Miller @ 2013-02-19 5:53 UTC (permalink / raw)
To: drjones; +Cc: xen-devel, ian.campbell, netdev, linux-kernel
In-Reply-To: <1361219360-29176-1-git-send-email-drjones@redhat.com>
From: Andrew Jones <drjones@redhat.com>
Date: Mon, 18 Feb 2013 21:29:20 +0100
> netbk_fatal_tx_err() calls xenvif_carrier_off(), which does
> a xenvif_put(). As callers of netbk_fatal_tx_err should only
> have one reference to the vif at this time, then the xenvif_put
> in netbk_fatal_tx_err is one too many.
>
> Signed-off-by: Andrew Jones <drjones@redhat.com>
Applied.
^ permalink raw reply
* Re: [PATCH v4] net: fec: Do a sanity check on the gpio number
From: David Miller @ 2013-02-19 5:53 UTC (permalink / raw)
To: fabio.estevam; +Cc: shawn.guo, marex, s.hauer, netdev
In-Reply-To: <1361218831-17336-1-git-send-email-fabio.estevam@freescale.com>
From: Fabio Estevam <fabio.estevam@freescale.com>
Date: Mon, 18 Feb 2013 17:20:31 -0300
> Check whether the phy-reset GPIO is valid, prior to requesting it.
>
> In the case a board does not provide a phy-reset GPIO, just returns immediately.
>
> With such gpio validation in place, it is also safe to change from pr_debug to
> dev_err in the case the gpio request fails.
>
> Signed-off-by: Fabio Estevam <fabio.estevam@freescale.com>
Applied.
^ permalink raw reply
* Re: [PATCH net-next v2 2/2] ip_gre: propogate target device GSO capability to the tunnel device
From: David Miller @ 2013-02-19 5:53 UTC (permalink / raw)
To: dmitry; +Cc: netdev
In-Reply-To: <1361217053-16984-2-git-send-email-dmitry@broadcom.com>
From: "Dmitry Kravkov" <dmitry@broadcom.com>
Date: Mon, 18 Feb 2013 21:50:53 +0200
> Signed-off-by: Dmitry Kravkov <dmitry@broadcom.com>
Applied.
^ permalink raw reply
* Re: [PATCH net-next v2 1/2] ip_gre: allow CSUM capable devices to handle packets
From: David Miller @ 2013-02-19 5:53 UTC (permalink / raw)
To: dmitry; +Cc: netdev
In-Reply-To: <1361217053-16984-1-git-send-email-dmitry@broadcom.com>
From: "Dmitry Kravkov" <dmitry@broadcom.com>
Date: Mon, 18 Feb 2013 21:50:52 +0200
> If device is not able to handle checksumming it will
> be handled in dev_xmit
>
> Signed-off-by: Dmitry Kravkov <dmitry@broadcom.com>
Applied.
^ permalink raw reply
* [PATCH v2 5/5] usb: musb: omap2430: use the new generic PHY framework
From: Kishon Vijay Abraham I @ 2013-02-19 5:53 UTC (permalink / raw)
To: rob, tony, linux, eballetbo, javier, kishon, balbi, gregkh, akpm,
mchehab, cesarb, davem, arnd, santosh.shilimkar, broonie, swarren,
linux-doc, linux-kernel, linux-arm-kernel, linux-omap, linux-usb,
netdev
In-Reply-To: <1361253198-7401-1-git-send-email-kishon@ti.com>
Use the generic PHY framework API to get the PHY. The usb_phy_set_suspend
and usb_phy_set_resume is replaced with phy_suspend and phy_resume to
align with the new PHY framework.
musb->xceiv can't be removed as of now because musb core uses xceiv.state and
xceiv.otg. Once there is a separate state machine to handle otg, these can be
moved out of xceiv and then we can start using the generic PHY framework.
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
drivers/usb/musb/musb_core.h | 2 ++
drivers/usb/musb/omap2430.c | 22 ++++++++++++++++------
2 files changed, 18 insertions(+), 6 deletions(-)
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
index 7fb4819..78251fd 100644
--- a/drivers/usb/musb/musb_core.h
+++ b/drivers/usb/musb/musb_core.h
@@ -46,6 +46,7 @@
#include <linux/usb.h>
#include <linux/usb/otg.h>
#include <linux/usb/musb.h>
+#include <linux/phy/phy.h>
struct musb;
struct musb_hw_ep;
@@ -357,6 +358,7 @@ struct musb {
u16 int_tx;
struct usb_phy *xceiv;
+ struct phy *phy;
int nIrq;
unsigned irq_wake:1;
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
index 1762354..99378af 100644
--- a/drivers/usb/musb/omap2430.c
+++ b/drivers/usb/musb/omap2430.c
@@ -345,14 +345,24 @@ static int omap2430_musb_init(struct musb *musb)
* up through ULPI. TWL4030-family PMICs include one,
* which needs a driver, drivers aren't always needed.
*/
- if (dev->parent->of_node)
+ if (dev->parent->of_node) {
+ musb->phy = devm_of_phy_get(dev->parent, "usb-phy", 0);
+
+ /* We can't totally remove musb->xceiv as of now because
+ * musb core uses xceiv.state and xceiv.otg. Once we have
+ * a separate state machine to handle otg, these can be moved
+ * out of xceiv and then we can start using the generic PHY
+ * framework
+ */
musb->xceiv = devm_usb_get_phy_by_phandle(dev->parent,
"usb-phy", 0);
- else
+ } else {
musb->xceiv = devm_usb_get_phy_dev(dev, 0);
+ musb->phy = devm_phy_get(dev, 0);
+ }
- if (IS_ERR_OR_NULL(musb->xceiv)) {
- pr_err("HS USB OTG: no transceiver configured\n");
+ if (IS_ERR_OR_NULL(musb->xceiv) || IS_ERR_OR_NULL(musb->phy)) {
+ dev_err(dev, "no transceiver configured\n");
return -EPROBE_DEFER;
}
@@ -608,7 +618,7 @@ static int omap2430_runtime_suspend(struct device *dev)
OTG_INTERFSEL);
omap2430_low_level_exit(musb);
- usb_phy_set_suspend(musb->xceiv, 1);
+ phy_suspend(musb->phy);
}
return 0;
@@ -624,7 +634,7 @@ static int omap2430_runtime_resume(struct device *dev)
musb_writel(musb->mregs, OTG_INTERFSEL,
musb->context.otg_interfsel);
- usb_phy_set_suspend(musb->xceiv, 0);
+ phy_resume(musb->phy);
}
return 0;
--
1.7.10.4
^ permalink raw reply related
* Re: [PATCHv2] bonding: set sysfs device_type to 'bond'
From: David Miller @ 2013-02-19 5:53 UTC (permalink / raw)
To: cardoe; +Cc: netdev, fubar, andy
In-Reply-To: <1361235563-2684-1-git-send-email-cardoe@cardoe.com>
From: Doug Goldstein <cardoe@cardoe.com>
Date: Mon, 18 Feb 2013 18:59:23 -0600
> Sets the sysfs device_type to 'bond' for udev. This allows udev rules to
> be created for bond devices. This is similar to how other network
> devices set their device_type.
>
> Signed-off-by: Doug Goldstein <cardoe@cardoe.com>
Applied.
^ permalink raw reply
* [PATCH v2 4/5] ARM: OMAP: USB: Add phy binding information
From: Kishon Vijay Abraham I @ 2013-02-19 5:53 UTC (permalink / raw)
To: rob, tony, linux, eballetbo, javier, kishon, balbi, gregkh, akpm,
mchehab, cesarb, davem, arnd, santosh.shilimkar, broonie, swarren,
linux-doc, linux-kernel, linux-arm-kernel, linux-omap, linux-usb,
netdev
In-Reply-To: <1361253198-7401-1-git-send-email-kishon@ti.com>
In order for controllers to get PHY in case of non dt boot, the phy
binding information should be added in the platform specific
initialization code using phy_bind. The previously added usb_bind_phy
can't be removed yet because the musb controller continues to use the
old PHY library which has OTG in it (struct usb_phy has struct usb_otg
as member). Until we have a separate OTG state machine to handle all of
that, the new generic PHY framework and the old phy library will co-exist.
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
arch/arm/mach-omap2/board-2430sdp.c | 2 ++
arch/arm/mach-omap2/board-3430sdp.c | 2 ++
arch/arm/mach-omap2/board-4430sdp.c | 2 ++
arch/arm/mach-omap2/board-cm-t35.c | 2 ++
arch/arm/mach-omap2/board-devkit8000.c | 2 ++
arch/arm/mach-omap2/board-igep0020.c | 2 ++
arch/arm/mach-omap2/board-ldp.c | 2 ++
arch/arm/mach-omap2/board-omap3beagle.c | 2 ++
arch/arm/mach-omap2/board-omap3evm.c | 2 ++
arch/arm/mach-omap2/board-omap3logic.c | 2 ++
arch/arm/mach-omap2/board-omap3pandora.c | 2 ++
arch/arm/mach-omap2/board-omap3stalker.c | 2 ++
arch/arm/mach-omap2/board-omap3touchbook.c | 2 ++
arch/arm/mach-omap2/board-omap4panda.c | 2 ++
arch/arm/mach-omap2/board-overo.c | 2 ++
arch/arm/mach-omap2/board-rm680.c | 2 ++
arch/arm/mach-omap2/board-zoom-peripherals.c | 2 ++
17 files changed, 34 insertions(+)
diff --git a/arch/arm/mach-omap2/board-2430sdp.c b/arch/arm/mach-omap2/board-2430sdp.c
index 1337f2c..a28cc5b 100644
--- a/arch/arm/mach-omap2/board-2430sdp.c
+++ b/arch/arm/mach-omap2/board-2430sdp.c
@@ -28,6 +28,7 @@
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/usb/phy.h>
+#include <linux/phy/phy.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -265,6 +266,7 @@ static void __init omap_2430sdp_init(void)
omap_mux_init_signal("usb0hs_stp", OMAP_PULL_ENA | OMAP_PULL_UP);
usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
+ phy_bind("musb-hdrc.0.auto", 0, "twl4030_usb");
usb_musb_init(NULL);
board_smc91x_init();
diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c
index 8a2e242..a4f4b8e 100644
--- a/arch/arm/mach-omap2/board-3430sdp.c
+++ b/arch/arm/mach-omap2/board-3430sdp.c
@@ -26,6 +26,7 @@
#include <linux/mmc/host.h>
#include <linux/platform_data/spi-omap2-mcspi.h>
#include <linux/usb/phy.h>
+#include <linux/phy/phy.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -581,6 +582,7 @@ static void __init omap_3430sdp_init(void)
omap_serial_init();
omap_sdrc_init(hyb18m512160af6_sdrc_params, NULL);
usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
+ phy_bind("musb-hdrc.0.auto", 0, "twl4030_usb");
usb_musb_init(NULL);
board_smc91x_init();
board_flash_init(sdp_flash_partitions, chip_sel_3430, 0);
diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c
index 8e8efcc..d5bc353 100644
--- a/arch/arm/mach-omap2/board-4430sdp.c
+++ b/arch/arm/mach-omap2/board-4430sdp.c
@@ -29,6 +29,7 @@
#include <linux/platform_data/omap4-keypad.h>
#include <linux/usb/musb.h>
#include <linux/usb/phy.h>
+#include <linux/phy/phy.h>
#include <asm/hardware/gic.h>
#include <asm/mach-types.h>
@@ -698,6 +699,7 @@ static void __init omap_4430sdp_init(void)
omap4_twl6030_hsmmc_init(mmc);
usb_bind_phy("musb-hdrc.0.auto", 0, "omap-usb2.1.auto");
+ phy_bind("musb-hdrc.0.auto", 0, "omap-usb2.1.auto");
usb_musb_init(&musb_board_data);
status = omap_ethernet_init();
diff --git a/arch/arm/mach-omap2/board-cm-t35.c b/arch/arm/mach-omap2/board-cm-t35.c
index f1172f2..6860dc9 100644
--- a/arch/arm/mach-omap2/board-cm-t35.c
+++ b/arch/arm/mach-omap2/board-cm-t35.c
@@ -31,6 +31,7 @@
#include <linux/regulator/machine.h>
#include <linux/mmc/host.h>
#include <linux/usb/phy.h>
+#include <linux/phy/phy.h>
#include <linux/spi/spi.h>
#include <linux/spi/tdo24m.h>
@@ -726,6 +727,7 @@ static void __init cm_t3x_common_init(void)
omap_twl4030_audio_init("cm-t3x");
usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
+ phy_bind("musb-hdrc.0.auto", 0, "twl4030_usb");
usb_musb_init(NULL);
cm_t35_init_usbh();
cm_t35_init_camera();
diff --git a/arch/arm/mach-omap2/board-devkit8000.c b/arch/arm/mach-omap2/board-devkit8000.c
index 77cade52..89c3e64 100644
--- a/arch/arm/mach-omap2/board-devkit8000.c
+++ b/arch/arm/mach-omap2/board-devkit8000.c
@@ -30,6 +30,7 @@
#include <linux/mtd/nand.h>
#include <linux/mmc/host.h>
#include <linux/usb/phy.h>
+#include <linux/phy/phy.h>
#include <linux/regulator/machine.h>
#include <linux/i2c/twl.h>
@@ -624,6 +625,7 @@ static void __init devkit8000_init(void)
omap_ads7846_init(2, OMAP3_DEVKIT_TS_GPIO, 0, NULL);
usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
+ phy_bind("musb-hdrc.0.auto", 0, "twl4030_usb");
usb_musb_init(NULL);
usbhs_init(&usbhs_bdata);
board_nand_init(devkit8000_nand_partitions,
diff --git a/arch/arm/mach-omap2/board-igep0020.c b/arch/arm/mach-omap2/board-igep0020.c
index 15e5881..2ef8b31 100644
--- a/arch/arm/mach-omap2/board-igep0020.c
+++ b/arch/arm/mach-omap2/board-igep0020.c
@@ -19,6 +19,7 @@
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/usb/phy.h>
+#include <linux/phy/phy.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/fixed.h>
@@ -627,6 +628,7 @@ static void __init igep_init(void)
omap_sdrc_init(m65kxxxxam_sdrc_params,
m65kxxxxam_sdrc_params);
usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
+ phy_bind("musb-hdrc.0.auto", 0, "twl4030_usb");
usb_musb_init(NULL);
igep_flash_init();
diff --git a/arch/arm/mach-omap2/board-ldp.c b/arch/arm/mach-omap2/board-ldp.c
index 3b5510a..c2d8cbd 100644
--- a/arch/arm/mach-omap2/board-ldp.c
+++ b/arch/arm/mach-omap2/board-ldp.c
@@ -29,6 +29,7 @@
#include <linux/smsc911x.h>
#include <linux/mmc/host.h>
#include <linux/usb/phy.h>
+#include <linux/phy/phy.h>
#include <linux/platform_data/spi-omap2-mcspi.h>
#include <asm/mach-types.h>
@@ -420,6 +421,7 @@ static void __init omap_ldp_init(void)
omap_serial_init();
omap_sdrc_init(NULL, NULL);
usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
+ phy_bind("musb-hdrc.0.auto", 0, "twl4030_usb");
usb_musb_init(NULL);
board_nand_init(ldp_nand_partitions, ARRAY_SIZE(ldp_nand_partitions),
ZOOM_NAND_CS, 0, nand_default_timings);
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
index 4616f92..6f17343 100644
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ b/arch/arm/mach-omap2/board-omap3beagle.c
@@ -31,6 +31,7 @@
#include <linux/mtd/nand.h>
#include <linux/mmc/host.h>
#include <linux/usb/phy.h>
+#include <linux/phy/phy.h>
#include <linux/regulator/machine.h>
#include <linux/i2c/twl.h>
@@ -521,6 +522,7 @@ static void __init omap3_beagle_init(void)
mt46h32m32lf6_sdrc_params);
usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
+ phy_bind("musb-hdrc.0.auto", 0, "twl4030_usb");
usb_musb_init(NULL);
usbhs_init(&usbhs_bdata);
board_nand_init(omap3beagle_nand_partitions,
diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c
index a198b61..bfd3927 100644
--- a/arch/arm/mach-omap2/board-omap3evm.c
+++ b/arch/arm/mach-omap2/board-omap3evm.c
@@ -42,6 +42,7 @@
#include <linux/mmc/host.h>
#include <linux/export.h>
#include <linux/usb/phy.h>
+#include <linux/phy/phy.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -736,6 +737,7 @@ static void __init omap3_evm_init(void)
usbhs_bdata.reset_gpio_port[1] = 135;
}
usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
+ phy_bind("musb-hdrc.0.auto", 0, "twl4030_usb");
usb_musb_init(&musb_board_data);
usbhs_init(&usbhs_bdata);
board_nand_init(omap3evm_nand_partitions,
diff --git a/arch/arm/mach-omap2/board-omap3logic.c b/arch/arm/mach-omap2/board-omap3logic.c
index 9409eb8..64d4daf 100644
--- a/arch/arm/mach-omap2/board-omap3logic.c
+++ b/arch/arm/mach-omap2/board-omap3logic.c
@@ -30,6 +30,7 @@
#include <linux/i2c/twl.h>
#include <linux/mmc/host.h>
#include <linux/usb/phy.h>
+#include <linux/phy/phy.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -217,6 +218,7 @@ static void __init omap3logic_init(void)
board_smsc911x_init();
usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
+ phy_bind("musb-hdrc.0.auto", 0, "twl4030_usb");
usb_musb_init(NULL);
/* Ensure SDRC pins are mux'd for self-refresh */
diff --git a/arch/arm/mach-omap2/board-omap3pandora.c b/arch/arm/mach-omap2/board-omap3pandora.c
index 1ac3e81..b391107 100644
--- a/arch/arm/mach-omap2/board-omap3pandora.c
+++ b/arch/arm/mach-omap2/board-omap3pandora.c
@@ -36,6 +36,7 @@
#include <linux/mmc/card.h>
#include <linux/regulator/fixed.h>
#include <linux/usb/phy.h>
+#include <linux/phy/phy.h>
#include <linux/platform_data/spi-omap2-mcspi.h>
#include <asm/mach-types.h>
@@ -603,6 +604,7 @@ static void __init omap3pandora_init(void)
omap_ads7846_init(1, OMAP3_PANDORA_TS_GPIO, 0, NULL);
usbhs_init(&usbhs_bdata);
usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
+ phy_bind("musb-hdrc.0.auto", 0, "twl4030_usb");
usb_musb_init(NULL);
gpmc_nand_init(&pandora_nand_data, NULL);
diff --git a/arch/arm/mach-omap2/board-omap3stalker.c b/arch/arm/mach-omap2/board-omap3stalker.c
index 63cb204..8f22977 100644
--- a/arch/arm/mach-omap2/board-omap3stalker.c
+++ b/arch/arm/mach-omap2/board-omap3stalker.c
@@ -34,6 +34,7 @@
#include <linux/smsc911x.h>
#include <linux/i2c/at24.h>
#include <linux/usb/phy.h>
+#include <linux/phy/phy.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -406,6 +407,7 @@ static void __init omap3_stalker_init(void)
omap_serial_init();
omap_sdrc_init(mt46h32m32lf6_sdrc_params, NULL);
usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
+ phy_bind("musb-hdrc.0.auto", 0, "twl4030_usb");
usb_musb_init(NULL);
usbhs_init(&usbhs_bdata);
omap_ads7846_init(1, OMAP3_STALKER_TS_GPIO, 310, NULL);
diff --git a/arch/arm/mach-omap2/board-omap3touchbook.c b/arch/arm/mach-omap2/board-omap3touchbook.c
index 6b22ce3..acd82e4 100644
--- a/arch/arm/mach-omap2/board-omap3touchbook.c
+++ b/arch/arm/mach-omap2/board-omap3touchbook.c
@@ -29,6 +29,7 @@
#include <linux/mtd/nand.h>
#include <linux/mmc/host.h>
#include <linux/usb/phy.h>
+#include <linux/phy/phy.h>
#include <linux/platform_data/spi-omap2-mcspi.h>
#include <linux/spi/spi.h>
@@ -367,6 +368,7 @@ static void __init omap3_touchbook_init(void)
/* Touchscreen and accelerometer */
omap_ads7846_init(4, OMAP3_TS_GPIO, 310, &ads7846_pdata);
usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
+ phy_bind("musb-hdrc.0.auto", 0, "twl4030_usb");
usb_musb_init(NULL);
usbhs_init(&usbhs_bdata);
board_nand_init(omap3touchbook_nand_partitions,
diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c
index 40184cc..7fe4363 100644
--- a/arch/arm/mach-omap2/board-omap4panda.c
+++ b/arch/arm/mach-omap2/board-omap4panda.c
@@ -31,6 +31,7 @@
#include <linux/ti_wilink_st.h>
#include <linux/usb/musb.h>
#include <linux/usb/phy.h>
+#include <linux/phy/phy.h>
#include <linux/wl12xx.h>
#include <linux/platform_data/omap-abe-twl6040.h>
@@ -449,6 +450,7 @@ static void __init omap4_panda_init(void)
omap4_twl6030_hsmmc_init(mmc);
omap4_ehci_init();
usb_bind_phy("musb-hdrc.0.auto", 0, "omap-usb2.1.auto");
+ phy_bind("musb-hdrc.0.auto", 0, "omap-usb2.1.auto");
usb_musb_init(&musb_board_data);
omap4_panda_display_init();
}
diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c
index 7e43ff3..92835cc 100644
--- a/arch/arm/mach-omap2/board-overo.c
+++ b/arch/arm/mach-omap2/board-overo.c
@@ -37,6 +37,7 @@
#include <linux/mtd/partitions.h>
#include <linux/mmc/host.h>
#include <linux/usb/phy.h>
+#include <linux/phy/phy.h>
#include <linux/platform_data/mtd-nand-omap2.h>
#include <linux/platform_data/spi-omap2-mcspi.h>
@@ -501,6 +502,7 @@ static void __init overo_init(void)
board_nand_init(overo_nand_partitions,
ARRAY_SIZE(overo_nand_partitions), NAND_CS, 0, NULL);
usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
+ phy_bind("musb-hdrc.0.auto", 0, "twl4030_usb");
usb_musb_init(NULL);
usbhs_init(&usbhs_bdata);
overo_spi_init();
diff --git a/arch/arm/mach-omap2/board-rm680.c b/arch/arm/mach-omap2/board-rm680.c
index f8a272c..ed854ca 100644
--- a/arch/arm/mach-omap2/board-rm680.c
+++ b/arch/arm/mach-omap2/board-rm680.c
@@ -19,6 +19,7 @@
#include <linux/regulator/consumer.h>
#include <linux/platform_data/mtd-onenand-omap2.h>
#include <linux/usb/phy.h>
+#include <linux/phy/phy.h>
#include <asm/mach/arch.h>
#include <asm/mach-types.h>
@@ -136,6 +137,7 @@ static void __init rm680_init(void)
omap_sdrc_init(sdrc_params, sdrc_params);
usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
+ phy_bind("musb-hdrc.0.auto", 0, "twl4030_usb");
usb_musb_init(NULL);
rm680_peripherals_init();
}
diff --git a/arch/arm/mach-omap2/board-zoom-peripherals.c b/arch/arm/mach-omap2/board-zoom-peripherals.c
index dc5498b..2093e25 100644
--- a/arch/arm/mach-omap2/board-zoom-peripherals.c
+++ b/arch/arm/mach-omap2/board-zoom-peripherals.c
@@ -21,6 +21,7 @@
#include <linux/mmc/host.h>
#include <linux/platform_data/gpio-omap.h>
#include <linux/usb/phy.h>
+#include <linux/phy/phy.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -300,6 +301,7 @@ void __init zoom_peripherals_init(void)
omap_i2c_init();
platform_device_register(&omap_vwlan_device);
usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
+ phy_bind("musb-hdrc.0.auto", 0, "twl4030_usb");
usb_musb_init(NULL);
enable_board_wakeup_source();
omap_serial_init();
--
1.7.10.4
^ permalink raw reply related
* [PATCH v2 2/5] usb: phy: omap-usb2: use the new generic PHY framework
From: Kishon Vijay Abraham I @ 2013-02-19 5:53 UTC (permalink / raw)
To: rob, tony, linux, eballetbo, javier, kishon, balbi, gregkh, akpm,
mchehab, cesarb, davem, arnd, santosh.shilimkar, broonie, swarren,
linux-doc, linux-kernel, linux-arm-kernel, linux-omap, linux-usb,
netdev
In-Reply-To: <1361253198-7401-1-git-send-email-kishon@ti.com>
Used the generic PHY framework API to create the PHY. omap_usb2_suspend
is split into omap_usb_suspend and omap_usb_resume in order to align
with the new framework.
However using the old USB PHY library cannot be completely removed
because OTG is intertwined with PHY and moving to the new framework
will break OTG. Once we have a separate OTG state machine, we
can get rid of the USB PHY library.
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
drivers/usb/phy/omap-usb2.c | 49 ++++++++++++++++++++++++++++++++++++++++++
include/linux/usb/omap_usb.h | 3 +++
2 files changed, 52 insertions(+)
diff --git a/drivers/usb/phy/omap-usb2.c b/drivers/usb/phy/omap-usb2.c
index 844ab68..924ae59 100644
--- a/drivers/usb/phy/omap-usb2.c
+++ b/drivers/usb/phy/omap-usb2.c
@@ -119,9 +119,48 @@ static int omap_usb2_suspend(struct usb_phy *x, int suspend)
return 0;
}
+static int omap_usb_suspend(struct phy_descriptor *desc)
+{
+ struct omap_usb *phy = desc_to_omapusb(desc);
+
+ if (!phy->is_suspended) {
+ omap_control_usb_phy_power(phy->control_dev, 0);
+ pm_runtime_put_sync(phy->dev);
+ phy->is_suspended = 1;
+ }
+
+ return 0;
+}
+
+static int omap_usb_resume(struct phy_descriptor *desc)
+{
+ u32 ret;
+ struct omap_usb *phy = desc_to_omapusb(desc);
+
+ if (phy->is_suspended) {
+ ret = pm_runtime_get_sync(phy->dev);
+ if (ret < 0) {
+ dev_err(phy->dev, "get_sync failed with err %d\n",
+ ret);
+ return ret;
+ }
+ omap_control_usb_phy_power(phy->control_dev, 1);
+ phy->is_suspended = 0;
+ }
+
+ return 0;
+}
+
+static struct phy_ops ops = {
+ .suspend = omap_usb_suspend,
+ .resume = omap_usb_resume,
+ .owner = THIS_MODULE,
+};
+
static int omap_usb2_probe(struct platform_device *pdev)
{
struct omap_usb *phy;
+ struct phy *generic_phy;
struct usb_otg *otg;
phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL);
@@ -144,6 +183,16 @@ static int omap_usb2_probe(struct platform_device *pdev)
phy->phy.otg = otg;
phy->phy.type = USB_PHY_TYPE_USB2;
+ phy->desc.ops = &ops;
+ phy->desc.label = "omap-usb2";
+ phy->desc.of_node = pdev->dev.of_node;
+
+ generic_phy = devm_phy_create(phy->dev, &phy->desc);
+ if (IS_ERR(generic_phy)) {
+ dev_dbg(&pdev->dev, "Failed to create PHY\n");
+ return PTR_ERR(generic_phy);
+ }
+
phy->control_dev = omap_get_control_dev();
if (IS_ERR(phy->control_dev)) {
dev_dbg(&pdev->dev, "Failed to get control device\n");
diff --git a/include/linux/usb/omap_usb.h b/include/linux/usb/omap_usb.h
index 6ae2936..4c6878e 100644
--- a/include/linux/usb/omap_usb.h
+++ b/include/linux/usb/omap_usb.h
@@ -20,6 +20,7 @@
#define __DRIVERS_OMAP_USB2_H
#include <linux/io.h>
+#include <linux/phy/phy.h>
#include <linux/usb/otg.h>
struct usb_dpll_params {
@@ -32,6 +33,7 @@ struct usb_dpll_params {
struct omap_usb {
struct usb_phy phy;
+ struct phy_descriptor desc;
struct phy_companion *comparator;
void __iomem *pll_ctrl_base;
struct device *dev;
@@ -43,6 +45,7 @@ struct omap_usb {
};
#define phy_to_omapusb(x) container_of((x), struct omap_usb, phy)
+#define desc_to_omapusb(x) container_of((x), struct omap_usb, desc)
#if defined(CONFIG_OMAP_USB2) || defined(CONFIG_OMAP_USB2_MODULE)
extern int omap_usb2_set_comparator(struct phy_companion *comparator);
--
1.7.10.4
^ permalink raw reply related
* [PATCH v2 1/5] drivers: phy: add generic PHY framework
From: Kishon Vijay Abraham I @ 2013-02-19 5:53 UTC (permalink / raw)
To: rob, tony, linux, eballetbo, javier, kishon, balbi, gregkh, akpm,
mchehab, cesarb, davem, arnd, santosh.shilimkar, broonie, swarren,
linux-doc, linux-kernel, linux-arm-kernel, linux-omap, linux-usb,
netdev
In-Reply-To: <1361253198-7401-1-git-send-email-kishon@ti.com>
The PHY framework provides a set of APIs for the PHY drivers to
create/destroy a PHY and APIs for the PHY users to obtain a reference to the
PHY with or without using phandle. To obtain a reference to the PHY without
using phandle, the platform specfic intialization code (say from board file)
should have already called phy_bind with the binding information. The binding
information consists of phy's device name, phy user device name and an index.
The index is used when the same phy user binds to mulitple phys.
PHY drivers should create the PHY by passing phy_descriptor that has
describes the PHY (label, type etc..) and ops like init, exit, suspend, resume,
poweron, shutdown.
The documentation for the generic PHY framework is added in
Documentation/phy.txt and the documentation for the sysfs entry is added
in Documentation/ABI/testing/sysfs-class-phy.
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
Documentation/ABI/testing/sysfs-class-phy | 15 +
Documentation/phy.txt | 113 +++++++
MAINTAINERS | 7 +
drivers/Kconfig | 2 +
drivers/Makefile | 2 +
drivers/phy/Kconfig | 13 +
drivers/phy/Makefile | 5 +
drivers/phy/phy-core.c | 519 +++++++++++++++++++++++++++++
include/linux/phy/phy.h | 198 +++++++++++
9 files changed, 874 insertions(+)
create mode 100644 Documentation/ABI/testing/sysfs-class-phy
create mode 100644 Documentation/phy.txt
create mode 100644 drivers/phy/Kconfig
create mode 100644 drivers/phy/Makefile
create mode 100644 drivers/phy/phy-core.c
create mode 100644 include/linux/phy/phy.h
diff --git a/Documentation/ABI/testing/sysfs-class-phy b/Documentation/ABI/testing/sysfs-class-phy
new file mode 100644
index 0000000..ffd9930
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-phy
@@ -0,0 +1,15 @@
+What: /sys/class/phy/<phy>/label
+Date: Feb 2013
+KernelVersion: 3.10
+Contact: Kishon Vijay Abraham I <kishon@ti.com>
+Description:
+ This is a read-only file for getting the label of the phy.
+
+What: /sys/class/phy/<phy>/bind
+Date: Feb 2013
+KernelVersion: 3.10
+Contact: Kishon Vijay Abraham I <kishon@ti.com>
+Description:
+ This is a read-only file for reading the phy binding
+ information. It contains the device name of the controller,
+ the index and the device name of the PHY in that order.
diff --git a/Documentation/phy.txt b/Documentation/phy.txt
new file mode 100644
index 0000000..a850aa0
--- /dev/null
+++ b/Documentation/phy.txt
@@ -0,0 +1,113 @@
+ The Generic PHY Framework
+ Kishon Vijay Abraham I <kishon@ti.com>
+
+This document explains the Generic PHY Framework along with the APIs provided,
+how-to-use, current status and the future work list.
+
+1. Introduction
+
+*PHY* is the abbreviation for physical layer. It is used to connect a device
+to the physical medium e.g., the USB controller has a PHY to provide functions
+such as serialization, de-serialization, encoding, decoding and is responsible
+for obtaining the required data transmission rate. Note that some USB
+controller has PHY functionality embedded into it and others use an external
+PHY. Other peripherals that uses a PHY include Wireless LAN, Ethernet,
+SATA etc.
+
+The intention of creating this framework is to bring the phy drivers spread
+all over the Linux kernel to drivers/phy to increase code re-use and to
+increase code maintainability.
+
+This framework will be of use only to devices that uses external PHY (PHY
+functionality is not embedded within the controller).
+
+2. Creating the PHY
+
+The PHY driver should create the PHY in order for other peripheral controllers
+to make use of it. The PHY framework provides 2 APIs to create the PHY.
+
+struct phy *phy_create(struct device *dev, struct phy_descriptor *desc);
+struct phy *devm_phy_create(struct device *dev, struct phy_descriptor *desc);
+
+The PHY drivers can use one of the above 2 APIs to create the PHY by passing
+the device pointer and the phy_descriptor. phy_descriptor is a structure that
+contains information about the PHY such as label, type, bus_type and phy_ops.
+phy_ops is a set of function pointers for performing PHY operations such as
+init, exit, suspend, resume, poweron and shutdown.
+
+3. Binding the PHY to the controller
+
+The framework provides an API for binding the controller to the PHY in the
+case of non dt boot.
+
+struct phy_bind *phy_bind(const char *dev_name, u8 index,
+ const char *phy_dev_name);
+
+The API fills the phy_bind structure with the dev_name (device name of the
+controller), index and phy_dev_name (device name of the PHY). This will
+be used when the controller requests this phy. This API should be used by
+platform specific initialization code (board file).
+
+In the case of dt boot, the binding information should be added in the dt
+data of the controller.
+
+4. Getting a reference to the PHY
+
+Before the controller can make use of the PHY, it has to get a reference to
+the PHY. The PHY framework provides 4 APIs to get a reference to the PHY.
+
+struct phy *phy_get(struct device *dev, u8 index);
+struct phy *devm_phy_get(struct device *dev, u8 index);
+struct phy *of_phy_get(struct device *dev, const char *phandle, u8 index);
+struct phy *devm_of_phy_get(struct device *dev, const char *phandle, u8 index);
+
+phy_get and devm_phy_get can be used to get the PHY in non-dt boot. This API
+uses the binding information added using the phy_bind API to find and return
+the appropriate PHY. The only difference between the two APIs is that
+devm_phy_get associates the device with the PHY using devres on successful PHY
+get. On driver detach, release function is invoked on the the devres data and
+devres data is freed.
+
+of_phy_get and devm_of_phy_get can be used to get the PHY in dt boot. These
+APIs take the phandle and index to get a reference to the PHY. The only
+difference between the two APIs is that devm_of_phy_get associates the device
+with the PHY using devres on successful phy get. On driver detach, release
+function is invoked on the the devres data and devres data is freed.
+
+5. Releasing a reference to the PHY
+
+When the controller no longer needs the PHY, it has to release the reference
+to the PHY it has obtained using the APIs mentioned in the above section. The
+PHY framework provides 2 APIS to release a reference to the PHY.
+
+void phy_put(struct phy *phy);
+void devm_phy_put(struct device *dev, struct phy *phy);
+
+Both these APIs are used to release a reference to the PHY and devm_phy_put
+destroys the devres associated with this PHY.
+
+6. Destroying the PHY
+
+When the driver that created the PHY is unloaded, it should destroy the PHY it
+created using one of the following 2 APIs.
+
+void phy_destroy(struct phy *phy);
+void devm_phy_destroy(struct device *dev, struct phy *phy);
+
+Both these APIs destroys the PHY and devm_phy_destroy destroys the devres
+associated with this PHY.
+
+7. Current Status
+
+Currently only USB in OMAP is made to use this framework. However using the
+USB PHY library cannot be completely removed because it is intertwined with
+OTG. Once we move OTG out of PHY completely, using the old PHY library can be
+completely removed. SATA in OMAP will also more likely use this new framework
+and we should have a patch for it soon.
+
+8. Future Work list
+
+The intention of writing this framework is to have all the phy drivers spread
+all over the kernel to use this framework and have it in drivers/phy/. So
+immediate action items include make USB and Ethernet use this Generic PHY
+Framework.
diff --git a/MAINTAINERS b/MAINTAINERS
index c5b37de..cba2a92 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3381,6 +3381,13 @@ S: Maintained
F: include/asm-generic
F: include/uapi/asm-generic
+GENERIC PHY FRAMEWORK
+M: Kishon Vijay Abraham I <kishon@ti.com>
+L: linux-kernel@vger.kernel.org
+S: Supported
+F: drivers/phy/
+F: include/linux/phy/
+
GENERIC UIO DRIVER FOR PCI DEVICES
M: "Michael S. Tsirkin" <mst@redhat.com>
L: kvm@vger.kernel.org
diff --git a/drivers/Kconfig b/drivers/Kconfig
index f5fb072..5230abe 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -158,4 +158,6 @@ source "drivers/irqchip/Kconfig"
source "drivers/ipack/Kconfig"
+source "drivers/phy/Kconfig"
+
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 7863b9f..4d5c9cb 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -45,6 +45,8 @@ obj-y += char/
# gpu/ comes after char for AGP vs DRM startup
obj-y += gpu/
+obj-y += phy/
+
obj-$(CONFIG_CONNECTOR) += connector/
# i810fb and intelfb depend on char/agp/
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
new file mode 100644
index 0000000..34f7077
--- /dev/null
+++ b/drivers/phy/Kconfig
@@ -0,0 +1,13 @@
+#
+# PHY
+#
+
+menuconfig GENERIC_PHY
+ tristate "Generic PHY Support"
+ help
+ Generic PHY support.
+
+ This framework is designed to provide a generic interface for PHY
+ devices present in the kernel. This layer will have the generic
+ API by which phy drivers can create PHY using the phy framework and
+ phy users can obtain reference to the PHY.
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
new file mode 100644
index 0000000..9e9560f
--- /dev/null
+++ b/drivers/phy/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the phy drivers.
+#
+
+obj-$(CONFIG_GENERIC_PHY) += phy-core.o
diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
new file mode 100644
index 0000000..c52aaf8
--- /dev/null
+++ b/drivers/phy/phy-core.c
@@ -0,0 +1,519 @@
+/*
+ * phy-core.c -- Generic Phy framework.
+ *
+ * Copyright (C) 2013 Texas Instruments
+ *
+ * Author: Kishon Vijay Abraham I <kishon@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/phy/phy.h>
+
+static struct class *phy_class;
+static LIST_HEAD(phy_list);
+static DEFINE_MUTEX(phy_list_mutex);
+static LIST_HEAD(phy_bind_list);
+
+static void devm_phy_release(struct device *dev, void *res)
+{
+ struct phy *phy = *(struct phy **)res;
+
+ phy_put(phy);
+}
+
+static void devm_phy_consume(struct device *dev, void *res)
+{
+ struct phy *phy = *(struct phy **)res;
+
+ phy_destroy(phy);
+}
+
+static int devm_phy_match(struct device *dev, void *res, void *match_data)
+{
+ return res == match_data;
+}
+
+static struct phy *phy_lookup(struct device *dev, u8 index)
+{
+ struct phy_bind *phy_bind = NULL;
+
+ list_for_each_entry(phy_bind, &phy_bind_list, list) {
+ if (!(strcmp(phy_bind->dev_name, dev_name(dev)) &&
+ phy_bind->index == index)) {
+ if (phy_bind->phy)
+ return phy_bind->phy;
+ else
+ return ERR_PTR(-EPROBE_DEFER);
+ }
+ }
+
+ return ERR_PTR(-ENODEV);
+}
+
+static struct phy *of_phy_lookup(struct device *dev, struct device_node *node)
+{
+ struct phy *phy;
+
+ list_for_each_entry(phy, &phy_list, head) {
+ if (node != phy->desc->of_node)
+ continue;
+
+ return phy;
+ }
+
+ return ERR_PTR(-EPROBE_DEFER);
+}
+
+/**
+ * phy_put - release the PHY
+ * @phy: the phy returned by phy_get()
+ *
+ * Releases a refcount the caller received from phy_get().
+ */
+void phy_put(struct phy *phy)
+{
+ if (phy) {
+ module_put(phy->desc->ops->owner);
+ put_device(&phy->dev);
+ }
+}
+EXPORT_SYMBOL_GPL(phy_put);
+
+/**
+ * devm_phy_put - release the PHY
+ * @dev: device that wants to release this phy
+ * @phy: the phy returned by devm_phy_get()
+ *
+ * destroys the devres associated with this phy and invokes phy_put
+ * to release the phy.
+ */
+void devm_phy_put(struct device *dev, struct phy *phy)
+{
+ int r;
+
+ r = devres_destroy(dev, devm_phy_release, devm_phy_match, phy);
+ dev_WARN_ONCE(dev, r, "couldn't find PHY resource\n");
+}
+EXPORT_SYMBOL_GPL(devm_phy_put);
+
+/**
+ * of_phy_get - lookup and obtain a reference to a phy by phandle
+ * @dev: device that requests this phy
+ * @phandle: name of the property holding the phy phandle value
+ * @index - the index of the phy
+ *
+ * Returns the phy associated with the given phandle value,
+ * after getting a refcount to it or -ENODEV if there is no such phy or
+ * -EPROBE_DEFER if there is a phandle to the phy, but the device is
+ * not yet loaded.
+ */
+struct phy *of_phy_get(struct device *dev, const char *phandle, u8 index)
+{
+ struct phy *phy = NULL;
+ struct phy_bind *phy_map = NULL;
+ struct device_node *node;
+
+ if (!dev->of_node) {
+ dev_dbg(dev, "device does not have a device node entry\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ node = of_parse_phandle(dev->of_node, phandle, index);
+ if (!node) {
+ dev_dbg(dev, "failed to get %s phandle in %s node\n", phandle,
+ dev->of_node->full_name);
+ return ERR_PTR(-ENODEV);
+ }
+
+ mutex_lock(&phy_list_mutex);
+
+ phy = of_phy_lookup(dev, node);
+ if (IS_ERR(phy) || !try_module_get(phy->desc->ops->owner)) {
+ phy = ERR_PTR(-EPROBE_DEFER);
+ goto err0;
+ }
+
+ phy_map = phy_bind(dev_name(dev), index, dev_name(&phy->dev));
+ if (!IS_ERR(phy_map)) {
+ phy_map->phy = phy;
+ phy_map->auto_bind = true;
+ }
+
+ get_device(&phy->dev);
+
+err0:
+ mutex_unlock(&phy_list_mutex);
+ of_node_put(node);
+
+ return phy;
+}
+EXPORT_SYMBOL_GPL(of_phy_get);
+
+/**
+ * devm_of_phy_get - lookup and obtain a reference to a phy by phandle
+ * @dev: device that requests this phy
+ * @phandle: name of the property holding the phy phandle value
+ * @index - the index of the phy
+ *
+ * Calls of_phy_get to get a reference to the PHY and passes on the return
+ * value of of_phy_get. While at that, it also associates the device with the
+ * phy using devres on successful phy get. On driver detach, release function
+ * is invoked on the the devres data and devres data is freed.
+ */
+struct phy *devm_of_phy_get(struct device *dev, const char *phandle, u8 index)
+{
+ struct phy *phy = NULL, **ptr;
+
+ ptr = devres_alloc(devm_phy_release, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return ERR_PTR(-ENOMEM);
+
+ phy = of_phy_get(dev, phandle, index);
+ if (!IS_ERR(phy)) {
+ *ptr = phy;
+ devres_add(dev, ptr);
+ } else {
+ devres_free(ptr);
+ }
+
+ return phy;
+}
+EXPORT_SYMBOL_GPL(devm_of_phy_get);
+
+/**
+ * phy_get - lookup and obtain a reference to a phy.
+ * @dev: device that requests this phy
+ * @index: the index of the phy
+ *
+ * Returns the phy driver, after getting a refcount to it; or
+ * -ENODEV if there is no such phy. The caller is responsible for
+ * calling phy_put() to release that count.
+ */
+struct phy *phy_get(struct device *dev, u8 index)
+{
+ struct phy *phy = NULL;
+
+ mutex_lock(&phy_list_mutex);
+
+ phy = phy_lookup(dev, index);
+ if (IS_ERR(phy)) {
+ dev_err(dev, "unable to find phy\n");
+ goto err0;
+ }
+
+ if (!try_module_get(phy->desc->ops->owner)) {
+ phy = ERR_PTR(-EPROBE_DEFER);
+ goto err0;
+ }
+
+ get_device(&phy->dev);
+
+err0:
+ mutex_unlock(&phy_list_mutex);
+
+ return phy;
+}
+EXPORT_SYMBOL_GPL(phy_get);
+
+/**
+ * devm_phy_get - lookup and obtain a reference to a phy.
+ * @dev: device that requests this phy
+ * @index: the index of the phy
+ *
+ * Gets the phy using phy_get(), and associates a device with it using
+ * devres. On driver detach, release function is invoked on the devres data,
+ * then, devres data is freed.
+ */
+struct phy *devm_phy_get(struct device *dev, u8 index)
+{
+ struct phy **ptr, *phy;
+
+ ptr = devres_alloc(devm_phy_release, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return ERR_PTR(-ENOMEM);
+
+ phy = phy_get(dev, index);
+ if (!IS_ERR(phy)) {
+ *ptr = phy;
+ devres_add(dev, ptr);
+ } else {
+ devres_free(ptr);
+ }
+
+ return phy;
+}
+EXPORT_SYMBOL_GPL(devm_phy_get);
+
+/**
+ * phy_create - create a new phy
+ * @dev: device that is creating the new phy
+ * @desc: descriptor of the phy
+ *
+ * Called to create a phy using phy framework.
+ */
+struct phy *phy_create(struct device *dev, struct phy_descriptor *desc)
+{
+ int ret;
+ struct phy *phy;
+ struct phy_bind *phy_bind;
+ const char *devname = NULL;
+
+ if (!dev || !desc) {
+ dev_err(dev, "no descriptor/device provided for PHY\n");
+ ret = -EINVAL;
+ goto err0;
+ }
+
+ if (!(desc->ops)) {
+ dev_err(dev, "no PHY ops/PHY owner provided\n");
+ ret = -EINVAL;
+ goto err0;
+ }
+
+ phy = kzalloc(sizeof(*phy), GFP_KERNEL);
+ if (!phy) {
+ ret = -ENOMEM;
+ goto err0;
+ }
+
+ devname = dev_name(dev);
+ device_initialize(&phy->dev);
+ phy->desc = desc;
+ phy->dev.class = phy_class;
+ phy->dev.parent = dev;
+ phy->dev.bus = desc->bus;
+ ret = dev_set_name(&phy->dev, "%s", devname);
+ if (ret)
+ goto err1;
+
+ mutex_lock(&phy_list_mutex);
+ list_for_each_entry(phy_bind, &phy_bind_list, list)
+ if (!(strcmp(phy_bind->phy_dev_name, devname)))
+ phy_bind->phy = phy;
+
+ list_add_tail(&phy->head, &phy_list);
+
+ ret = device_add(&phy->dev);
+ if (ret)
+ goto err2;
+
+ mutex_unlock(&phy_list_mutex);
+
+ return phy;
+
+err2:
+ phy_bind->phy = NULL;
+ list_del(&phy->head);
+ mutex_unlock(&phy_list_mutex);
+
+err1:
+ put_device(&phy->dev);
+ kfree(phy);
+
+err0:
+ return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(phy_create);
+
+/**
+ * devm_phy_create - create a new phy
+ * @dev: device that is creating the new phy
+ * @desc: descriptor of the phy
+ *
+ * Creates a new PHY device adding it to the PHY class.
+ * While at that, it also associates the device with the phy using devres.
+ * On driver detach, release function is invoked on the devres data,
+ * then, devres data is freed.
+ */
+struct phy *devm_phy_create(struct device *dev, struct phy_descriptor *desc)
+{
+ struct phy **ptr, *phy;
+
+ ptr = devres_alloc(devm_phy_consume, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return ERR_PTR(-ENOMEM);
+
+ phy = phy_create(dev, desc);
+ if (!IS_ERR(phy)) {
+ *ptr = phy;
+ devres_add(dev, ptr);
+ } else {
+ devres_free(ptr);
+ }
+
+ return phy;
+}
+EXPORT_SYMBOL_GPL(devm_phy_create);
+
+/**
+ * phy_destroy - destroy the phy
+ * @phy: the phy to be destroyed
+ *
+ * Called to destroy the phy.
+ */
+void phy_destroy(struct phy *phy)
+{
+ struct phy_bind *phy_bind;
+
+ mutex_lock(&phy_list_mutex);
+ list_for_each_entry(phy_bind, &phy_bind_list, list) {
+ if (phy_bind->phy == phy)
+ phy_bind->phy = NULL;
+
+ if (phy_bind->auto_bind) {
+ list_del(&phy_bind->list);
+ kfree(phy_bind);
+ }
+ }
+
+ list_del(&phy->head);
+ mutex_unlock(&phy_list_mutex);
+
+ device_unregister(&phy->dev);
+}
+EXPORT_SYMBOL_GPL(phy_destroy);
+
+/**
+ * devm_phy_destroy - destroy the PHY
+ * @dev: device that wants to release this phy
+ * @phy: the phy returned by devm_phy_get()
+ *
+ * destroys the devres associated with this phy and invokes phy_destroy
+ * to destroy the phy.
+ */
+void devm_phy_destroy(struct device *dev, struct phy *phy)
+{
+ int r;
+
+ r = devres_destroy(dev, devm_phy_consume, devm_phy_match, phy);
+ dev_WARN_ONCE(dev, r, "couldn't find PHY resource\n");
+}
+EXPORT_SYMBOL_GPL(devm_phy_destroy);
+
+/**
+ * phy_bind - bind the phy and the controller that uses the phy
+ * @dev_name: the device name of the device that will bind to the phy
+ * @index: index to specify the port number
+ * @phy_dev_name: the device name of the phy
+ *
+ * Fills the phy_bind structure with the dev_name and phy_dev_name. This will
+ * be used when the phy driver registers the phy and when the controller
+ * requests this phy.
+ *
+ * To be used by platform specific initialization code.
+ */
+struct phy_bind *phy_bind(const char *dev_name, u8 index,
+ const char *phy_dev_name)
+{
+ struct phy_bind *phy_bind;
+
+ phy_bind = kzalloc(sizeof(*phy_bind), GFP_KERNEL);
+ if (!phy_bind)
+ return ERR_PTR(-ENOMEM);
+
+ phy_bind->dev_name = dev_name;
+ phy_bind->phy_dev_name = phy_dev_name;
+ phy_bind->index = index;
+ phy_bind->auto_bind = false;
+
+ list_add_tail(&phy_bind->list, &phy_bind_list);
+
+ return phy_bind;
+}
+EXPORT_SYMBOL_GPL(phy_bind);
+
+static ssize_t phy_name_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct phy *phy;
+
+ phy = container_of(dev, struct phy, dev);
+
+ return sprintf(buf, "%s\n", phy->desc->label);
+}
+
+static ssize_t phy_bind_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct phy_bind *phy_bind;
+ struct phy *phy;
+ char *p = buf;
+ int len;
+
+ phy = container_of(dev, struct phy, dev);
+
+ list_for_each_entry(phy_bind, &phy_bind_list, list)
+ if (phy_bind->phy == phy)
+ p += sprintf(p, "%s %d %s\n", phy_bind->dev_name,
+ phy_bind->index, phy_bind->phy_dev_name);
+ len = (p - buf);
+
+ return len;
+}
+
+static struct device_attribute phy_dev_attrs[] = {
+ __ATTR(label, 0444, phy_name_show, NULL),
+ __ATTR(bind, 0444, phy_bind_show, NULL),
+ __ATTR_NULL,
+};
+
+/**
+ * phy_release - release the phy
+ * @dev: the dev member within phy
+ *
+ * when the last reference to the device is removed; it is called
+ * from the embedded kobject as release method.
+ */
+static void phy_release(struct device *dev)
+{
+ struct phy *phy;
+
+ phy = container_of(dev, struct phy, dev);
+ dev_dbg(dev, "releasing '%s'\n", dev_name(dev));
+ kfree(phy);
+}
+
+static int __init phy_core_init(void)
+{
+ phy_class = class_create(THIS_MODULE, "phy");
+ if (IS_ERR(phy_class)) {
+ pr_err("failed to create phy class --> %ld\n",
+ PTR_ERR(phy_class));
+ return PTR_ERR(phy_class);
+ }
+
+ phy_class->dev_release = phy_release;
+ phy_class->dev_attrs = phy_dev_attrs;
+
+ return 0;
+}
+subsys_initcall(phy_core_init);
+
+static void __exit phy_core_exit(void)
+{
+ class_destroy(phy_class);
+}
+module_exit(phy_core_exit);
+
+MODULE_DESCRIPTION("Generic PHY Framework");
+MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h
new file mode 100644
index 0000000..4e9076d
--- /dev/null
+++ b/include/linux/phy/phy.h
@@ -0,0 +1,198 @@
+/*
+ * phy.h -- generic phy header file
+ *
+ * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Author: Kishon Vijay Abraham I <kishon@ti.com>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __DRIVERS_PHY_H
+#define __DRIVERS_PHY_H
+
+#include <linux/err.h>
+
+struct phy;
+
+/**
+ * struct phy_descriptor - structure that describes the PHY
+ * @label: label given to phy
+ * @type: specifies the phy type
+ * @of_node: device node of the phy
+ * @ops: function pointers for performing phy operations
+ */
+struct phy_descriptor {
+ const char *label;
+ int type;
+ struct bus_type *bus;
+ struct device_node *of_node;
+ struct phy_ops *ops;
+};
+
+/**
+ * struct phy_ops - set of function pointers for performing phy operations
+ * @init: operation to be performed for initializing phy
+ * @exit: operation to be performed while exiting
+ * @suspend: suspending the phy
+ * @resume: resuming the phy
+ * @poweron: powering on the phy
+ * @shutdown: shutting down the phy
+ * @owner: the module owner containing the ops
+ */
+struct phy_ops {
+ int (*init)(struct phy_descriptor *desc);
+ int (*exit)(struct phy_descriptor *desc);
+ int (*suspend)(struct phy_descriptor *desc);
+ int (*resume)(struct phy_descriptor *desc);
+ int (*poweron)(struct phy_descriptor *desc);
+ int (*shutdown)(struct phy_descriptor *desc);
+ struct module *owner;
+};
+
+/**
+ * struct phy - represent the phy device
+ * @desc: descriptor for the phy
+ * @head: to support multiple transceivers
+ */
+struct phy {
+ struct device dev;
+ struct phy_descriptor *desc;
+ struct list_head head;
+};
+
+/**
+ * struct phy_bind - represent the binding for the phy
+ * @dev_name: the device name of the device that will bind to the phy
+ * @phy_dev_name: the device name of the phy
+ * @index: used if a single controller uses multiple phys
+ * @auto_bind: tells if the binding is done explicitly from board file or not
+ * @phy: reference to the phy
+ * @list: to maintain a linked list of the binding information
+ */
+struct phy_bind {
+ const char *dev_name;
+ const char *phy_dev_name;
+ u8 index;
+ int auto_bind:1;
+ struct phy *phy;
+ struct list_head list;
+};
+
+#if defined(CONFIG_GENERIC_PHY) || defined(CONFIG_GENERIC_PHY_MODULE)
+extern struct phy *devm_phy_get(struct device *dev, u8 index);
+extern void devm_phy_put(struct device *dev, struct phy *phy);
+extern struct phy *devm_of_phy_get(struct device *dev, const char *phandle,
+ u8 index);
+extern struct phy *phy_get(struct device *dev, u8 index);
+extern void phy_put(struct phy *phy);
+extern struct phy *phy_create(struct device *dev, struct phy_descriptor *desc);
+extern struct phy *devm_phy_create(struct device *dev,
+ struct phy_descriptor *desc);
+extern void phy_destroy(struct phy *phy);
+extern struct phy_bind *phy_bind(const char *dev_name, u8 index,
+ const char *phy_dev_name);
+#else
+static inline struct phy *devm_phy_get(struct device *dev, u8 index)
+{
+ return ERR_PTR(-EINVAL);
+}
+
+static inline void devm_phy_put(struct device *dev, struct phy *phy)
+{
+}
+
+static inline struct phy *devm_of_phy_get(struct device *dev,
+ const char *phandlei, u8 index)
+{
+ return ERR_PTR(-EINVAL);
+}
+
+static inline struct phy *phy_get(struct device *dev, u8 index)
+{
+ return ERR_PTR(-EINVAL);
+}
+
+static inline void phy_put(struct phy *phy)
+{
+}
+
+static inline struct phy *phy_create(struct device *dev,
+ struct phy_descriptor *desc)
+{
+ return ERR_PTR(-EINVAL);
+}
+
+static inline struct phy *devm_phy_create(struct device *dev,
+ struct phy_descriptor *desc)
+{
+ return ERR_PTR(-EINVAL);
+}
+
+static inline void phy_destroy(struct phy *phy)
+{
+}
+
+static inline struct phy_bind *phy_bind(const char *dev_name, u8 index,
+ const char *phy_dev_name)
+{
+ return ERR_PTR(-EINVAL);
+}
+#endif
+
+static inline int phy_init(struct phy *phy)
+{
+ if (phy->desc->ops->init)
+ return phy->desc->ops->init(phy->desc);
+
+ return -EINVAL;
+}
+
+static inline int phy_exit(struct phy *phy)
+{
+ if (phy->desc->ops->exit)
+ return phy->desc->ops->exit(phy->desc);
+
+ return -EINVAL;
+}
+
+static inline int phy_suspend(struct phy *phy)
+{
+ if (phy->desc->ops->suspend)
+ return phy->desc->ops->suspend(phy->desc);
+
+ return -EINVAL;
+}
+
+static inline int phy_resume(struct phy *phy)
+{
+ if (phy->desc->ops->resume)
+ return phy->desc->ops->resume(phy->desc);
+
+ return -EINVAL;
+}
+
+static inline int phy_poweron(struct phy *phy)
+{
+ if (phy->desc->ops->poweron)
+ return phy->desc->ops->poweron(phy->desc);
+
+ return -EINVAL;
+}
+
+static inline int phy_shutdown(struct phy *phy)
+{
+ if (phy->desc->ops->shutdown)
+ return phy->desc->ops->shutdown(phy->desc);
+
+ return -EINVAL;
+}
+#endif /* __DRIVERS_PHY_H */
--
1.7.10.4
^ permalink raw reply related
* [PATCH v2 0/5] Generic PHY Framework
From: Kishon Vijay Abraham I @ 2013-02-19 5:53 UTC (permalink / raw)
To: rob, tony, linux, eballetbo, javier, kishon, balbi, gregkh, akpm,
mchehab, cesarb, davem, arnd, santosh.shilimkar, broonie, swarren,
linux-doc, linux-kernel, linux-arm-kernel, linux-omap, linux-usb,
netdev
Added a generic PHY framework that provides a set of APIs for the PHY drivers
to create/destroy a PHY and APIs for the PHY users to obtain a reference to
the PHY with or without using phandle. To obtain a reference to the PHY
without using phandle, the platform specfic intialization code (say from board
file) should have already called phy_bind with the binding information. The
binding information consists of phy's device name, phy user device name and an
index. The index is used when the same phy user binds to mulitple phys.
This framework will be of use only to devices that uses external PHY (PHY
functionality is not embedded within the controller).
The intention of creating this framework is to bring the phy drivers spread
all over the Linux kernel to drivers/phy to increase code re-use and to
increase code maintainability.
Comments to make PHY as bus wasn't done because PHY devices can be part of
other bus and making a same device attached to multiple bus leads to bad
design.
Changes from v1:
* Added Documentation for the PHY framework
* Added few more APIs mostly w.r.t devres
* Modified omap-usb2 and twl4030 to make use of the new framework
Did USB enumeration testing in panda and beagle.
Kishon Vijay Abraham I (5):
drivers: phy: add generic PHY framework
usb: phy: omap-usb2: use the new generic PHY framework
usb: otg: twl4030: use the new generic PHY framework
ARM: OMAP: USB: Add phy binding information
usb: musb: omap2430: use the new generic PHY framework
Documentation/ABI/testing/sysfs-class-phy | 15 +
Documentation/phy.txt | 113 ++++++
MAINTAINERS | 7 +
arch/arm/mach-omap2/board-2430sdp.c | 2 +
arch/arm/mach-omap2/board-3430sdp.c | 2 +
arch/arm/mach-omap2/board-4430sdp.c | 2 +
arch/arm/mach-omap2/board-cm-t35.c | 2 +
arch/arm/mach-omap2/board-devkit8000.c | 2 +
arch/arm/mach-omap2/board-igep0020.c | 2 +
arch/arm/mach-omap2/board-ldp.c | 2 +
arch/arm/mach-omap2/board-omap3beagle.c | 2 +
arch/arm/mach-omap2/board-omap3evm.c | 2 +
arch/arm/mach-omap2/board-omap3logic.c | 2 +
arch/arm/mach-omap2/board-omap3pandora.c | 2 +
arch/arm/mach-omap2/board-omap3stalker.c | 2 +
arch/arm/mach-omap2/board-omap3touchbook.c | 2 +
arch/arm/mach-omap2/board-omap4panda.c | 2 +
arch/arm/mach-omap2/board-overo.c | 2 +
arch/arm/mach-omap2/board-rm680.c | 2 +
arch/arm/mach-omap2/board-zoom-peripherals.c | 2 +
drivers/Kconfig | 2 +
drivers/Makefile | 2 +
drivers/phy/Kconfig | 13 +
drivers/phy/Makefile | 5 +
drivers/phy/phy-core.c | 519 ++++++++++++++++++++++++++
drivers/usb/musb/musb_core.h | 2 +
drivers/usb/musb/omap2430.c | 22 +-
drivers/usb/otg/twl4030-usb.c | 41 ++
drivers/usb/phy/omap-usb2.c | 49 +++
include/linux/phy/phy.h | 198 ++++++++++
include/linux/usb/omap_usb.h | 3 +
31 files changed, 1019 insertions(+), 6 deletions(-)
create mode 100644 Documentation/ABI/testing/sysfs-class-phy
create mode 100644 Documentation/phy.txt
create mode 100644 drivers/phy/Kconfig
create mode 100644 drivers/phy/Makefile
create mode 100644 drivers/phy/phy-core.c
create mode 100644 include/linux/phy/phy.h
--
1.7.10.4
^ permalink raw reply
* Re: [PATCH net-next v2 3/3] bonding: fix bond_release_all inconsistencies
From: David Miller @ 2013-02-19 5:53 UTC (permalink / raw)
To: fubar; +Cc: nikolay, netdev, andy
In-Reply-To: <29485.1361243521@death.nxdomain>
From: Jay Vosburgh <fubar@us.ibm.com>
Date: Mon, 18 Feb 2013 19:12:01 -0800
> Nikolay Aleksandrov <nikolay@redhat.com> wrote:
>
>>This patch fixes the following inconsistencies in bond_release_all:
>>- IFF_BONDING flag is not stripped from slaves
>>- MTU is not restored
>>- no netdev notifiers are sent
>>Instead of trying to keep bond_release and bond_release_all in sync
>>I think we can re-use bond_release as the environment for calling it
>>is correct (RTNL is held). I have been running tests for the past
>>week and they came out successful. The only way for bond_release to fail
>>is for the slave to be attached in a different bond or to not be a slave
>>but that cannot happen as RTNL is held and no slave manipulations can be
>>achieved.
>>
>>V2: As suggested bond_release is renamed to __bond_release_one with a
>>new parameter "all" introduced so to avoid calling unnecessary code while
>>destroying a bond, and a wrapper for it called bond_release is created
>>because of ndo_del_link. bond_release_all() is removed.
>>
>>Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com>
>
> Signed-off-by: Jay Vosburgh <fubar@us.ibm.com>
Applied.
^ permalink raw reply
* Re: [PATCH net 2/3] bonding: Fix initialize after use for 3ad machine state spinlock
From: David Miller @ 2013-02-19 5:52 UTC (permalink / raw)
To: fubar; +Cc: nikolay, netdev, andy
In-Reply-To: <21258.1361223190@death.nxdomain>
From: Jay Vosburgh <fubar@us.ibm.com>
Date: Mon, 18 Feb 2013 13:33:10 -0800
> Nikolay Aleksandrov <nikolay@redhat.com> wrote:
>
>>The 3ad machine state spinlock can be used before it is inititialized
>>while doing bond_enslave() (and the port is being initialized) since
>>port->slave is set before the lock is prepared, thus causing soft
>>lock-ups and a multitude of other nasty bugs.
>
> Does this change cause the "uninitialized port" warnings in
> bond_3ad_state_machine_handler and bond_3ad_rx_indication to
> intermittently print during the enslavement process? If so (and it
> looks to me like it will), I think the warnings should be removed, since
> after this change, port->slave being NULL isn't really an error
> condition that needs a warning to the log.
>
>>Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com>
...
>>-static inline void __initialize_port_locks(struct port *port)
>>+static inline void __initialize_port_locks(struct slave *port)
>> {
>> // make sure it isn't called twice
>>- spin_lock_init(&(SLAVE_AD_INFO(port->slave).state_machine_lock));
>>+ spin_lock_init(&(SLAVE_AD_INFO(port).state_machine_lock));
>
> Change the name of the variable here, too, not just the type.
> This is confusing.
I made this adjustment and applied Nikolay's patch.
^ permalink raw reply
* Re: [PATCH net 1/3] bonding: Fix race condition between bond_enslave() and bond_3ad_update_lacp_rate()
From: David Miller @ 2013-02-19 5:52 UTC (permalink / raw)
To: fubar; +Cc: nikolay, netdev, andy
In-Reply-To: <21028.1361221753@death.nxdomain>
From: Jay Vosburgh <fubar@us.ibm.com>
Date: Mon, 18 Feb 2013 13:09:13 -0800
> Nikolay Aleksandrov <nikolay@redhat.com> wrote:
>
>>port->slave can be NULL since it's being initialized in bond_enslave
>>thus dereferencing a NULL pointer in bond_3ad_update_lacp_rate()
>>Also fix a minor bug, which could cause a port not to have
>>AD_STATE_LACP_TIMEOUT since there's no sync between
>>bond_3ad_update_lacp_rate() and bond_3ad_bind_slave(), by changing
>>the read_lock to a write_lock_bh in bond_3ad_update_lacp_rate().
>
> Signed-off-by: Jay Vosburgh <fubar@us.ibm.com>
>
>>Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com>
Applied
^ permalink raw reply
* Re: [PATCH] b43: Increase number of RX DMA slots
From: David Miller @ 2013-02-19 5:52 UTC (permalink / raw)
To: Larry.Finger-tQ5ms3gMjBLk1uMJSBkQmQ
Cc: linville-2XuSBdqkA4R54TAoqtyWWQ,
linux-wireless-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA, bittorf-yxHw+vPQXZDZJqsBc5GL+g,
stable-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1361156480-32566-1-git-send-email-Larry.Finger-tQ5ms3gMjBLk1uMJSBkQmQ@public.gmane.org>
From: Larry Finger <Larry.Finger-tQ5ms3gMjBLk1uMJSBkQmQ@public.gmane.org>
Date: Sun, 17 Feb 2013 21:01:20 -0600
> Bastian Bittorf reported that some of the silent freezes on a Linksys WRT54G
> were due to overflow of the RX DMA ring buffer, which was created with 64
> slots. That finding reminded me that I was seeing similar crashed on a netbook,
> which also has a relatively slow processor. After increasing the number of
> slots to 128, runs on the netbook that previously failed now worked; however,
> I found that 109 slots had been used in one test. For that reason, the number
> of slots is being increased to 256.
>
> Signed-off-by: Larry Finger <Larry.Finger-tQ5ms3gMjBLk1uMJSBkQmQ@public.gmane.org>
Applied.
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH 0/7] netfilter updates for net-next
From: David Miller @ 2013-02-19 5:44 UTC (permalink / raw)
To: pablo; +Cc: netdev, netfilter-devel
In-Reply-To: <1361232651-5626-1-git-send-email-pablo@netfilter.org>
From: pablo@netfilter.org
Date: Tue, 19 Feb 2013 01:10:44 +0100
> The following patchset contain updates for your net-next tree, they are:
>
> * Fix (for just added) connlabel dependencies, from Florian Westphal.
>
> * Add aliasing support for conntrack, thus users can either use -m state
> or -m conntrack from iptables while using the same kernel module, from
> Jozsef Kadlecsik.
>
> * Some code refactoring for the CT target to merge common code in
> revision 0 and 1, from myself.
>
> * Add aliasing support for CT, based on patch from Jozsef Kadlecsik.
>
> * Add one mutex per nfnetlink subsystem, from myself.
>
> * Improved logging for packets that are dropped by helpers, from myself.
Pulled, thanks Pablo.
^ permalink raw reply
* Re: 3.7.8/amd64 full interrupt hangs due to iwlwifi under big nfs copies out
From: Marc MERLIN @ 2013-02-19 5:26 UTC (permalink / raw)
To: Eric Dumazet
Cc: David Miller, Larry.Finger, bhutchings, linux-wireless, netdev
In-Reply-To: <1361251033.19353.120.camel@edumazet-glaptop>
On Mon, Feb 18, 2013 at 09:17:13PM -0800, Eric Dumazet wrote:
> > chrome: page allocation failure: order:1, mode:0x4020
> > Pid: 8730, comm: chrome Tainted: G O 3.7.8-amd64-preempt-20121226-fixwd #1
> > Call Trace:
> > <IRQ> [<ffffffff810d5f38>] warn_alloc_failed+0x117/0x12c
> > [<ffffffff810d8cfd>] __alloc_pages_nodemask+0x66a/0x702
> > [<ffffffff8108a948>] ? arch_local_irq_save+0x15/0x1b
> > [<ffffffff811064af>] alloc_pages_current+0xcd/0xee
> > [<ffffffffa039b579>] iwl_rx_allocate+0x8c/0x271 [iwlwifi]
> > [<ffffffffa039c24e>] iwl_irq_tasklet+0x7e5/0x91c [iwlwifi]
> > [<ffffffff8104805e>] tasklet_action+0x80/0xd2
> > [<ffffffff81047c99>] __do_softirq+0xdf/0x1c5
> > [<ffffffff814c1ed6>] ? _raw_spin_lock+0x1b/0x1f
> > [<ffffffff810a7f37>] ? handle_irq_event+0x4d/0x62
> > [<ffffffff814c7f5c>] call_softirq+0x1c/0x30
> > [<ffffffff8101104e>] do_softirq+0x41/0x7f
> > [<ffffffff81047e52>] irq_exit+0x3f/0xa7
> > [<ffffffff81010d40>] do_IRQ+0x88/0x9f
> > [<ffffffff814c246d>] common_interrupt+0x6d/0x6d
> > <EOI> Mem-Info:
>
> You could try to load iwlwifi with amsdu_size_8K set to 0 (disable)
>
> It should hopefully use order-0 pages
>
> Some drivers cant fallback to low order page allocations.
>
> mlx4 is another example (it uses order-2 pages )
Well, now that I changed NFS to 32K buffering, I won't have the problem
anyway, so the problem is effectively fixed enough for me.
But because the default behaviour is so bad, I wanted to help fix the
defaults so that it doesn't happen to others if possible.
I haven't been following the NFS world recently, so I don't know if the code
is known broken beyond fixing, or if I did find an unusual problem that is
worth looking into.
If somehow I'm the only one, then let's not worry about it :)
Marc
--
"A mouse is a device used to point at the xterm you want to type in" - A.S.R.
Microsoft is to operating systems ....
.... what McDonalds is to gourmet cooking
Home page: http://marc.merlins.org/
^ permalink raw reply
* Re: [PATCH] net: move procfs code to net/core/net-procfs.c
From: Cong Wang @ 2013-02-19 5:24 UTC (permalink / raw)
To: Cong Wang; +Cc: netdev, David S. Miller
In-Reply-To: <1361251233-25914-1-git-send-email-xiyou.wangcong@gmail.com>
On 02/19/2013 01:20 PM, Cong Wang wrote:
> From: Cong Wang <xiyou.wangcong@gmail.com>
>
> Similar to net/core/net-sysfs.c, group procfs code to
> a single unit.
>
> Cc: "David S. Miller" <davem@davemloft.net>
> Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
This is for net-next, sorry for missing it in $subject.
^ permalink raw reply
* [PATCH] net: move procfs code to net/core/net-procfs.c
From: Cong Wang @ 2013-02-19 5:20 UTC (permalink / raw)
To: netdev; +Cc: David S. Miller, Cong Wang
From: Cong Wang <xiyou.wangcong@gmail.com>
Similar to net/core/net-sysfs.c, group procfs code to
a single unit.
Cc: "David S. Miller" <davem@davemloft.net>
Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
---
include/linux/netdevice.h | 36 ++++-
net/core/Makefile | 1 +
net/core/dev.c | 384 +-----------------------------------------
net/core/dev_addr_lists.c | 74 --------
net/core/net-procfs.c | 414 +++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 450 insertions(+), 459 deletions(-)
create mode 100644 net/core/net-procfs.c
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 920361b..f111b4f 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2692,9 +2692,9 @@ extern void net_enable_timestamp(void);
extern void net_disable_timestamp(void);
#ifdef CONFIG_PROC_FS
-extern void *dev_seq_start(struct seq_file *seq, loff_t *pos);
-extern void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos);
-extern void dev_seq_stop(struct seq_file *seq, void *v);
+extern int __init dev_proc_init(void);
+#else
+#define dev_proc_init() 0
#endif
extern int netdev_class_create_file(struct class_attribute *class_attr);
@@ -2896,4 +2896,34 @@ do { \
})
#endif
+/*
+ * The list of packet types we will receive (as opposed to discard)
+ * and the routines to invoke.
+ *
+ * Why 16. Because with 16 the only overlap we get on a hash of the
+ * low nibble of the protocol value is RARP/SNAP/X.25.
+ *
+ * NOTE: That is no longer true with the addition of VLAN tags. Not
+ * sure which should go first, but I bet it won't make much
+ * difference if we are running VLANs. The good news is that
+ * this protocol won't be in the list unless compiled in, so
+ * the average user (w/out VLANs) will not be adversely affected.
+ * --BLG
+ *
+ * 0800 IP
+ * 8100 802.1Q VLAN
+ * 0001 802.3
+ * 0002 AX.25
+ * 0004 802.2
+ * 8035 RARP
+ * 0005 SNAP
+ * 0805 X.25
+ * 0806 ARP
+ * 8137 IPX
+ * 0009 Localtalk
+ * 86DD IPv6
+ */
+#define PTYPE_HASH_SIZE (16)
+#define PTYPE_HASH_MASK (PTYPE_HASH_SIZE - 1)
+
#endif /* _LINUX_NETDEVICE_H */
diff --git a/net/core/Makefile b/net/core/Makefile
index 0c5e361..b33b996 100644
--- a/net/core/Makefile
+++ b/net/core/Makefile
@@ -13,6 +13,7 @@ obj-y += dev.o ethtool.o dev_addr_lists.o dst.o netevent.o \
obj-$(CONFIG_XFRM) += flow.o
obj-y += net-sysfs.o
+obj-$(CONFIG_PROC_FS) += net-procfs.o
obj-$(CONFIG_NET_PKTGEN) += pktgen.o
obj-$(CONFIG_NETPOLL) += netpoll.o
obj-$(CONFIG_NET_DMA) += user_dma.o
diff --git a/net/core/dev.c b/net/core/dev.c
index decf55f..8d9ddb0 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -97,8 +97,6 @@
#include <net/net_namespace.h>
#include <net/sock.h>
#include <linux/rtnetlink.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
#include <linux/stat.h>
#include <net/dst.h>
#include <net/pkt_sched.h>
@@ -110,7 +108,6 @@
#include <linux/netpoll.h>
#include <linux/rcupdate.h>
#include <linux/delay.h>
-#include <net/wext.h>
#include <net/iw_handler.h>
#include <asm/current.h>
#include <linux/audit.h>
@@ -141,41 +138,10 @@
/* This should be increased if a protocol with a bigger head is added. */
#define GRO_MAX_HEAD (MAX_HEADER + 128)
-/*
- * The list of packet types we will receive (as opposed to discard)
- * and the routines to invoke.
- *
- * Why 16. Because with 16 the only overlap we get on a hash of the
- * low nibble of the protocol value is RARP/SNAP/X.25.
- *
- * NOTE: That is no longer true with the addition of VLAN tags. Not
- * sure which should go first, but I bet it won't make much
- * difference if we are running VLANs. The good news is that
- * this protocol won't be in the list unless compiled in, so
- * the average user (w/out VLANs) will not be adversely affected.
- * --BLG
- *
- * 0800 IP
- * 8100 802.1Q VLAN
- * 0001 802.3
- * 0002 AX.25
- * 0004 802.2
- * 8035 RARP
- * 0005 SNAP
- * 0805 X.25
- * 0806 ARP
- * 8137 IPX
- * 0009 Localtalk
- * 86DD IPv6
- */
-
-#define PTYPE_HASH_SIZE (16)
-#define PTYPE_HASH_MASK (PTYPE_HASH_SIZE - 1)
-
static DEFINE_SPINLOCK(ptype_lock);
static DEFINE_SPINLOCK(offload_lock);
-static struct list_head ptype_base[PTYPE_HASH_SIZE] __read_mostly;
-static struct list_head ptype_all __read_mostly; /* Taps */
+struct list_head ptype_base[PTYPE_HASH_SIZE] __read_mostly;
+struct list_head ptype_all __read_mostly; /* Taps */
static struct list_head offload_base __read_mostly;
/*
@@ -4217,352 +4183,6 @@ softnet_break:
goto out;
}
-#ifdef CONFIG_PROC_FS
-
-#define BUCKET_SPACE (32 - NETDEV_HASHBITS - 1)
-
-#define get_bucket(x) ((x) >> BUCKET_SPACE)
-#define get_offset(x) ((x) & ((1 << BUCKET_SPACE) - 1))
-#define set_bucket_offset(b, o) ((b) << BUCKET_SPACE | (o))
-
-static inline struct net_device *dev_from_same_bucket(struct seq_file *seq, loff_t *pos)
-{
- struct net *net = seq_file_net(seq);
- struct net_device *dev;
- struct hlist_node *p;
- struct hlist_head *h;
- unsigned int count = 0, offset = get_offset(*pos);
-
- h = &net->dev_name_head[get_bucket(*pos)];
- hlist_for_each_entry_rcu(dev, p, h, name_hlist) {
- if (++count == offset)
- return dev;
- }
-
- return NULL;
-}
-
-static inline struct net_device *dev_from_bucket(struct seq_file *seq, loff_t *pos)
-{
- struct net_device *dev;
- unsigned int bucket;
-
- do {
- dev = dev_from_same_bucket(seq, pos);
- if (dev)
- return dev;
-
- bucket = get_bucket(*pos) + 1;
- *pos = set_bucket_offset(bucket, 1);
- } while (bucket < NETDEV_HASHENTRIES);
-
- return NULL;
-}
-
-/*
- * This is invoked by the /proc filesystem handler to display a device
- * in detail.
- */
-void *dev_seq_start(struct seq_file *seq, loff_t *pos)
- __acquires(RCU)
-{
- rcu_read_lock();
- if (!*pos)
- return SEQ_START_TOKEN;
-
- if (get_bucket(*pos) >= NETDEV_HASHENTRIES)
- return NULL;
-
- return dev_from_bucket(seq, pos);
-}
-
-void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
-{
- ++*pos;
- return dev_from_bucket(seq, pos);
-}
-
-void dev_seq_stop(struct seq_file *seq, void *v)
- __releases(RCU)
-{
- rcu_read_unlock();
-}
-
-static void dev_seq_printf_stats(struct seq_file *seq, struct net_device *dev)
-{
- struct rtnl_link_stats64 temp;
- const struct rtnl_link_stats64 *stats = dev_get_stats(dev, &temp);
-
- seq_printf(seq, "%6s: %7llu %7llu %4llu %4llu %4llu %5llu %10llu %9llu "
- "%8llu %7llu %4llu %4llu %4llu %5llu %7llu %10llu\n",
- dev->name, stats->rx_bytes, stats->rx_packets,
- stats->rx_errors,
- stats->rx_dropped + stats->rx_missed_errors,
- stats->rx_fifo_errors,
- stats->rx_length_errors + stats->rx_over_errors +
- stats->rx_crc_errors + stats->rx_frame_errors,
- stats->rx_compressed, stats->multicast,
- stats->tx_bytes, stats->tx_packets,
- stats->tx_errors, stats->tx_dropped,
- stats->tx_fifo_errors, stats->collisions,
- stats->tx_carrier_errors +
- stats->tx_aborted_errors +
- stats->tx_window_errors +
- stats->tx_heartbeat_errors,
- stats->tx_compressed);
-}
-
-/*
- * Called from the PROCfs module. This now uses the new arbitrary sized
- * /proc/net interface to create /proc/net/dev
- */
-static int dev_seq_show(struct seq_file *seq, void *v)
-{
- if (v == SEQ_START_TOKEN)
- seq_puts(seq, "Inter-| Receive "
- " | Transmit\n"
- " face |bytes packets errs drop fifo frame "
- "compressed multicast|bytes packets errs "
- "drop fifo colls carrier compressed\n");
- else
- dev_seq_printf_stats(seq, v);
- return 0;
-}
-
-static struct softnet_data *softnet_get_online(loff_t *pos)
-{
- struct softnet_data *sd = NULL;
-
- while (*pos < nr_cpu_ids)
- if (cpu_online(*pos)) {
- sd = &per_cpu(softnet_data, *pos);
- break;
- } else
- ++*pos;
- return sd;
-}
-
-static void *softnet_seq_start(struct seq_file *seq, loff_t *pos)
-{
- return softnet_get_online(pos);
-}
-
-static void *softnet_seq_next(struct seq_file *seq, void *v, loff_t *pos)
-{
- ++*pos;
- return softnet_get_online(pos);
-}
-
-static void softnet_seq_stop(struct seq_file *seq, void *v)
-{
-}
-
-static int softnet_seq_show(struct seq_file *seq, void *v)
-{
- struct softnet_data *sd = v;
-
- seq_printf(seq, "%08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n",
- sd->processed, sd->dropped, sd->time_squeeze, 0,
- 0, 0, 0, 0, /* was fastroute */
- sd->cpu_collision, sd->received_rps);
- return 0;
-}
-
-static const struct seq_operations dev_seq_ops = {
- .start = dev_seq_start,
- .next = dev_seq_next,
- .stop = dev_seq_stop,
- .show = dev_seq_show,
-};
-
-static int dev_seq_open(struct inode *inode, struct file *file)
-{
- return seq_open_net(inode, file, &dev_seq_ops,
- sizeof(struct seq_net_private));
-}
-
-static const struct file_operations dev_seq_fops = {
- .owner = THIS_MODULE,
- .open = dev_seq_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release_net,
-};
-
-static const struct seq_operations softnet_seq_ops = {
- .start = softnet_seq_start,
- .next = softnet_seq_next,
- .stop = softnet_seq_stop,
- .show = softnet_seq_show,
-};
-
-static int softnet_seq_open(struct inode *inode, struct file *file)
-{
- return seq_open(file, &softnet_seq_ops);
-}
-
-static const struct file_operations softnet_seq_fops = {
- .owner = THIS_MODULE,
- .open = softnet_seq_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release,
-};
-
-static void *ptype_get_idx(loff_t pos)
-{
- struct packet_type *pt = NULL;
- loff_t i = 0;
- int t;
-
- list_for_each_entry_rcu(pt, &ptype_all, list) {
- if (i == pos)
- return pt;
- ++i;
- }
-
- for (t = 0; t < PTYPE_HASH_SIZE; t++) {
- list_for_each_entry_rcu(pt, &ptype_base[t], list) {
- if (i == pos)
- return pt;
- ++i;
- }
- }
- return NULL;
-}
-
-static void *ptype_seq_start(struct seq_file *seq, loff_t *pos)
- __acquires(RCU)
-{
- rcu_read_lock();
- return *pos ? ptype_get_idx(*pos - 1) : SEQ_START_TOKEN;
-}
-
-static void *ptype_seq_next(struct seq_file *seq, void *v, loff_t *pos)
-{
- struct packet_type *pt;
- struct list_head *nxt;
- int hash;
-
- ++*pos;
- if (v == SEQ_START_TOKEN)
- return ptype_get_idx(0);
-
- pt = v;
- nxt = pt->list.next;
- if (pt->type == htons(ETH_P_ALL)) {
- if (nxt != &ptype_all)
- goto found;
- hash = 0;
- nxt = ptype_base[0].next;
- } else
- hash = ntohs(pt->type) & PTYPE_HASH_MASK;
-
- while (nxt == &ptype_base[hash]) {
- if (++hash >= PTYPE_HASH_SIZE)
- return NULL;
- nxt = ptype_base[hash].next;
- }
-found:
- return list_entry(nxt, struct packet_type, list);
-}
-
-static void ptype_seq_stop(struct seq_file *seq, void *v)
- __releases(RCU)
-{
- rcu_read_unlock();
-}
-
-static int ptype_seq_show(struct seq_file *seq, void *v)
-{
- struct packet_type *pt = v;
-
- if (v == SEQ_START_TOKEN)
- seq_puts(seq, "Type Device Function\n");
- else if (pt->dev == NULL || dev_net(pt->dev) == seq_file_net(seq)) {
- if (pt->type == htons(ETH_P_ALL))
- seq_puts(seq, "ALL ");
- else
- seq_printf(seq, "%04x", ntohs(pt->type));
-
- seq_printf(seq, " %-8s %pF\n",
- pt->dev ? pt->dev->name : "", pt->func);
- }
-
- return 0;
-}
-
-static const struct seq_operations ptype_seq_ops = {
- .start = ptype_seq_start,
- .next = ptype_seq_next,
- .stop = ptype_seq_stop,
- .show = ptype_seq_show,
-};
-
-static int ptype_seq_open(struct inode *inode, struct file *file)
-{
- return seq_open_net(inode, file, &ptype_seq_ops,
- sizeof(struct seq_net_private));
-}
-
-static const struct file_operations ptype_seq_fops = {
- .owner = THIS_MODULE,
- .open = ptype_seq_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release_net,
-};
-
-
-static int __net_init dev_proc_net_init(struct net *net)
-{
- int rc = -ENOMEM;
-
- if (!proc_create("dev", S_IRUGO, net->proc_net, &dev_seq_fops))
- goto out;
- if (!proc_create("softnet_stat", S_IRUGO, net->proc_net,
- &softnet_seq_fops))
- goto out_dev;
- if (!proc_create("ptype", S_IRUGO, net->proc_net, &ptype_seq_fops))
- goto out_softnet;
-
- if (wext_proc_init(net))
- goto out_ptype;
- rc = 0;
-out:
- return rc;
-out_ptype:
- remove_proc_entry("ptype", net->proc_net);
-out_softnet:
- remove_proc_entry("softnet_stat", net->proc_net);
-out_dev:
- remove_proc_entry("dev", net->proc_net);
- goto out;
-}
-
-static void __net_exit dev_proc_net_exit(struct net *net)
-{
- wext_proc_exit(net);
-
- remove_proc_entry("ptype", net->proc_net);
- remove_proc_entry("softnet_stat", net->proc_net);
- remove_proc_entry("dev", net->proc_net);
-}
-
-static struct pernet_operations __net_initdata dev_proc_ops = {
- .init = dev_proc_net_init,
- .exit = dev_proc_net_exit,
-};
-
-static int __init dev_proc_init(void)
-{
- return register_pernet_subsys(&dev_proc_ops);
-}
-#else
-#define dev_proc_init() 0
-#endif /* CONFIG_PROC_FS */
-
-
struct netdev_upper {
struct net_device *dev;
bool master;
diff --git a/net/core/dev_addr_lists.c b/net/core/dev_addr_lists.c
index 8956252..bd2eb9d 100644
--- a/net/core/dev_addr_lists.c
+++ b/net/core/dev_addr_lists.c
@@ -15,7 +15,6 @@
#include <linux/rtnetlink.h>
#include <linux/export.h>
#include <linux/list.h>
-#include <linux/proc_fs.h>
/*
* General list handling functions
@@ -727,76 +726,3 @@ void dev_mc_init(struct net_device *dev)
__hw_addr_init(&dev->mc);
}
EXPORT_SYMBOL(dev_mc_init);
-
-#ifdef CONFIG_PROC_FS
-#include <linux/seq_file.h>
-
-static int dev_mc_seq_show(struct seq_file *seq, void *v)
-{
- struct netdev_hw_addr *ha;
- struct net_device *dev = v;
-
- if (v == SEQ_START_TOKEN)
- return 0;
-
- netif_addr_lock_bh(dev);
- netdev_for_each_mc_addr(ha, dev) {
- int i;
-
- seq_printf(seq, "%-4d %-15s %-5d %-5d ", dev->ifindex,
- dev->name, ha->refcount, ha->global_use);
-
- for (i = 0; i < dev->addr_len; i++)
- seq_printf(seq, "%02x", ha->addr[i]);
-
- seq_putc(seq, '\n');
- }
- netif_addr_unlock_bh(dev);
- return 0;
-}
-
-static const struct seq_operations dev_mc_seq_ops = {
- .start = dev_seq_start,
- .next = dev_seq_next,
- .stop = dev_seq_stop,
- .show = dev_mc_seq_show,
-};
-
-static int dev_mc_seq_open(struct inode *inode, struct file *file)
-{
- return seq_open_net(inode, file, &dev_mc_seq_ops,
- sizeof(struct seq_net_private));
-}
-
-static const struct file_operations dev_mc_seq_fops = {
- .owner = THIS_MODULE,
- .open = dev_mc_seq_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release_net,
-};
-
-#endif
-
-static int __net_init dev_mc_net_init(struct net *net)
-{
- if (!proc_create("dev_mcast", 0, net->proc_net, &dev_mc_seq_fops))
- return -ENOMEM;
- return 0;
-}
-
-static void __net_exit dev_mc_net_exit(struct net *net)
-{
- remove_proc_entry("dev_mcast", net->proc_net);
-}
-
-static struct pernet_operations __net_initdata dev_mc_net_ops = {
- .init = dev_mc_net_init,
- .exit = dev_mc_net_exit,
-};
-
-void __init dev_mcast_init(void)
-{
- register_pernet_subsys(&dev_mc_net_ops);
-}
-
diff --git a/net/core/net-procfs.c b/net/core/net-procfs.c
new file mode 100644
index 0000000..ac87066
--- /dev/null
+++ b/net/core/net-procfs.c
@@ -0,0 +1,414 @@
+#include <linux/netdevice.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <net/wext.h>
+
+#define BUCKET_SPACE (32 - NETDEV_HASHBITS - 1)
+
+#define get_bucket(x) ((x) >> BUCKET_SPACE)
+#define get_offset(x) ((x) & ((1 << BUCKET_SPACE) - 1))
+#define set_bucket_offset(b, o) ((b) << BUCKET_SPACE | (o))
+
+extern struct list_head ptype_all __read_mostly;
+extern struct list_head ptype_base[PTYPE_HASH_SIZE] __read_mostly;
+
+static inline struct net_device *dev_from_same_bucket(struct seq_file *seq, loff_t *pos)
+{
+ struct net *net = seq_file_net(seq);
+ struct net_device *dev;
+ struct hlist_node *p;
+ struct hlist_head *h;
+ unsigned int count = 0, offset = get_offset(*pos);
+
+ h = &net->dev_name_head[get_bucket(*pos)];
+ hlist_for_each_entry_rcu(dev, p, h, name_hlist) {
+ if (++count == offset)
+ return dev;
+ }
+
+ return NULL;
+}
+
+static inline struct net_device *dev_from_bucket(struct seq_file *seq, loff_t *pos)
+{
+ struct net_device *dev;
+ unsigned int bucket;
+
+ do {
+ dev = dev_from_same_bucket(seq, pos);
+ if (dev)
+ return dev;
+
+ bucket = get_bucket(*pos) + 1;
+ *pos = set_bucket_offset(bucket, 1);
+ } while (bucket < NETDEV_HASHENTRIES);
+
+ return NULL;
+}
+
+/*
+ * This is invoked by the /proc filesystem handler to display a device
+ * in detail.
+ */
+static void *dev_seq_start(struct seq_file *seq, loff_t *pos)
+ __acquires(RCU)
+{
+ rcu_read_lock();
+ if (!*pos)
+ return SEQ_START_TOKEN;
+
+ if (get_bucket(*pos) >= NETDEV_HASHENTRIES)
+ return NULL;
+
+ return dev_from_bucket(seq, pos);
+}
+
+static void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ ++*pos;
+ return dev_from_bucket(seq, pos);
+}
+
+static void dev_seq_stop(struct seq_file *seq, void *v)
+ __releases(RCU)
+{
+ rcu_read_unlock();
+}
+
+static void dev_seq_printf_stats(struct seq_file *seq, struct net_device *dev)
+{
+ struct rtnl_link_stats64 temp;
+ const struct rtnl_link_stats64 *stats = dev_get_stats(dev, &temp);
+
+ seq_printf(seq, "%6s: %7llu %7llu %4llu %4llu %4llu %5llu %10llu %9llu "
+ "%8llu %7llu %4llu %4llu %4llu %5llu %7llu %10llu\n",
+ dev->name, stats->rx_bytes, stats->rx_packets,
+ stats->rx_errors,
+ stats->rx_dropped + stats->rx_missed_errors,
+ stats->rx_fifo_errors,
+ stats->rx_length_errors + stats->rx_over_errors +
+ stats->rx_crc_errors + stats->rx_frame_errors,
+ stats->rx_compressed, stats->multicast,
+ stats->tx_bytes, stats->tx_packets,
+ stats->tx_errors, stats->tx_dropped,
+ stats->tx_fifo_errors, stats->collisions,
+ stats->tx_carrier_errors +
+ stats->tx_aborted_errors +
+ stats->tx_window_errors +
+ stats->tx_heartbeat_errors,
+ stats->tx_compressed);
+}
+
+/*
+ * Called from the PROCfs module. This now uses the new arbitrary sized
+ * /proc/net interface to create /proc/net/dev
+ */
+static int dev_seq_show(struct seq_file *seq, void *v)
+{
+ if (v == SEQ_START_TOKEN)
+ seq_puts(seq, "Inter-| Receive "
+ " | Transmit\n"
+ " face |bytes packets errs drop fifo frame "
+ "compressed multicast|bytes packets errs "
+ "drop fifo colls carrier compressed\n");
+ else
+ dev_seq_printf_stats(seq, v);
+ return 0;
+}
+
+static struct softnet_data *softnet_get_online(loff_t *pos)
+{
+ struct softnet_data *sd = NULL;
+
+ while (*pos < nr_cpu_ids)
+ if (cpu_online(*pos)) {
+ sd = &per_cpu(softnet_data, *pos);
+ break;
+ } else
+ ++*pos;
+ return sd;
+}
+
+static void *softnet_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ return softnet_get_online(pos);
+}
+
+static void *softnet_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ ++*pos;
+ return softnet_get_online(pos);
+}
+
+static void softnet_seq_stop(struct seq_file *seq, void *v)
+{
+}
+
+static int softnet_seq_show(struct seq_file *seq, void *v)
+{
+ struct softnet_data *sd = v;
+
+ seq_printf(seq, "%08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n",
+ sd->processed, sd->dropped, sd->time_squeeze, 0,
+ 0, 0, 0, 0, /* was fastroute */
+ sd->cpu_collision, sd->received_rps);
+ return 0;
+}
+
+static const struct seq_operations dev_seq_ops = {
+ .start = dev_seq_start,
+ .next = dev_seq_next,
+ .stop = dev_seq_stop,
+ .show = dev_seq_show,
+};
+
+static int dev_seq_open(struct inode *inode, struct file *file)
+{
+ return seq_open_net(inode, file, &dev_seq_ops,
+ sizeof(struct seq_net_private));
+}
+
+static const struct file_operations dev_seq_fops = {
+ .owner = THIS_MODULE,
+ .open = dev_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release_net,
+};
+
+static const struct seq_operations softnet_seq_ops = {
+ .start = softnet_seq_start,
+ .next = softnet_seq_next,
+ .stop = softnet_seq_stop,
+ .show = softnet_seq_show,
+};
+
+static int softnet_seq_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &softnet_seq_ops);
+}
+
+static const struct file_operations softnet_seq_fops = {
+ .owner = THIS_MODULE,
+ .open = softnet_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+static void *ptype_get_idx(loff_t pos)
+{
+ struct packet_type *pt = NULL;
+ loff_t i = 0;
+ int t;
+
+ list_for_each_entry_rcu(pt, &ptype_all, list) {
+ if (i == pos)
+ return pt;
+ ++i;
+ }
+
+ for (t = 0; t < PTYPE_HASH_SIZE; t++) {
+ list_for_each_entry_rcu(pt, &ptype_base[t], list) {
+ if (i == pos)
+ return pt;
+ ++i;
+ }
+ }
+ return NULL;
+}
+
+static void *ptype_seq_start(struct seq_file *seq, loff_t *pos)
+ __acquires(RCU)
+{
+ rcu_read_lock();
+ return *pos ? ptype_get_idx(*pos - 1) : SEQ_START_TOKEN;
+}
+
+static void *ptype_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ struct packet_type *pt;
+ struct list_head *nxt;
+ int hash;
+
+ ++*pos;
+ if (v == SEQ_START_TOKEN)
+ return ptype_get_idx(0);
+
+ pt = v;
+ nxt = pt->list.next;
+ if (pt->type == htons(ETH_P_ALL)) {
+ if (nxt != &ptype_all)
+ goto found;
+ hash = 0;
+ nxt = ptype_base[0].next;
+ } else
+ hash = ntohs(pt->type) & PTYPE_HASH_MASK;
+
+ while (nxt == &ptype_base[hash]) {
+ if (++hash >= PTYPE_HASH_SIZE)
+ return NULL;
+ nxt = ptype_base[hash].next;
+ }
+found:
+ return list_entry(nxt, struct packet_type, list);
+}
+
+static void ptype_seq_stop(struct seq_file *seq, void *v)
+ __releases(RCU)
+{
+ rcu_read_unlock();
+}
+
+static int ptype_seq_show(struct seq_file *seq, void *v)
+{
+ struct packet_type *pt = v;
+
+ if (v == SEQ_START_TOKEN)
+ seq_puts(seq, "Type Device Function\n");
+ else if (pt->dev == NULL || dev_net(pt->dev) == seq_file_net(seq)) {
+ if (pt->type == htons(ETH_P_ALL))
+ seq_puts(seq, "ALL ");
+ else
+ seq_printf(seq, "%04x", ntohs(pt->type));
+
+ seq_printf(seq, " %-8s %pF\n",
+ pt->dev ? pt->dev->name : "", pt->func);
+ }
+
+ return 0;
+}
+
+static const struct seq_operations ptype_seq_ops = {
+ .start = ptype_seq_start,
+ .next = ptype_seq_next,
+ .stop = ptype_seq_stop,
+ .show = ptype_seq_show,
+};
+
+static int ptype_seq_open(struct inode *inode, struct file *file)
+{
+ return seq_open_net(inode, file, &ptype_seq_ops,
+ sizeof(struct seq_net_private));
+}
+
+static const struct file_operations ptype_seq_fops = {
+ .owner = THIS_MODULE,
+ .open = ptype_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release_net,
+};
+
+
+static int __net_init dev_proc_net_init(struct net *net)
+{
+ int rc = -ENOMEM;
+
+ if (!proc_create("dev", S_IRUGO, net->proc_net, &dev_seq_fops))
+ goto out;
+ if (!proc_create("softnet_stat", S_IRUGO, net->proc_net,
+ &softnet_seq_fops))
+ goto out_dev;
+ if (!proc_create("ptype", S_IRUGO, net->proc_net, &ptype_seq_fops))
+ goto out_softnet;
+
+ if (wext_proc_init(net))
+ goto out_ptype;
+ rc = 0;
+out:
+ return rc;
+out_ptype:
+ remove_proc_entry("ptype", net->proc_net);
+out_softnet:
+ remove_proc_entry("softnet_stat", net->proc_net);
+out_dev:
+ remove_proc_entry("dev", net->proc_net);
+ goto out;
+}
+
+static void __net_exit dev_proc_net_exit(struct net *net)
+{
+ wext_proc_exit(net);
+
+ remove_proc_entry("ptype", net->proc_net);
+ remove_proc_entry("softnet_stat", net->proc_net);
+ remove_proc_entry("dev", net->proc_net);
+}
+
+static struct pernet_operations __net_initdata dev_proc_ops = {
+ .init = dev_proc_net_init,
+ .exit = dev_proc_net_exit,
+};
+
+int __init dev_proc_init(void)
+{
+ return register_pernet_subsys(&dev_proc_ops);
+}
+
+static int dev_mc_seq_show(struct seq_file *seq, void *v)
+{
+ struct netdev_hw_addr *ha;
+ struct net_device *dev = v;
+
+ if (v == SEQ_START_TOKEN)
+ return 0;
+
+ netif_addr_lock_bh(dev);
+ netdev_for_each_mc_addr(ha, dev) {
+ int i;
+
+ seq_printf(seq, "%-4d %-15s %-5d %-5d ", dev->ifindex,
+ dev->name, ha->refcount, ha->global_use);
+
+ for (i = 0; i < dev->addr_len; i++)
+ seq_printf(seq, "%02x", ha->addr[i]);
+
+ seq_putc(seq, '\n');
+ }
+ netif_addr_unlock_bh(dev);
+ return 0;
+}
+
+static const struct seq_operations dev_mc_seq_ops = {
+ .start = dev_seq_start,
+ .next = dev_seq_next,
+ .stop = dev_seq_stop,
+ .show = dev_mc_seq_show,
+};
+
+static int dev_mc_seq_open(struct inode *inode, struct file *file)
+{
+ return seq_open_net(inode, file, &dev_mc_seq_ops,
+ sizeof(struct seq_net_private));
+}
+
+static const struct file_operations dev_mc_seq_fops = {
+ .owner = THIS_MODULE,
+ .open = dev_mc_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release_net,
+};
+
+static int __net_init dev_mc_net_init(struct net *net)
+{
+ if (!proc_create("dev_mcast", 0, net->proc_net, &dev_mc_seq_fops))
+ return -ENOMEM;
+ return 0;
+}
+
+static void __net_exit dev_mc_net_exit(struct net *net)
+{
+ remove_proc_entry("dev_mcast", net->proc_net);
+}
+
+static struct pernet_operations __net_initdata dev_mc_net_ops = {
+ .init = dev_mc_net_init,
+ .exit = dev_mc_net_exit,
+};
+
+void __init dev_mcast_init(void)
+{
+ register_pernet_subsys(&dev_mc_net_ops);
+}
--
1.7.7.6
^ permalink raw reply related
* Re: 3.7.8/amd64 full interrupt hangs due to iwlwifi under big nfs copies out
From: Eric Dumazet @ 2013-02-19 5:17 UTC (permalink / raw)
To: Marc MERLIN
Cc: David Miller, Larry.Finger, bhutchings, linux-wireless, netdev
In-Reply-To: <20130219040557.GB4778@merlins.org>
On Mon, 2013-02-18 at 20:05 -0800, Marc MERLIN wrote:
> On Mon, Jul 16, 2012 at 06:21:57PM +0200, Eric Dumazet wrote:
> > > No, it's atually when I'm 'uploading' from my laptop to my server.
> > > One interesting thing is that my server is running lvm2 with snapshots,
> > > which makes writes slower than my laptop can push data over the network, so
> > > it's definitely causing buffers to fill up.
> > > I just did a download test and got 4.5MB/s sustained without problems.
> >
> > Hmm, nfs apparently is able to push lot of data, try to reduce
> > rsize/wsize to sane values, like 32K instead of 512K ?
> >
> > gargamel:/mnt/dshelf2/ /net/gargamel/mnt/dshelf2 nfs4
> > rw,nosuid,nodev,relatime,vers=4.0,rsize=524288,wsize=524288,namlen=255,hard,proto=tcp,port=0,timeo=600,retrans=2,sec=sys,clientaddr=192.168.205.7,local_lock=none,addr=192.168.205.3 0 0
> >
> > You could trace svc_sock_setbufsize() and check how large is set
> > sk_sndbuf
>
> My apologies, I totally dropped the ball on this.
>
> So, the problem was still there in more recent kernels.
>
> TL;DR:
> - reducing nfs buffers removes the full hang
> - iwlwifi has a problem where lack of pages causes the whoe machine to hang
> - NFS copies out, even with buffers down to 32K is very wonky and cp does not
> return until over 2mn after the copy is actually finished.
> (I have a trace of what's hung in cp/nfs when this happens)
>
>
> Details:
>
> It's still pretty severe because whatever blocks doesn't just end up
> blocking disk IO, but actually blocking interrupts altogether since my mouse
> can't move for a minute or more until some buffer flushes.
>
> The last trace I got during this (I can't do sysrq because I have a broken
> Lenovo T530 without a sysrq key, and typing doesn't really work when
> interrupts aren't firing).
>
> Not sure if it's useful. First chrome had an issue, and then iwlwifi
>
> chrome: page allocation failure: order:1, mode:0x4020
> Pid: 8730, comm: chrome Tainted: G O 3.7.8-amd64-preempt-20121226-fixwd #1
> Call Trace:
> <IRQ> [<ffffffff810d5f38>] warn_alloc_failed+0x117/0x12c
> [<ffffffff810d8cfd>] __alloc_pages_nodemask+0x66a/0x702
> [<ffffffff8108a948>] ? arch_local_irq_save+0x15/0x1b
> [<ffffffff811064af>] alloc_pages_current+0xcd/0xee
> [<ffffffffa039b579>] iwl_rx_allocate+0x8c/0x271 [iwlwifi]
> [<ffffffffa039c24e>] iwl_irq_tasklet+0x7e5/0x91c [iwlwifi]
> [<ffffffff8104805e>] tasklet_action+0x80/0xd2
> [<ffffffff81047c99>] __do_softirq+0xdf/0x1c5
> [<ffffffff814c1ed6>] ? _raw_spin_lock+0x1b/0x1f
> [<ffffffff810a7f37>] ? handle_irq_event+0x4d/0x62
> [<ffffffff814c7f5c>] call_softirq+0x1c/0x30
> [<ffffffff8101104e>] do_softirq+0x41/0x7f
> [<ffffffff81047e52>] irq_exit+0x3f/0xa7
> [<ffffffff81010d40>] do_IRQ+0x88/0x9f
> [<ffffffff814c246d>] common_interrupt+0x6d/0x6d
> <EOI> Mem-Info:
You could try to load iwlwifi with amsdu_size_8K set to 0 (disable)
It should hopefully use order-0 pages
Some drivers cant fallback to low order page allocations.
mlx4 is another example (it uses order-2 pages )
^ permalink raw reply
* RE: [PATCH] libertas sdio: remove CMD_FUNC_INIT call
From: Lubomir Rintel @ 2013-02-19 4:46 UTC (permalink / raw)
To: Bing Zhao
Cc: Harro Haan, Dan Williams, libertas-dev@lists.infradead.org,
netdev@vger.kernel.org, linux-wireless@vger.kernel.org,
John W. Linville, linux-kernel@vger.kernel.org
In-Reply-To: <477F20668A386D41ADCC57781B1F70430D140B07DE@SC-VEXCH1.marvell.com>
On Fri, 2013-01-18 at 12:28 -0800, Bing Zhao wrote:
> Hi Lubomir,
>
> > It actually times out on a 8688 present in GuruPlug with sd8688.bin
> > (md5=7233401e9687f8c880da547beed4324e) firmware (that's present in
> > linux-firmware tree), but the adapter works fine.
> >
> > For that firmware times out with libertas_uap [1] as well, though it succeeds
> > with sd8688_ap.bin (md5=52cd8f8296b9a7e1d3835d57416256b2) that was originally
> > shipped with GuruPlug. That firmware is not in linux-firmware tree and btmrvl
> > driver might win the race programming the 8688 with sd8688.bin anyway.
> >
> > [1] https://github.com/lkundrak/linux/tree/libertas_uap
> > ---
> > drivers/net/wireless/libertas/if_sdio.c | 14 --------------
> > 1 files changed, 0 insertions(+), 14 deletions(-)
> >
> > diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
> > index 2ecab49..3c4c555 100644
> > --- a/drivers/net/wireless/libertas/if_sdio.c
> > +++ b/drivers/net/wireless/libertas/if_sdio.c
> > @@ -825,20 +825,6 @@ static void if_sdio_finish_power_on(struct if_sdio_card *card)
> >
> > sdio_release_host(func);
> >
> > - /*
> > - * FUNC_INIT is required for SD8688 WLAN/BT multiple functions
> > - */
> > - if (card->model == MODEL_8688) {
> > - struct cmd_header cmd;
> > -
> > - memset(&cmd, 0, sizeof(cmd));
> > -
> > - lbs_deb_sdio("send function INIT command\n");
> > - if (__lbs_cmd(priv, CMD_FUNC_INIT, &cmd, sizeof(cmd),
> > - lbs_cmd_copyback, (unsigned long) &cmd))
> > - netdev_alert(priv->dev, "CMD_FUNC_INIT cmd failed\n");
> > - }
> > -
>
> Removing FUNC_INIT could break things in some scenarios.
> Could you please test the following case?
>
> 1. insmod liberates -> download firmware, send FUNC_INIT, ...
> 2. rmmod libertas -> send FUNC_SHUTDOWN command to firmware; BT is still working.
> 3. insmod libertas -> skip firmware downloading, send FUNC_INIT, ...
>
> If FUNC_INIT is removed, I don't expect step 3 to work.
In case btmrvl_sdio is loaded, the driver always locks up in FUNC_INIT
upon probe time, thus I'm not able to proceed to further steps.
[ 209.338953] [<c0502248>] (__schedule+0x610/0x764) from [<bf20ae24>] (__lbs_cmd+0xb8/0x130 [libertas])
[ 209.348340] [<bf20ae24>] (__lbs_cmd+0xb8/0x130 [libertas]) from [<bf222474>] (if_sdio_finish_power_on+0xec/0x1b0 [libertas_sdio])
[ 209.360136] [<bf222474>] (if_sdio_finish_power_on+0xec/0x1b0 [libertas_sdio]) from [<bf2226c4>] (if_sdio_power_on+0x18c/0x20c [libertas_sdio])
[ 209.373052] [<bf2226c4>] (if_sdio_power_on+0x18c/0x20c [libertas_sdio]) from [<bf222944>] (if_sdio_probe+0x200/0x31c [libertas_sdio])
[ 209.385316] [<bf222944>] (if_sdio_probe+0x200/0x31c [libertas_sdio]) from [<bf01d820>] (sdio_bus_probe+0x94/0xfc [mmc_core])
[ 209.396748] [<bf01d820>] (sdio_bus_probe+0x94/0xfc [mmc_core]) from [<c02e729c>] (driver_probe_device+0x12c/0x348)
[ 209.407214] [<c02e729c>] (driver_probe_device+0x12c/0x348) from [<c02e7530>] (__driver_attach+0x78/0x9c)
[ 209.416798] [<c02e7530>] (__driver_attach+0x78/0x9c) from [<c02e5658>] (bus_for_each_dev+0x50/0x88)
[ 209.425946] [<c02e5658>] (bus_for_each_dev+0x50/0x88) from [<c02e6810>] (bus_add_driver+0x108/0x268)
[ 209.435180] [<c02e6810>] (bus_add_driver+0x108/0x268) from [<c02e782c>] (driver_register+0xa4/0x134)
[ 209.444426] [<c02e782c>] (driver_register+0xa4/0x134) from [<bf22601c>] (if_sdio_init_module+0x1c/0x3c [libertas_sdio])
[ 209.455339] [<bf22601c>] (if_sdio_init_module+0x1c/0x3c [libertas_sdio]) from [<c00085b8>] (do_one_initcall+0x98/0x174)
[ 209.466236] [<c00085b8>] (do_one_initcall+0x98/0x174) from [<c0076504>] (load_module+0x1c5c/0x1f80)
[ 209.475390] [<c0076504>] (load_module+0x1c5c/0x1f80) from [<c007692c>] (sys_init_module+0x104/0x128)
[ 209.484632] [<c007692c>] (sys_init_module+0x104/0x128) from [<c0008c40>] (ret_fast_syscall+0x0/0x38)
In case btmrvl_sdio is _not_ loaded, insmod returns, but driver locks up
waiting for FUNC_INIT to finish:
[ 300.538859] [<c0502248>] (__schedule+0x610/0x764) from [<bf1fae24>] (__lbs_cmd+0xb8/0x130 [libertas])
[ 300.548600] [<bf1fae24>] (__lbs_cmd+0xb8/0x130 [libertas]) from [<bf212474>] (if_sdio_finish_power_on+0xec/0x1b0 [libertas_sdio])
[ 300.560398] [<bf212474>] (if_sdio_finish_power_on+0xec/0x1b0 [libertas_sdio]) from [<bf213230>] (if_sdio_do_prog_firmware+0x414/0x454 [libertas_sdio])
[ 300.574052] [<bf213230>] (if_sdio_do_prog_firmware+0x414/0x454 [libertas_sdio]) from [<bf1fffbc>] (lbs_fw_loaded+0x24/0x58 [libertas])
[ 300.586907] [<bf1fffbc>] (lbs_fw_loaded+0x24/0x58 [libertas]) from [<c02f02c0>] (request_firmware_work_func+0xb0/0xf4)
[ 300.597746] [<c02f02c0>] (request_firmware_work_func+0xb0/0xf4) from [<c003ae0c>] (process_one_work+0x348/0x6a8)
[ 300.608288] [<c003ae0c>] (process_one_work+0x348/0x6a8) from [<c003b408>] (worker_thread+0x268/0x390)
[ 300.617630] [<c003b408>] (worker_thread+0x268/0x390) from [<c00414b0>] (kthread+0xc0/0xd4)
[ 300.625947] [<c00414b0>] (kthread+0xc0/0xd4) from [<c0008ce8>] (ret_from_fork+0x14/0x20)
[ 300.634135] 2 locks held by kworker/0:1/19:
[ 300.638383] #0: (events){.+.+.+}, at: [<c003accc>] process_one_work+0x208/0x6a8
[ 300.646512] #1: ((&fw_work->work)){+.+.+.}, at: [<c003accc>] process_one_work+0x208/0x6a8
If I remove the FUNC_INIT call, wifi works fine, but bluetooth stops
working after a network scan:
[root@megalodon lkundrak]# iwlist scan >/dev/null 2>&1
[root@megalodon lkundrak]# hcitool scan --flush
Device is not available: No such device
[root@megalodon lkundrak]#
>
> Thanks,
> Bing
>
> > priv->fw_ready = 1;
> > wake_up(&card->pwron_waitq);
> >
> > --
> > 1.7.1
^ permalink raw reply
* net being merged into net-next
From: David Miller @ 2013-02-19 4:38 UTC (permalink / raw)
To: netdev
I'm merging net into net-next, the pending fixes in there didn't make
it to Linus in time for 3.8-final.
So I'm going to cherry pick those leftovers for -stable inclusion when
I find the time.
I'm also merging net into net-next to deal with the semantic merge
conflict caused by the xfrm6_policy.c neigh release fix on the net
side.
^ 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