* [PATCH 5/9] usb: add phy connection by phy-mode
From: Michael Grzeschik @ 2012-11-14 16:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1352909950-32555-1-git-send-email-m.grzeschik@pengutronix.de>
This patch makes it possible to set the connection of the usbphy to the
soc. It is derived from the oftree bindings for the ethernetphy and adds
similar helperfunctions.
Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
drivers/of/Kconfig | 4 ++++
drivers/of/Makefile | 1 +
drivers/of/of_usbphy.c | 49 +++++++++++++++++++++++++++++++++++++++++++++
include/linux/of_usbphy.h | 15 ++++++++++++++
include/linux/usb/phy.h | 8 ++++++++
5 files changed, 77 insertions(+)
create mode 100644 drivers/of/of_usbphy.c
create mode 100644 include/linux/of_usbphy.h
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index dfba3e6..28f99fb 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -67,6 +67,10 @@ config OF_MDIO
help
OpenFirmware MDIO bus (Ethernet PHY) accessors
+config OF_USBPHY
+ depends on USB
+ def_bool y
+
config OF_PCI
def_tristate PCI
depends on PCI
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index e027f44..fdcaf51 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_OF_IRQ) += irq.o
obj-$(CONFIG_OF_DEVICE) += device.o platform.o
obj-$(CONFIG_OF_I2C) += of_i2c.o
obj-$(CONFIG_OF_NET) += of_net.o
+obj-$(CONFIG_OF_USBPHY) += of_usbphy.o
obj-$(CONFIG_OF_SELFTEST) += selftest.o
obj-$(CONFIG_OF_MDIO) += of_mdio.o
obj-$(CONFIG_OF_PCI) += of_pci.o
diff --git a/drivers/of/of_usbphy.c b/drivers/of/of_usbphy.c
new file mode 100644
index 0000000..2e71f7b
--- /dev/null
+++ b/drivers/of/of_usbphy.c
@@ -0,0 +1,49 @@
+/*
+ * OF helpers for network devices.
+ *
+ * This file is released under the GPLv2
+ *
+ * Initially copied out of drivers/of/of_net.c
+ */
+#include <linux/etherdevice.h>
+#include <linux/kernel.h>
+#include <linux/of_usbphy.h>
+#include <linux/usb/phy.h>
+#include <linux/export.h>
+
+/**
+ * It maps 'enum usb_phy_interface' found in include/linux/usb/phy.h
+ * into the device tree binding of 'phy-mode', so that USB
+ * device driver can get phy interface from device tree.
+ */
+static const char *usbphy_modes[] = {
+ [USBPHY_INTERFACE_MODE_NA] = "",
+ [USBPHY_INTERFACE_MODE_UTMI] = "utmi",
+ [USBPHY_INTERFACE_MODE_UTMIW] = "utmiw",
+ [USBPHY_INTERFACE_MODE_ULPI] = "ulpi",
+ [USBPHY_INTERFACE_MODE_SERIAL] = "fsls",
+};
+
+/**
+ * of_get_phy_mode - Get phy mode for given device_node
+ * @np: Pointer to the given device_node
+ *
+ * The function gets phy interface string from property 'phy-mode',
+ * and return its index in phy_modes table, or errno in error case.
+ */
+const int of_get_usbphy_mode(struct device_node *np)
+{
+ const char *pm;
+ int err, i;
+
+ err = of_property_read_string(np, "phy-mode", &pm);
+ if (err < 0)
+ return err;
+
+ for (i = 0; i < ARRAY_SIZE(usbphy_modes); i++)
+ if (!strcasecmp(pm, usbphy_modes[i]))
+ return i;
+
+ return -ENODEV;
+}
+EXPORT_SYMBOL_GPL(of_get_usbphy_mode);
diff --git a/include/linux/of_usbphy.h b/include/linux/of_usbphy.h
new file mode 100644
index 0000000..9a4132d
--- /dev/null
+++ b/include/linux/of_usbphy.h
@@ -0,0 +1,15 @@
+/*
+ * OF helpers for usb devices.
+ *
+ * This file is released under the GPLv2
+ */
+
+#ifndef __LINUX_OF_USBPHY_H
+#define __LINUX_OF_USBPHY_H
+
+#ifdef CONFIG_OF_USBPHY
+#include <linux/of.h>
+extern const int of_get_usbphy_mode(struct device_node *np);
+#endif
+
+#endif /* __LINUX_OF_USBPHY_H */
diff --git a/include/linux/usb/phy.h b/include/linux/usb/phy.h
index a29ae1e..150eb69 100644
--- a/include/linux/usb/phy.h
+++ b/include/linux/usb/phy.h
@@ -12,6 +12,14 @@
#include <linux/notifier.h>
#include <linux/usb.h>
+enum usb_phy_interface {
+ USBPHY_INTERFACE_MODE_NA,
+ USBPHY_INTERFACE_MODE_UTMI,
+ USBPHY_INTERFACE_MODE_UTMIW,
+ USBPHY_INTERFACE_MODE_ULPI,
+ USBPHY_INTERFACE_MODE_SERIAL,
+};
+
enum usb_phy_events {
USB_EVENT_NONE, /* no events or cable disconnected */
USB_EVENT_VBUS, /* vbus valid event */
--
1.7.10.4
^ permalink raw reply related
* [PATCH 6/9] usb: chipidea: add PTW and PTS handling
From: Michael Grzeschik @ 2012-11-14 16:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1352909950-32555-1-git-send-email-m.grzeschik@pengutronix.de>
This patch makes it possible to configure the PTW and PTS bits inside
the portsc register for host and device mode before the driver starts
and the phy can be addressed as hardware implementation is designed.
Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
drivers/usb/chipidea/bits.h | 3 +++
drivers/usb/chipidea/ci.h | 2 ++
drivers/usb/chipidea/ci13xxx_imx.c | 1 +
drivers/usb/chipidea/core.c | 47 ++++++++++++++++++++++++++++++++++++
drivers/usb/chipidea/host.c | 4 +++
include/linux/usb/chipidea.h | 9 +++++++
6 files changed, 66 insertions(+)
diff --git a/drivers/usb/chipidea/bits.h b/drivers/usb/chipidea/bits.h
index 4b6ae3e..3cded5f 100644
--- a/drivers/usb/chipidea/bits.h
+++ b/drivers/usb/chipidea/bits.h
@@ -48,6 +48,9 @@
#define PORTSC_SUSP BIT(7)
#define PORTSC_HSP BIT(9)
#define PORTSC_PTC (0x0FUL << 16)
+#define PORTSC_PTS (BIT(31) | BIT(30))
+#define PORTSC_PTW BIT(28)
+#define PORTSC_STS BIT(29)
/* DEVLC */
#define DEVLC_PSPD (0x03UL << 25)
diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h
index cd42b59..1439e51 100644
--- a/drivers/usb/chipidea/ci.h
+++ b/drivers/usb/chipidea/ci.h
@@ -314,6 +314,8 @@ static inline u32 hw_test_and_write(struct ci13xxx *ci, enum ci13xxx_regs reg,
return (val & mask) >> ffs_nr(mask);
}
+void hw_portsc_configure(struct ci13xxx *ci);
+
int hw_device_reset(struct ci13xxx *ci, u32 mode);
int hw_port_test_set(struct ci13xxx *ci, u8 mode);
diff --git a/drivers/usb/chipidea/ci13xxx_imx.c b/drivers/usb/chipidea/ci13xxx_imx.c
index ee4dab0..a8257b8 100644
--- a/drivers/usb/chipidea/ci13xxx_imx.c
+++ b/drivers/usb/chipidea/ci13xxx_imx.c
@@ -133,6 +133,7 @@ static int __devinit ci13xxx_imx_probe(struct platform_device *pdev)
CI13XXX_PULLUP_ON_VBUS |
CI13XXX_DISABLE_STREAMING |
CI13XXX_REGS_SHARED,
+ ci13xxx_get_dr_flags(pdev->dev.of_node, pdata);
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data) {
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index 3e3e159..7e80f1b 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -68,6 +68,8 @@
#include <linux/usb/gadget.h>
#include <linux/usb/otg.h>
#include <linux/usb/chipidea.h>
+#include <linux/of_usbphy.h>
+#include <linux/phy.h>
#include "ci.h"
#include "udc.h"
@@ -213,6 +215,23 @@ static int hw_device_init(struct ci13xxx *ci, void __iomem *base)
return 0;
}
+void hw_portsc_configure(struct ci13xxx *ci)
+{
+ if (ci->platdata->flags & CI13XXX_PORTSC_PTW_16BIT)
+ hw_write(ci, OP_PORTSC, PORTSC_PTW, 0x1 << ffs_nr(PORTSC_PTW));
+
+ if (ci->platdata->flags & CI13XXX_PORTSC_PTS_UTMI) {
+ hw_write(ci, OP_PORTSC, PORTSC_PTS, 0x0 << ffs_nr(PORTSC_PTS));
+ hw_write(ci, OP_PORTSC, PORTSC_STS, 0x0 << ffs_nr(PORTSC_STS));
+ } else if (ci->platdata->flags & CI13XXX_PORTSC_PTS_ULPI) {
+ hw_write(ci, OP_PORTSC, PORTSC_PTS, 0x2 << ffs_nr(PORTSC_PTS));
+ hw_write(ci, OP_PORTSC, PORTSC_STS, 0x0 << ffs_nr(PORTSC_STS));
+ } else if (ci->platdata->flags & CI13XXX_PORTSC_PTS_FSLS) {
+ hw_write(ci, OP_PORTSC, PORTSC_PTS, 0x3 << ffs_nr(PORTSC_PTS));
+ hw_write(ci, OP_PORTSC, PORTSC_STS, 0x1 << ffs_nr(PORTSC_STS));
+ }
+}
+
/**
* hw_device_reset: resets chip (execute without interruption)
* @ci: the controller
@@ -237,6 +256,8 @@ int hw_device_reset(struct ci13xxx *ci, u32 mode)
if (ci->platdata->flags & CI13XXX_DISABLE_STREAMING)
hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS);
+ hw_portsc_configure(ci);
+
/* USBMODE should be configured step by step */
hw_write(ci, OP_USBMODE, USBMODE_CM, USBMODE_CM_IDLE);
hw_write(ci, OP_USBMODE, USBMODE_CM, mode);
@@ -522,6 +543,32 @@ void ci13xxx_remove_device(struct platform_device *pdev)
}
EXPORT_SYMBOL_GPL(ci13xxx_remove_device);
+void ci13xxx_get_dr_flags(struct device_node *of_node, struct ci13xxx_platform_data *pdata)
+{
+ int interface = of_get_usbphy_mode(of_node);
+
+ switch (interface) {
+ case USBPHY_INTERFACE_MODE_UTMI:
+ pdata->flags |= CI13XXX_PORTSC_PTS_UTMI;
+ break;
+ case USBPHY_INTERFACE_MODE_UTMIW:
+ pdata->flags |= CI13XXX_PORTSC_PTS_UTMI |
+ CI13XXX_PORTSC_PTW_16BIT;
+ break;
+ case USBPHY_INTERFACE_MODE_ULPI:
+ pdata->flags |= CI13XXX_PORTSC_PTS_ULPI;
+ break;
+ case USBPHY_INTERFACE_MODE_SERIAL:
+ pdata->flags |= CI13XXX_PORTSC_PTS_FSLS;
+ break;
+ case USBPHY_INTERFACE_MODE_NA:
+ default:
+ pr_err("no phy interface defined\n");
+ }
+
+}
+EXPORT_SYMBOL_GPL(ci13xxx_get_dr_flags);
+
void ci13xxx_get_dr_mode(struct device_node *of_node, struct ci13xxx_platform_data *pdata)
{
const unsigned char *dr_mode;
diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c
index ebff9f4..b23ee1d 100644
--- a/drivers/usb/chipidea/host.c
+++ b/drivers/usb/chipidea/host.c
@@ -106,6 +106,10 @@ static int host_start(struct ci13xxx *ci)
if (usb_disabled())
return -ENODEV;
+ hw_portsc_configure(ci);
+
+ mdelay(10);
+
hcd = usb_create_hcd(&ci_ehci_hc_driver, ci->dev, dev_name(ci->dev));
if (!hcd)
return -ENOMEM;
diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h
index 906d259..cafca23 100644
--- a/include/linux/usb/chipidea.h
+++ b/include/linux/usb/chipidea.h
@@ -21,6 +21,12 @@ struct ci13xxx_platform_data {
#define CI13XXX_DISABLE_STREAMING BIT(3)
#define CI13XXX_DR_MODE_HOST BIT(4)
#define CI13XXX_DR_MODE_PERIPHERAL BIT(5)
+#define CI13XXX_PORTSC_PTW_8BIT BIT(6)
+#define CI13XXX_PORTSC_PTW_16BIT BIT(7)
+#define CI13XXX_PORTSC_PTS_UTMI BIT(8)
+#define CI13XXX_PORTSC_PTS_ULPI BIT(9)
+#define CI13XXX_PORTSC_PTS_FSLS BIT(10)
+
#define CI13XXX_DR_MODE_MASK \
(CI13XXX_DR_MODE_HOST | CI13XXX_DR_MODE_PERIPHERAL)
@@ -42,4 +48,7 @@ void ci13xxx_remove_device(struct platform_device *pdev);
/* Parse of-tree "dr_mode" property */
void ci13xxx_get_dr_mode(struct device_node *of_node, struct ci13xxx_platform_data *pdata);
+/* Parse of-tree "flags" */
+void ci13xxx_get_dr_flags(struct device_node *of_node, struct ci13xxx_platform_data *pdata);
+
#endif
--
1.7.10.4
^ permalink raw reply related
* [PATCH 7/9] usb: chipidea: udc: add force-full-speed option
From: Michael Grzeschik @ 2012-11-14 16:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1352909950-32555-1-git-send-email-m.grzeschik@pengutronix.de>
This patch makes it possible to set the chipidea udc
into full-speed only mode. It can be set by the oftree
property "force-full-speed".
Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
drivers/usb/chipidea/bits.h | 1 +
drivers/usb/chipidea/core.c | 5 +++++
include/linux/usb/chipidea.h | 1 +
3 files changed, 7 insertions(+)
diff --git a/drivers/usb/chipidea/bits.h b/drivers/usb/chipidea/bits.h
index 3cded5f..85b6b09 100644
--- a/drivers/usb/chipidea/bits.h
+++ b/drivers/usb/chipidea/bits.h
@@ -51,6 +51,7 @@
#define PORTSC_PTS (BIT(31) | BIT(30))
#define PORTSC_PTW BIT(28)
#define PORTSC_STS BIT(29)
+#define PORTSC_PFSC BIT(24)
/* DEVLC */
#define DEVLC_PSPD (0x03UL << 25)
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index 7e80f1b..bc99cea 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -230,6 +230,9 @@ void hw_portsc_configure(struct ci13xxx *ci)
hw_write(ci, OP_PORTSC, PORTSC_PTS, 0x3 << ffs_nr(PORTSC_PTS));
hw_write(ci, OP_PORTSC, PORTSC_STS, 0x1 << ffs_nr(PORTSC_STS));
}
+
+ if (ci->platdata->flags & CI13XXX_PORTSC_PFSC)
+ hw_write(ci, OP_PORTSC, PORTSC_PFSC, 0x1 << ffs_nr(PORTSC_PFSC));
}
/**
@@ -566,6 +569,8 @@ void ci13xxx_get_dr_flags(struct device_node *of_node, struct ci13xxx_platform_d
pr_err("no phy interface defined\n");
}
+ if (of_find_property(of_node, "force-full-speed", NULL))
+ pdata->flags |= CI13XXX_PORTSC_PFSC;
}
EXPORT_SYMBOL_GPL(ci13xxx_get_dr_flags);
diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h
index cafca23..9ffe105 100644
--- a/include/linux/usb/chipidea.h
+++ b/include/linux/usb/chipidea.h
@@ -26,6 +26,7 @@ struct ci13xxx_platform_data {
#define CI13XXX_PORTSC_PTS_UTMI BIT(8)
#define CI13XXX_PORTSC_PTS_ULPI BIT(9)
#define CI13XXX_PORTSC_PTS_FSLS BIT(10)
+#define CI13XXX_PORTSC_PFSC BIT(11)
#define CI13XXX_DR_MODE_MASK \
(CI13XXX_DR_MODE_HOST | CI13XXX_DR_MODE_PERIPHERAL)
--
1.7.10.4
^ permalink raw reply related
* [PATCH 8/9] usb: chipidea: udc: remove unlocked ep_queue which can lead to an race
From: Michael Grzeschik @ 2012-11-14 16:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1352909950-32555-1-git-send-email-m.grzeschik@pengutronix.de>
Its not nessecary to call ep_queue unlocked while in the
own driver. So we move the function to an unlocked version
and call it conditionaly.
Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
drivers/usb/chipidea/udc.c | 115 +++++++++++++++++++++++++-------------------
1 file changed, 65 insertions(+), 50 deletions(-)
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index 0ed2e1a..2999b0d 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -648,6 +648,68 @@ static void isr_get_status_complete(struct usb_ep *ep, struct usb_request *req)
}
/**
+ * _ep_queue: queues (submits) an I/O request to an endpoint
+ *
+ * Caller must hold lock
+ */
+static int _ep_queue(struct usb_ep *ep, struct usb_request *req,
+ gfp_t __maybe_unused gfp_flags)
+{
+ struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+ struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
+ struct ci13xxx *ci = mEp->ci;
+ int retval = 0;
+
+ if (ep == NULL || req == NULL || mEp->ep.desc == NULL)
+ return -EINVAL;
+
+ if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
+ if (req->length)
+ mEp = (ci->ep0_dir == RX) ?
+ ci->ep0out : ci->ep0in;
+ if (!list_empty(&mEp->qh.queue)) {
+ _ep_nuke(mEp);
+ retval = -EOVERFLOW;
+ dev_warn(mEp->ci->dev, "endpoint ctrl %X nuked\n",
+ _usb_addr(mEp));
+ }
+ }
+
+ /* first nuke then test link, e.g. previous status has not sent */
+ if (!list_empty(&mReq->queue)) {
+ retval = -EBUSY;
+ dev_err(mEp->ci->dev, "request already in queue\n");
+ goto done;
+ }
+
+ if (req->length > 4 * CI13XXX_PAGE_SIZE) {
+ req->length = 4 * CI13XXX_PAGE_SIZE;
+ retval = -EMSGSIZE;
+ dev_warn(mEp->ci->dev, "request length truncated\n");
+ }
+
+ dbg_queue(_usb_addr(mEp), req, retval);
+
+ /* push request */
+ mReq->req.status = -EINPROGRESS;
+ mReq->req.actual = 0;
+
+ retval = _hardware_enqueue(mEp, mReq);
+
+ if (retval == -EALREADY) {
+ dbg_event(_usb_addr(mEp), "QUEUE", retval);
+ retval = 0;
+ }
+ if (!retval)
+ list_add_tail(&mReq->queue, &mEp->qh.queue);
+
+ done:
+ return retval;
+}
+
+
+
+/**
* isr_get_status_response: get_status request response
* @ci: ci struct
* @setup: setup request packet
@@ -694,9 +756,7 @@ __acquires(mEp->lock)
}
/* else do nothing; reserved for future use */
- spin_unlock(mEp->lock);
- retval = usb_ep_queue(&mEp->ep, req, gfp_flags);
- spin_lock(mEp->lock);
+ retval = _ep_queue(&mEp->ep, req, gfp_flags);
if (retval)
goto err_free_buf;
@@ -743,8 +803,6 @@ isr_setup_status_complete(struct usb_ep *ep, struct usb_request *req)
* This function returns an error code
*/
static int isr_setup_status_phase(struct ci13xxx *ci)
-__releases(mEp->lock)
-__acquires(mEp->lock)
{
int retval;
struct ci13xxx_ep *mEp;
@@ -753,9 +811,7 @@ __acquires(mEp->lock)
ci->status->context = ci;
ci->status->complete = isr_setup_status_complete;
- spin_unlock(mEp->lock);
- retval = usb_ep_queue(&mEp->ep, ci->status, GFP_ATOMIC);
- spin_lock(mEp->lock);
+ retval = _ep_queue(&mEp->ep, ci->status, GFP_ATOMIC);
return retval;
}
@@ -1152,8 +1208,6 @@ static int ep_queue(struct usb_ep *ep, struct usb_request *req,
gfp_t __maybe_unused gfp_flags)
{
struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
- struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
- struct ci13xxx *ci = mEp->ci;
int retval = 0;
unsigned long flags;
@@ -1162,47 +1216,8 @@ static int ep_queue(struct usb_ep *ep, struct usb_request *req,
spin_lock_irqsave(mEp->lock, flags);
- if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
- if (req->length)
- mEp = (ci->ep0_dir == RX) ?
- ci->ep0out : ci->ep0in;
- if (!list_empty(&mEp->qh.queue)) {
- _ep_nuke(mEp);
- retval = -EOVERFLOW;
- dev_warn(mEp->ci->dev, "endpoint ctrl %X nuked\n",
- _usb_addr(mEp));
- }
- }
-
- /* first nuke then test link, e.g. previous status has not sent */
- if (!list_empty(&mReq->queue)) {
- retval = -EBUSY;
- dev_err(mEp->ci->dev, "request already in queue\n");
- goto done;
- }
-
- if (req->length > 4 * CI13XXX_PAGE_SIZE) {
- req->length = 4 * CI13XXX_PAGE_SIZE;
- retval = -EMSGSIZE;
- dev_warn(mEp->ci->dev, "request length truncated\n");
- }
-
- dbg_queue(_usb_addr(mEp), req, retval);
+ retval = _ep_queue(ep, req, gfp_flags);
- /* push request */
- mReq->req.status = -EINPROGRESS;
- mReq->req.actual = 0;
-
- retval = _hardware_enqueue(mEp, mReq);
-
- if (retval == -EALREADY) {
- dbg_event(_usb_addr(mEp), "QUEUE", retval);
- retval = 0;
- }
- if (!retval)
- list_add_tail(&mReq->queue, &mEp->qh.queue);
-
- done:
spin_unlock_irqrestore(mEp->lock, flags);
return retval;
}
--
1.7.10.4
^ permalink raw reply related
* [PATCH 9/9] usb: chipidea: udc: configure iso endpoints
From: Michael Grzeschik @ 2012-11-14 16:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1352909950-32555-1-git-send-email-m.grzeschik@pengutronix.de>
The implementation is derived from the fsl_udc_core code in
fsl_ep_enable and makes basic iso handling possible.
Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
drivers/usb/chipidea/udc.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index 2999b0d..0bc4308 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -1058,6 +1058,9 @@ static int ep_enable(struct usb_ep *ep,
int retval = 0;
unsigned long flags;
+ unsigned short max = 0;
+ unsigned char mult = 0;
+
if (ep == NULL || desc == NULL)
return -EINVAL;
@@ -1075,6 +1078,7 @@ static int ep_enable(struct usb_ep *ep,
mEp->type = usb_endpoint_type(desc);
mEp->ep.maxpacket = usb_endpoint_maxp(desc);
+ max = usb_endpoint_maxp(desc);
dbg_event(_usb_addr(mEp), "ENABLE", 0);
@@ -1082,8 +1086,12 @@ static int ep_enable(struct usb_ep *ep,
if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
mEp->qh.ptr->cap |= QH_IOS;
- else if (mEp->type == USB_ENDPOINT_XFER_ISOC)
- mEp->qh.ptr->cap &= ~QH_MULT;
+ else if (mEp->type == USB_ENDPOINT_XFER_ISOC) {
+ /* Calculate transactions needed for high bandwidth iso */
+ mult = (unsigned char)(1 + ((max >> 11) & 0x03));
+ max = max & 0x7ff; /* bit 0~10 */
+ mEp->qh.ptr->cap |= (mult << 30);
+ }
else
mEp->qh.ptr->cap &= ~QH_ZLT;
--
1.7.10.4
^ permalink raw reply related
* [PATCH v3 0/3] i2c: at91: add dma support
From: ludovic.desroches at atmel.com @ 2012-11-14 16:44 UTC (permalink / raw)
To: linux-arm-kernel
From: Ludovic Desroches <ludovic.desroches@atmel.com>
Hi Wolfram,
Here is the third version taking into account your feedback.
Patch 1/3 should go into v3.7.
Regards
Ludovic
Changes:
- v3
- introduce two new patches: one to fix a compilation warning and one to
fix indentation
- introduce a threshold to use dma transfers
- use dma wrappers to clean code
- remove dma cookie since it is no more used
- v2 (based on Russell feedback):
- replace DMA_TO_DEVICE/DMA_FROM_DEVICE by DMA_MEM_TO_DEV/DMA_DEV_TO_MEM
- don't check for tx_submit errors
- atmel dma header location has changed
Ludovic Desroches (3):
i2c: at91: fix compilation warning
i2c: at91: change struct members indentation
i2c: at91: add dma support
drivers/i2c/busses/i2c-at91.c | 338 +++++++++++++++++++++++++++++++++++++++---
1 file changed, 314 insertions(+), 24 deletions(-)
--
1.7.11.3
^ permalink raw reply
* [PATCH 1/3] i2c: at91: fix compilation warning
From: ludovic.desroches at atmel.com @ 2012-11-14 16:44 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1352911493-6979-1-git-send-email-ludovic.desroches@atmel.com>
From: Ludovic Desroches <ludovic.desroches@atmel.com>
Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
---
drivers/i2c/busses/i2c-at91.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
index a6670eb..dc8cb22 100644
--- a/drivers/i2c/busses/i2c-at91.c
+++ b/drivers/i2c/busses/i2c-at91.c
@@ -412,7 +412,7 @@ static struct at91_twi_pdata * __devinit at91_twi_get_driver_data(
match = of_match_node(atmel_twi_dt_ids, pdev->dev.of_node);
if (!match)
return NULL;
- return match->data;
+ return (struct at91_twi_pdata *) match->data;
}
return (struct at91_twi_pdata *) platform_get_device_id(pdev)->driver_data;
}
--
1.7.11.3
^ permalink raw reply related
* [PATCH 2/3] i2c: at91: change struct members indentation
From: ludovic.desroches at atmel.com @ 2012-11-14 16:44 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1352911493-6979-1-git-send-email-ludovic.desroches@atmel.com>
From: Ludovic Desroches <ludovic.desroches@atmel.com>
Replace tabs for struct members indentation by space to minimise line changes
when adding new members which would require extra tabs to keep alignment.
Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
---
drivers/i2c/busses/i2c-at91.c | 30 +++++++++++++++---------------
1 file changed, 15 insertions(+), 15 deletions(-)
diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
index dc8cb22..2c437df 100644
--- a/drivers/i2c/busses/i2c-at91.c
+++ b/drivers/i2c/busses/i2c-at91.c
@@ -66,24 +66,24 @@
#define AT91_TWI_THR 0x0034 /* Transmit Holding Register */
struct at91_twi_pdata {
- unsigned clk_max_div;
- unsigned clk_offset;
- bool has_unre_flag;
+ unsigned clk_max_div;
+ unsigned clk_offset;
+ bool has_unre_flag;
};
struct at91_twi_dev {
- struct device *dev;
- void __iomem *base;
- struct completion cmd_complete;
- struct clk *clk;
- u8 *buf;
- size_t buf_len;
- struct i2c_msg *msg;
- int irq;
- unsigned transfer_status;
- struct i2c_adapter adapter;
- unsigned twi_cwgr_reg;
- struct at91_twi_pdata *pdata;
+ struct device *dev;
+ void __iomem *base;
+ struct completion cmd_complete;
+ struct clk *clk;
+ u8 *buf;
+ size_t buf_len;
+ struct i2c_msg *msg;
+ int irq;
+ unsigned transfer_status;
+ struct i2c_adapter adapter;
+ unsigned twi_cwgr_reg;
+ struct at91_twi_pdata *pdata;
};
static unsigned at91_twi_read(struct at91_twi_dev *dev, unsigned reg)
--
1.7.11.3
^ permalink raw reply related
* [PATCH 3/3] i2c: at91: add dma support
From: ludovic.desroches at atmel.com @ 2012-11-14 16:44 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1352911493-6979-1-git-send-email-ludovic.desroches@atmel.com>
From: Ludovic Desroches <ludovic.desroches@atmel.com>
Add dma support for Atmel TWI which is available on sam9x5 and later.
When using dma for reception, you have to read only n-2 bytes. The last
two bytes are read manually. Don't doing this should cause to send the
STOP command too late and then to get extra data in the receive
register.
Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
---
drivers/i2c/busses/i2c-at91.c | 306 ++++++++++++++++++++++++++++++++++++++++--
1 file changed, 298 insertions(+), 8 deletions(-)
diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
index 2c437df..ceef40f 100644
--- a/drivers/i2c/busses/i2c-at91.c
+++ b/drivers/i2c/busses/i2c-at91.c
@@ -19,6 +19,8 @@
#include <linux/clk.h>
#include <linux/completion.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
@@ -29,9 +31,11 @@
#include <linux/of_i2c.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
+#include <linux/platform_data/dma-atmel.h>
#define TWI_CLK_HZ 100000 /* max 400 Kbits/s */
#define AT91_I2C_TIMEOUT msecs_to_jiffies(100) /* transfer timeout */
+#define AT91_I2C_DMA_THRESHOLD 8 /* enable DMA if transfer size is bigger than this threshold */
/* AT91 TWI register definitions */
#define AT91_TWI_CR 0x0000 /* Control Register */
@@ -69,6 +73,18 @@ struct at91_twi_pdata {
unsigned clk_max_div;
unsigned clk_offset;
bool has_unre_flag;
+ bool has_dma_support;
+ struct at_dma_slave dma_slave;
+};
+
+struct at91_twi_dma {
+ struct dma_chan *chan_rx;
+ struct dma_chan *chan_tx;
+ struct scatterlist sg;
+ struct dma_async_tx_descriptor *data_desc;
+ enum dma_data_direction direction;
+ bool buf_mapped;
+ bool xfer_in_progress;
};
struct at91_twi_dev {
@@ -80,10 +96,13 @@ struct at91_twi_dev {
size_t buf_len;
struct i2c_msg *msg;
int irq;
+ unsigned imr;
unsigned transfer_status;
struct i2c_adapter adapter;
unsigned twi_cwgr_reg;
struct at91_twi_pdata *pdata;
+ bool use_dma;
+ struct at91_twi_dma dma;
};
static unsigned at91_twi_read(struct at91_twi_dev *dev, unsigned reg)
@@ -102,6 +121,17 @@ static void at91_disable_twi_interrupts(struct at91_twi_dev *dev)
AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY);
}
+static void at91_twi_irq_save(struct at91_twi_dev *dev)
+{
+ dev->imr = at91_twi_read(dev, AT91_TWI_IMR) & 0x7;
+ at91_disable_twi_interrupts(dev);
+}
+
+static void at91_twi_irq_restore(struct at91_twi_dev *dev)
+{
+ at91_twi_write(dev, AT91_TWI_IER, dev->imr);
+}
+
static void at91_init_twi_bus(struct at91_twi_dev *dev)
{
at91_disable_twi_interrupts(dev);
@@ -138,6 +168,28 @@ static void __devinit at91_calc_twi_clock(struct at91_twi_dev *dev, int twi_clk)
dev_dbg(dev->dev, "cdiv %d ckdiv %d\n", cdiv, ckdiv);
}
+static void at91_twi_dma_cleanup(struct at91_twi_dev *dev)
+{
+ struct at91_twi_dma *dma = &dev->dma;
+
+ at91_twi_irq_save(dev);
+
+ if (dma->xfer_in_progress) {
+ if (dma->direction == DMA_FROM_DEVICE)
+ dmaengine_terminate_all(dma->chan_rx);
+ else
+ dmaengine_terminate_all(dma->chan_tx);
+ dma->xfer_in_progress = false;
+ }
+ if (dma->buf_mapped) {
+ dma_unmap_single(dev->dev, sg_dma_address(&dma->sg),
+ dev->buf_len, dma->direction);
+ dma->buf_mapped = false;
+ }
+
+ at91_twi_irq_restore(dev);
+}
+
static void at91_twi_write_next_byte(struct at91_twi_dev *dev)
{
if (dev->buf_len <= 0)
@@ -154,6 +206,60 @@ static void at91_twi_write_next_byte(struct at91_twi_dev *dev)
++dev->buf;
}
+static void at91_twi_write_data_dma_callback(void *data)
+{
+ struct at91_twi_dev *dev = (struct at91_twi_dev *)data;
+
+ dma_unmap_single(dev->dev, sg_dma_address(&dev->dma.sg),
+ dev->buf_len, DMA_MEM_TO_DEV);
+
+ at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP);
+}
+
+static void at91_twi_write_data_dma(struct at91_twi_dev *dev)
+{
+ dma_addr_t dma_addr;
+ struct dma_async_tx_descriptor *txdesc;
+ struct at91_twi_dma *dma = &dev->dma;
+ struct dma_chan *chan_tx = dma->chan_tx;
+
+ if (dev->buf_len <= 0)
+ return;
+
+ dma->direction = DMA_TO_DEVICE;
+
+ at91_twi_irq_save(dev);
+ dma_addr = dma_map_single(dev->dev, dev->buf, dev->buf_len,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(dev->dev, dma_addr)) {
+ dev_err(dev->dev, "dma map failed\n");
+ return;
+ }
+ dma->buf_mapped = true;
+ at91_twi_irq_restore(dev);
+ sg_dma_len(&dma->sg) = dev->buf_len;
+ sg_dma_address(&dma->sg) = dma_addr;
+
+ txdesc = dmaengine_prep_slave_sg(chan_tx, &dma->sg, 1, DMA_MEM_TO_DEV,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!txdesc) {
+ dev_err(dev->dev, "dma prep slave sg failed\n");
+ goto error;
+ }
+
+ txdesc->callback = at91_twi_write_data_dma_callback;
+ txdesc->callback_param = dev;
+
+ dma->xfer_in_progress = true;
+ dmaengine_submit(txdesc);
+ dma_async_issue_pending(chan_tx);
+
+ return;
+
+error:
+ at91_twi_dma_cleanup(dev);
+}
+
static void at91_twi_read_next_byte(struct at91_twi_dev *dev)
{
if (dev->buf_len <= 0)
@@ -179,6 +285,61 @@ static void at91_twi_read_next_byte(struct at91_twi_dev *dev)
++dev->buf;
}
+static void at91_twi_read_data_dma_callback(void *data)
+{
+ struct at91_twi_dev *dev = (struct at91_twi_dev *)data;
+
+ dma_unmap_single(dev->dev, sg_dma_address(&dev->dma.sg),
+ dev->buf_len, DMA_DEV_TO_MEM);
+
+ /* The last two bytes have to be read without using dma */
+ dev->buf += dev->buf_len - 2;
+ dev->buf_len = 2;
+ at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_RXRDY);
+}
+
+static void at91_twi_read_data_dma(struct at91_twi_dev *dev)
+{
+ dma_addr_t dma_addr;
+ struct dma_async_tx_descriptor *rxdesc;
+ struct at91_twi_dma *dma = &dev->dma;
+ struct dma_chan *chan_rx = dma->chan_rx;
+
+ dma->direction = DMA_FROM_DEVICE;
+
+ /* Keep in mind that we won't use dma to read the last two bytes */
+ at91_twi_irq_save(dev);
+ dma_addr = dma_map_single(dev->dev, dev->buf, dev->buf_len - 2,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(dev->dev, dma_addr)) {
+ dev_err(dev->dev, "dma map failed\n");
+ return;
+ }
+ dma->buf_mapped = true;
+ at91_twi_irq_restore(dev);
+ dma->sg.dma_address = dma_addr;
+ sg_dma_len(&dma->sg) = dev->buf_len - 2;
+
+ rxdesc = dmaengine_prep_slave_sg(chan_rx, &dma->sg, 1, DMA_DEV_TO_MEM,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!rxdesc) {
+ dev_err(dev->dev, "dma prep slave sg failed\n");
+ goto error;
+ }
+
+ rxdesc->callback = at91_twi_read_data_dma_callback;
+ rxdesc->callback_param = dev;
+
+ dma->xfer_in_progress = true;
+ dmaengine_submit(rxdesc);
+ dma_async_issue_pending(dma->chan_rx);
+
+ return;
+
+error:
+ at91_twi_dma_cleanup(dev);
+}
+
static irqreturn_t atmel_twi_interrupt(int irq, void *dev_id)
{
struct at91_twi_dev *dev = dev_id;
@@ -228,12 +389,36 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev)
if (dev->buf_len <= 1 && !(dev->msg->flags & I2C_M_RECV_LEN))
start_flags |= AT91_TWI_STOP;
at91_twi_write(dev, AT91_TWI_CR, start_flags);
- at91_twi_write(dev, AT91_TWI_IER,
+ /*
+ * When using dma, the last byte has to be read manually in
+ * order to not send the stop command too late and then
+ * to receive extra data. In practice, there are some issues
+ * if you use the dma to read n-1 bytes because of latency.
+ * Reading n-2 bytes with dma and the two last ones manually
+ * seems to be the best solution.
+ */
+ if (dev->use_dma && (dev->buf_len > AT91_I2C_DMA_THRESHOLD)) {
+ at91_twi_read_data_dma(dev);
+ /*
+ * It is important to enable TXCOMP irq here because
+ * doing it only when transferring the last two bytes
+ * will mask NACK errors since TXCOMP is set when a
+ * NACK occurs.
+ */
+ at91_twi_write(dev, AT91_TWI_IER,
+ AT91_TWI_TXCOMP);
+ } else
+ at91_twi_write(dev, AT91_TWI_IER,
AT91_TWI_TXCOMP | AT91_TWI_RXRDY);
} else {
- at91_twi_write_next_byte(dev);
- at91_twi_write(dev, AT91_TWI_IER,
- AT91_TWI_TXCOMP | AT91_TWI_TXRDY);
+ if (dev->use_dma && (dev->buf_len > AT91_I2C_DMA_THRESHOLD)) {
+ at91_twi_write_data_dma(dev);
+ at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_TXCOMP);
+ } else {
+ at91_twi_write_next_byte(dev);
+ at91_twi_write(dev, AT91_TWI_IER,
+ AT91_TWI_TXCOMP | AT91_TWI_TXRDY);
+ }
}
ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
@@ -241,23 +426,31 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev)
if (ret == 0) {
dev_dbg(dev->dev, "controller timed out\n");
at91_init_twi_bus(dev);
- return -ETIMEDOUT;
+ ret = -ETIMEDOUT;
+ goto error;
}
if (dev->transfer_status & AT91_TWI_NACK) {
dev_dbg(dev->dev, "received nack\n");
- return -EREMOTEIO;
+ ret = -EREMOTEIO;
+ goto error;
}
if (dev->transfer_status & AT91_TWI_OVRE) {
dev_err(dev->dev, "overrun while reading\n");
- return -EIO;
+ ret = -EIO;
+ goto error;
}
if (has_unre_flag && dev->transfer_status & AT91_TWI_UNRE) {
dev_err(dev->dev, "underrun while writing\n");
- return -EIO;
+ ret = -EIO;
+ goto error;
}
dev_dbg(dev->dev, "transfer complete\n");
return 0;
+
+error:
+ at91_twi_dma_cleanup(dev);
+ return ret;
}
static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num)
@@ -328,36 +521,42 @@ static struct at91_twi_pdata at91rm9200_config = {
.clk_max_div = 5,
.clk_offset = 3,
.has_unre_flag = true,
+ .has_dma_support = false,
};
static struct at91_twi_pdata at91sam9261_config = {
.clk_max_div = 5,
.clk_offset = 4,
.has_unre_flag = false,
+ .has_dma_support = false,
};
static struct at91_twi_pdata at91sam9260_config = {
.clk_max_div = 7,
.clk_offset = 4,
.has_unre_flag = false,
+ .has_dma_support = false,
};
static struct at91_twi_pdata at91sam9g20_config = {
.clk_max_div = 7,
.clk_offset = 4,
.has_unre_flag = false,
+ .has_dma_support = false,
};
static struct at91_twi_pdata at91sam9g10_config = {
.clk_max_div = 7,
.clk_offset = 4,
.has_unre_flag = false,
+ .has_dma_support = false,
};
static struct at91_twi_pdata at91sam9x5_config = {
.clk_max_div = 7,
.clk_offset = 4,
.has_unre_flag = false,
+ .has_dma_support = true,
};
static const struct platform_device_id at91_twi_devtypes[] = {
@@ -404,6 +603,90 @@ MODULE_DEVICE_TABLE(of, atmel_twi_dt_ids);
#define atmel_twi_dt_ids NULL
#endif
+static bool __devinit filter(struct dma_chan *chan, void *slave)
+{
+ struct at_dma_slave *sl = slave;
+
+ if (sl->dma_dev == chan->device->dev) {
+ chan->private = sl;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+static int __devinit at91_twi_configure_dma(struct at91_twi_dev *dev, u32 phy_addr)
+{
+ int ret = 0;
+ struct at_dma_slave *sdata;
+ struct dma_slave_config slave_config;
+ struct at91_twi_dma *dma = &dev->dma;
+
+ sdata = &dev->pdata->dma_slave;
+
+ memset(&slave_config, 0, sizeof(slave_config));
+ slave_config.src_addr = (dma_addr_t)phy_addr + AT91_TWI_RHR;
+ slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ slave_config.src_maxburst = 1;
+ slave_config.dst_addr = (dma_addr_t)phy_addr + AT91_TWI_THR;
+ slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ slave_config.dst_maxburst = 1;
+ slave_config.device_fc = false;
+
+ if (sdata && sdata->dma_dev) {
+ dma_cap_mask_t mask;
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ dma->chan_tx = dma_request_channel(mask, filter, sdata);
+ if (!dma->chan_tx) {
+ dev_err(dev->dev, "no DMA channel available for tx\n");
+ ret = -EBUSY;
+ goto error;
+ }
+ dma->chan_rx = dma_request_channel(mask, filter, sdata);
+ if (!dma->chan_rx) {
+ dev_err(dev->dev, "no DMA channel available for rx\n");
+ ret = -EBUSY;
+ goto error;
+ }
+ } else {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ slave_config.direction = DMA_MEM_TO_DEV;
+ if (dmaengine_slave_config(dma->chan_tx, &slave_config)) {
+ dev_err(dev->dev, "failed to configure tx channel\n");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ slave_config.direction = DMA_DEV_TO_MEM;
+ if (dmaengine_slave_config(dma->chan_rx, &slave_config)) {
+ dev_err(dev->dev, "failed to configure rx channel\n");
+ ret = -EINVAL;
+ goto error;
+ }
+
+ sg_init_table(&dma->sg, 1);
+ dma->buf_mapped = false;
+ dma->xfer_in_progress = false;
+
+ dev_info(dev->dev, "using %s (tx) and %s (rx) for DMA transfers\n",
+ dma_chan_name(dma->chan_tx), dma_chan_name(dma->chan_rx));
+
+ return ret;
+
+error:
+ dev_info(dev->dev, "can't use DMA\n");
+ if (dma->chan_rx)
+ dma_release_channel(dma->chan_rx);
+ if (dma->chan_tx)
+ dma_release_channel(dma->chan_tx);
+ return ret;
+}
+
static struct at91_twi_pdata * __devinit at91_twi_get_driver_data(
struct platform_device *pdev)
{
@@ -422,6 +705,7 @@ static int __devinit at91_twi_probe(struct platform_device *pdev)
struct at91_twi_dev *dev;
struct resource *mem;
int rc;
+ u32 phy_addr;
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
if (!dev)
@@ -432,6 +716,7 @@ static int __devinit at91_twi_probe(struct platform_device *pdev)
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem)
return -ENODEV;
+ phy_addr = mem->start;
dev->pdata = at91_twi_get_driver_data(pdev);
if (!dev->pdata)
@@ -461,6 +746,11 @@ static int __devinit at91_twi_probe(struct platform_device *pdev)
}
clk_prepare_enable(dev->clk);
+ if (dev->pdata->has_dma_support) {
+ if (at91_twi_configure_dma(dev, phy_addr) == 0)
+ dev->use_dma = true;
+ }
+
at91_calc_twi_clock(dev, TWI_CLK_HZ);
at91_init_twi_bus(dev);
--
1.7.11.3
^ permalink raw reply related
* [PATCH v3] i2c: omap: ensure writes to dev->buf_len are ordered
From: Wolfram Sang @ 2012-11-14 16:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1352902965-25666-1-git-send-email-balbi@ti.com>
On Wed, Nov 14, 2012 at 04:22:45PM +0200, Felipe Balbi wrote:
> if we allow compiler reorder our writes, we could
> fall into a situation where dev->buf_len is reset
> for no apparent reason.
>
> This bug was found with a simple script which would
> transfer data to an i2c client from 1 to 1024 bytes
> (a simple for loop), when we got to transfer sizes
> bigger than the fifo size, dev->buf_len was reset
> to zero before we had an oportunity to handle XDR
> Interrupt. Because dev->buf_len was zero, we entered
> omap_i2c_transmit_data() to transfer zero bytes,
> which would mean we would just silently exit
> omap_i2c_transmit_data() without actually writing
> anything to DATA register. That would cause XDR
> IRQ to trigger forever and we would never transfer
> the remaining bytes.
>
> After adding the memory barrier, we also drop resetting
> dev->buf_len to zero in omap_i2c_xfer_msg() because
> both omap_i2c_transmit_data() and omap_i2c_receive_data()
> will act until dev->buf_len reaches zero, rendering the
> other write in omap_i2c_xfer_msg() redundant.
>
> This patch has been tested with pandaboard for a few
> iterations of the script mentioned above.
>
> Signed-off-by: Felipe Balbi <balbi@ti.com>
Applied to for-current, thanks!
--
Pengutronix e.K. | Wolfram Sang |
Industrial Linux Solutions | http://www.pengutronix.de/ |
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 198 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121114/0b0eb476/attachment.sig>
^ permalink raw reply
* [PATCH v3 7/7] crypto: omap_sham: Remove usage of private DMA API
From: Mark A. Greer @ 2012-11-14 16:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CALLzPKZ0qC-mm4tLsywzGi7jtnK8aSQcbW5sGxr2Z1g6hyBpsA@mail.gmail.com>
On Tue, Nov 13, 2012 at 11:47:57PM -0800, Kasatkin, Dmitry wrote:
> On Fri, Nov 9, 2012 at 9:17 AM, Mark A. Greer <mgreer@animalcreek.com> wrote:
> > On Fri, Nov 09, 2012 at 06:28:16PM +0200, Kasatkin, Dmitry wrote:
> >> On Wed, Nov 7, 2012 at 4:57 AM, Mark A. Greer <mgreer@animalcreek.com> wrote:
> >> > From: "Mark A. Greer" <mgreer@animalcreek.com>
> >> >
> >> > Remove usage of the private OMAP DMA API.
> >> > The dmaengine API will be used instead.
> >> >
> >> > CC: Russell King <rmk+kernel@arm.linux.org.uk>
> >> > CC: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
> >> > Signed-off-by: Mark A. Greer <mgreer@animalcreek.com>
> >> > ---
> >> > drivers/crypto/omap-sham.c | 117 ---------------------------------------------
> >> > 1 file changed, 117 deletions(-)
> >> >
> >> > diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c
> >> > index b57277c..ebb5255 100644
> >> > --- a/drivers/crypto/omap-sham.c
> >> > +++ b/drivers/crypto/omap-sham.c
> >
> >> > @@ -807,18 +762,6 @@ static int omap_sham_handle_queue(struct omap_sham_dev *dd,
> >> > if (err)
> >> > goto err1;
> >> >
> >> > -#ifdef OMAP_SHAM_DMA_PRIVATE
> >> > - omap_set_dma_dest_params(dd->dma_lch, 0,
> >> > - OMAP_DMA_AMODE_CONSTANT,
> >> > - dd->phys_base + SHA_REG_DIN(0), 0, 16);
> >> > -
> >> > - omap_set_dma_dest_burst_mode(dd->dma_lch,
> >> > - OMAP_DMA_DATA_BURST_16);
> >> > -
> >> > - omap_set_dma_src_burst_mode(dd->dma_lch,
> >> > - OMAP_DMA_DATA_BURST_4);
> >>
> >> Burst mode significantly improves performance.
> >> How do you configure burst mode with new API?
> >
> > This is (or should be) taken care of by the dmaengine infrastructure.
> > I've noted that there's an issue and there is a discussion about it
> > here:
> >
> > http://www.spinics.net/lists/linux-omap/msg79855.html
> >
> > We probably need to extend the dmaengine API to allow API-users to
> > request specific tweaks/optimizations/whatever but that's MHO.
> >
>
> Hello,
>
> I am in favor of new APIs.
> The only my concern is that it performs worse..
>
> Is it possible to keep burst mode setting there?
I'm going to respin the patch the I posted in the email thread above
to only set bursting for non-cyclic DMAs.
Mark
--
^ permalink raw reply
* OMAP* Latest build failures
From: Tony Lindgren @ 2012-11-14 16:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <50A3844B.8040208@ti.com>
* Tomi Valkeinen <tomi.valkeinen@ti.com> [121114 03:47]:
> On 2012-11-14 11:26, Russell King - ARM Linux wrote:
> > OMAP* allnoconfig fails:
> >
> > arch/arm/mach-omap2/built-in.o: In function `omap_dss_set_min_bus_tput':
> > twl-common.c:(.text+0x1e08): undefined reference to `omap_pm_set_min_bus_tput'
> > arch/arm/mach-omap2/built-in.o: In function `omap_hwmod_init_postsetup':
> > twl-common.c:(.init.text+0x8f8): undefined reference to `omap_pm_if_early_init'
> > arch/arm/mach-omap2/built-in.o: In function `omap_serial_init_port':
> > twl-common.c:(.init.text+0x1284): undefined reference to `omap_pm_get_dev_context_loss_count'
> > arch/arm/mach-omap2/built-in.o: In function `omap_timer_init':
> > twl-common.c:(.init.text+0x1544): undefined reference to `omap_pm_get_dev_context_loss_count'
> > arch/arm/mach-omap2/built-in.o: In function `omap2_common_pm_init':
> > twl-common.c:(.init.text+0x1af0): undefined reference to `omap_pm_if_init'
> > arch/arm/mach-omap2/built-in.o: In function `omap2_gpio_dev_init':
> > twl-common.c:(.init.text+0x2168): undefined reference to `omap_pm_get_dev_context_loss_count'
> > arch/arm/mach-omap2/built-in.o: In function `omap_display_init':
> > twl-common.c:(.init.text+0x25cc): undefined reference to `omap_pm_get_dev_context_loss_count'
>
> I'm not able to reproduce this. I took v3.7-rc5, and the omap4430-sdp
> noconfig
> (http://www.arm.linux.org.uk/developer/build/file.php?type=config&idx=2711),
> and it builds fine for me.
It happens if in arm-soc/for-next and rmk/for-next. Looks like the
CONFIG_OMAP_PM_NOOP can't be under CONFIG_PM in the makefile where I moved it
in commit 6e740f9a8.
Looks like in my test configs I run make oldnoconfig on Russell's seed
config, and I do get CONFIG_PM=y set while Russell's generated config
does not have that. No ideas yet why oldnoconfig add CONFIG_PM=y..
Anyways, patch below to make it behave like earlier.
Regards,
Tony
From: Tony Lindgren <tony@atomide.com>
Date: Wed, 14 Nov 2012 08:40:00 -0800
Subject: [PATCH] ARM: OMAP: Fix compile for OMAP_PM_NOOP if PM is not selected
Commit 6e740f9a8 (ARM: OMAP: Move omap-pm-noop.c local to mach-omap2)
moved omap-pm-noop to be local to mach-omap2. However, the makefile
entry got placed within ifeq ($(CONFIG_PM),y) which was not the
case earlier.
Fix the issue by moving it out of the ifeq ($(CONFIG_PM),y) in
the makefile as these stubs are needed also when PM is not set.
Reported-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Tony Lindgren <tony@atomide.com>
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -68,6 +68,8 @@ obj-$(CONFIG_ARCH_OMAP4) += opp4xxx_data.o
endif
# Power Management
+obj-$(CONFIG_OMAP_PM_NOOP) += omap-pm-noop.o
+
ifeq ($(CONFIG_PM),y)
obj-$(CONFIG_ARCH_OMAP2) += pm24xx.o
obj-$(CONFIG_ARCH_OMAP2) += sleep24xx.o
@@ -75,7 +77,6 @@ obj-$(CONFIG_ARCH_OMAP3) += pm34xx.o sleep34xx.o
obj-$(CONFIG_ARCH_OMAP4) += pm44xx.o omap-mpuss-lowpower.o
obj-$(CONFIG_SOC_OMAP5) += omap-mpuss-lowpower.o
obj-$(CONFIG_PM_DEBUG) += pm-debug.o
-obj-$(CONFIG_OMAP_PM_NOOP) += omap-pm-noop.o
obj-$(CONFIG_POWER_AVS_OMAP) += sr_device.o
obj-$(CONFIG_POWER_AVS_OMAP_CLASS3) += smartreflex-class3.o
^ permalink raw reply
* [RFC PATCH 0/3] introduce static_vm for ARM-specific static mapped area
From: Joonsoo Kim @ 2012-11-14 16:55 UTC (permalink / raw)
To: linux-arm-kernel
In current implementation, we used ARM-specific flag, that is,
VM_ARM_STATIC_MAPPING, for distinguishing ARM specific static mapped area.
The purpose of static mapped area is to re-use static mapped area when
entire physical address range of the ioremap request can be covered
by this area.
This implementation causes needless overhead for some cases.
We unnecessarily iterate vmlist for finding matched area even if there
is no static mapped area. And if there are some static mapped areas,
iterating whole vmlist is not preferable.
In fact, it is not a critical problem, because ioremap is not frequently
used. But reducing overhead is better idea.
Another reason for doing this work is for removing architecture dependency
on vmalloc layer. I think that vmlist and vmlist_lock is internal data
structure for vmalloc layer. Some codes for debugging and stat inevitably
use vmlist and vmlist_lock. But it is preferable that they are used outside
of vmalloc.c as least as possible.
In the near future, I will try to remove other architecture dependency on
vmalloc layer.
This is just RFC patch and I did compile-test only.
If you have any good suggestion, please let me know.
These are based on v3.7-rc5.
Thanks.
Joonsoo Kim (3):
ARM: vmregion: remove vmregion code entirely
ARM: static_vm: introduce an infrastructure for static mapped area
ARM: mm: use static_vm for managing static mapped areas
arch/arm/include/asm/mach/static_vm.h | 51 ++++++++
arch/arm/mm/Makefile | 2 +-
arch/arm/mm/ioremap.c | 69 ++++-------
arch/arm/mm/mm.h | 10 --
arch/arm/mm/mmu.c | 55 +++++----
arch/arm/mm/static_vm.c | 97 ++++++++++++++++
arch/arm/mm/vmregion.c | 205 ---------------------------------
arch/arm/mm/vmregion.h | 31 -----
8 files changed, 208 insertions(+), 312 deletions(-)
create mode 100644 arch/arm/include/asm/mach/static_vm.h
create mode 100644 arch/arm/mm/static_vm.c
delete mode 100644 arch/arm/mm/vmregion.c
delete mode 100644 arch/arm/mm/vmregion.h
--
1.7.9.5
^ permalink raw reply
* [RFC PATCH 1/3] ARM: vmregion: remove vmregion code entirely
From: Joonsoo Kim @ 2012-11-14 16:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1352912154-16210-1-git-send-email-js1304@gmail.com>
Now, there is no user for vmregion.
So remove it.
Signed-off-by: Joonsoo Kim <js1304@gmail.com>
diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
index 8a9c4cb..4e333fa 100644
--- a/arch/arm/mm/Makefile
+++ b/arch/arm/mm/Makefile
@@ -6,7 +6,7 @@ obj-y := dma-mapping.o extable.o fault.o init.o \
iomap.o
obj-$(CONFIG_MMU) += fault-armv.o flush.o idmap.o ioremap.o \
- mmap.o pgd.o mmu.o vmregion.o
+ mmap.o pgd.o mmu.o
ifneq ($(CONFIG_MMU),y)
obj-y += nommu.o
diff --git a/arch/arm/mm/vmregion.c b/arch/arm/mm/vmregion.c
deleted file mode 100644
index a631016..0000000
--- a/arch/arm/mm/vmregion.c
+++ /dev/null
@@ -1,205 +0,0 @@
-#include <linux/fs.h>
-#include <linux/spinlock.h>
-#include <linux/list.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-
-#include "vmregion.h"
-
-/*
- * VM region handling support.
- *
- * This should become something generic, handling VM region allocations for
- * vmalloc and similar (ioremap, module space, etc).
- *
- * I envisage vmalloc()'s supporting vm_struct becoming:
- *
- * struct vm_struct {
- * struct vmregion region;
- * unsigned long flags;
- * struct page **pages;
- * unsigned int nr_pages;
- * unsigned long phys_addr;
- * };
- *
- * get_vm_area() would then call vmregion_alloc with an appropriate
- * struct vmregion head (eg):
- *
- * struct vmregion vmalloc_head = {
- * .vm_list = LIST_HEAD_INIT(vmalloc_head.vm_list),
- * .vm_start = VMALLOC_START,
- * .vm_end = VMALLOC_END,
- * };
- *
- * However, vmalloc_head.vm_start is variable (typically, it is dependent on
- * the amount of RAM found at boot time.) I would imagine that get_vm_area()
- * would have to initialise this each time prior to calling vmregion_alloc().
- */
-
-struct arm_vmregion *
-arm_vmregion_alloc(struct arm_vmregion_head *head, size_t align,
- size_t size, gfp_t gfp, const void *caller)
-{
- unsigned long start = head->vm_start, addr = head->vm_end;
- unsigned long flags;
- struct arm_vmregion *c, *new;
-
- if (head->vm_end - head->vm_start < size) {
- printk(KERN_WARNING "%s: allocation too big (requested %#x)\n",
- __func__, size);
- goto out;
- }
-
- new = kmalloc(sizeof(struct arm_vmregion), gfp);
- if (!new)
- goto out;
-
- new->caller = caller;
-
- spin_lock_irqsave(&head->vm_lock, flags);
-
- addr = rounddown(addr - size, align);
- list_for_each_entry_reverse(c, &head->vm_list, vm_list) {
- if (addr >= c->vm_end)
- goto found;
- addr = rounddown(c->vm_start - size, align);
- if (addr < start)
- goto nospc;
- }
-
- found:
- /*
- * Insert this entry after the one we found.
- */
- list_add(&new->vm_list, &c->vm_list);
- new->vm_start = addr;
- new->vm_end = addr + size;
- new->vm_active = 1;
-
- spin_unlock_irqrestore(&head->vm_lock, flags);
- return new;
-
- nospc:
- spin_unlock_irqrestore(&head->vm_lock, flags);
- kfree(new);
- out:
- return NULL;
-}
-
-static struct arm_vmregion *__arm_vmregion_find(struct arm_vmregion_head *head, unsigned long addr)
-{
- struct arm_vmregion *c;
-
- list_for_each_entry(c, &head->vm_list, vm_list) {
- if (c->vm_active && c->vm_start == addr)
- goto out;
- }
- c = NULL;
- out:
- return c;
-}
-
-struct arm_vmregion *arm_vmregion_find(struct arm_vmregion_head *head, unsigned long addr)
-{
- struct arm_vmregion *c;
- unsigned long flags;
-
- spin_lock_irqsave(&head->vm_lock, flags);
- c = __arm_vmregion_find(head, addr);
- spin_unlock_irqrestore(&head->vm_lock, flags);
- return c;
-}
-
-struct arm_vmregion *arm_vmregion_find_remove(struct arm_vmregion_head *head, unsigned long addr)
-{
- struct arm_vmregion *c;
- unsigned long flags;
-
- spin_lock_irqsave(&head->vm_lock, flags);
- c = __arm_vmregion_find(head, addr);
- if (c)
- c->vm_active = 0;
- spin_unlock_irqrestore(&head->vm_lock, flags);
- return c;
-}
-
-void arm_vmregion_free(struct arm_vmregion_head *head, struct arm_vmregion *c)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&head->vm_lock, flags);
- list_del(&c->vm_list);
- spin_unlock_irqrestore(&head->vm_lock, flags);
-
- kfree(c);
-}
-
-#ifdef CONFIG_PROC_FS
-static int arm_vmregion_show(struct seq_file *m, void *p)
-{
- struct arm_vmregion *c = list_entry(p, struct arm_vmregion, vm_list);
-
- seq_printf(m, "0x%08lx-0x%08lx %7lu", c->vm_start, c->vm_end,
- c->vm_end - c->vm_start);
- if (c->caller)
- seq_printf(m, " %pS", (void *)c->caller);
- seq_putc(m, '\n');
- return 0;
-}
-
-static void *arm_vmregion_start(struct seq_file *m, loff_t *pos)
-{
- struct arm_vmregion_head *h = m->private;
- spin_lock_irq(&h->vm_lock);
- return seq_list_start(&h->vm_list, *pos);
-}
-
-static void *arm_vmregion_next(struct seq_file *m, void *p, loff_t *pos)
-{
- struct arm_vmregion_head *h = m->private;
- return seq_list_next(p, &h->vm_list, pos);
-}
-
-static void arm_vmregion_stop(struct seq_file *m, void *p)
-{
- struct arm_vmregion_head *h = m->private;
- spin_unlock_irq(&h->vm_lock);
-}
-
-static const struct seq_operations arm_vmregion_ops = {
- .start = arm_vmregion_start,
- .stop = arm_vmregion_stop,
- .next = arm_vmregion_next,
- .show = arm_vmregion_show,
-};
-
-static int arm_vmregion_open(struct inode *inode, struct file *file)
-{
- struct arm_vmregion_head *h = PDE(inode)->data;
- int ret = seq_open(file, &arm_vmregion_ops);
- if (!ret) {
- struct seq_file *m = file->private_data;
- m->private = h;
- }
- return ret;
-}
-
-static const struct file_operations arm_vmregion_fops = {
- .open = arm_vmregion_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release,
-};
-
-int arm_vmregion_create_proc(const char *path, struct arm_vmregion_head *h)
-{
- proc_create_data(path, S_IRUSR, NULL, &arm_vmregion_fops, h);
- return 0;
-}
-#else
-int arm_vmregion_create_proc(const char *path, struct arm_vmregion_head *h)
-{
- return 0;
-}
-#endif
diff --git a/arch/arm/mm/vmregion.h b/arch/arm/mm/vmregion.h
deleted file mode 100644
index 0f5a5f2..0000000
--- a/arch/arm/mm/vmregion.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef VMREGION_H
-#define VMREGION_H
-
-#include <linux/spinlock.h>
-#include <linux/list.h>
-
-struct page;
-
-struct arm_vmregion_head {
- spinlock_t vm_lock;
- struct list_head vm_list;
- unsigned long vm_start;
- unsigned long vm_end;
-};
-
-struct arm_vmregion {
- struct list_head vm_list;
- unsigned long vm_start;
- unsigned long vm_end;
- int vm_active;
- const void *caller;
-};
-
-struct arm_vmregion *arm_vmregion_alloc(struct arm_vmregion_head *, size_t, size_t, gfp_t, const void *);
-struct arm_vmregion *arm_vmregion_find(struct arm_vmregion_head *, unsigned long);
-struct arm_vmregion *arm_vmregion_find_remove(struct arm_vmregion_head *, unsigned long);
-void arm_vmregion_free(struct arm_vmregion_head *, struct arm_vmregion *);
-
-int arm_vmregion_create_proc(const char *, struct arm_vmregion_head *);
-
-#endif
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH 2/3] ARM: static_vm: introduce an infrastructure for static mapped area
From: Joonsoo Kim @ 2012-11-14 16:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1352912154-16210-1-git-send-email-js1304@gmail.com>
In current implementation, we used ARM-specific flag, that is,
VM_ARM_STATIC_MAPPING, for distinguishing ARM specific static mapped area.
The purpose of static mapped area is to re-use static mapped area when
entire physical address range of the ioremap request can be covered
by this area.
This implementation causes needless overhead for some cases.
We unnecessarily iterate vmlist for finding matched area even if there
is no static mapped area. And if there are some static mapped areas,
iterating whole vmlist is not preferable.
In fact, it is not a critical problem, because ioremap is not frequently
used. But reducing overhead is better idea.
Another reason for doing this work is for removing architecture dependency
on vmalloc layer. I think that vmlist and vmlist_lock is internal data
structure for vmalloc layer. Some codes for debugging and stat inevitably
use vmlist and vmlist_lock. But it is preferable that they are used outside
of vmalloc.c as least as possible.
Now, I introduce an ARM-specific infrastructure for static mapped area. In
the following patch, we will use this and resolve above mentioned problem.
Signed-off-by: Joonsoo Kim <js1304@gmail.com>
diff --git a/arch/arm/include/asm/mach/static_vm.h b/arch/arm/include/asm/mach/static_vm.h
new file mode 100644
index 0000000..1bb6604
--- /dev/null
+++ b/arch/arm/include/asm/mach/static_vm.h
@@ -0,0 +1,45 @@
+/*
+ * arch/arm/include/asm/mach/static_vm.h
+ *
+ * Copyright (C) 2012 LG Electronics, Joonsoo Kim <js1304@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _ASM_MACH_STATIC_VM_H
+#define _ASM_MACH_STATIC_VM_H
+
+#include <linux/types.h>
+#include <linux/vmalloc.h>
+
+struct static_vm {
+ struct static_vm *next;
+ void *vaddr;
+ unsigned long size;
+ unsigned long flags;
+ phys_addr_t paddr;
+ const void *caller;
+};
+
+extern struct static_vm *static_vmlist;
+extern spinlock_t static_vmlist_lock;
+
+extern struct static_vm *find_static_vm_paddr(phys_addr_t paddr,
+ size_t size, unsigned long flags);
+extern struct static_vm *find_static_vm_vaddr(void *vaddr, unsigned long flags);
+extern void init_static_vm(struct static_vm *static_vm,
+ struct vm_struct *vm, unsigned long flags);
+extern void insert_static_vm(struct static_vm *vm);
+
+#endif /* _ASM_MACH_STATIC_VM_H */
diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
index 4e333fa..57b329a 100644
--- a/arch/arm/mm/Makefile
+++ b/arch/arm/mm/Makefile
@@ -6,7 +6,7 @@ obj-y := dma-mapping.o extable.o fault.o init.o \
iomap.o
obj-$(CONFIG_MMU) += fault-armv.o flush.o idmap.o ioremap.o \
- mmap.o pgd.o mmu.o
+ mmap.o pgd.o mmu.o static_vm.o
ifneq ($(CONFIG_MMU),y)
obj-y += nommu.o
diff --git a/arch/arm/mm/static_vm.c b/arch/arm/mm/static_vm.c
new file mode 100644
index 0000000..d7677cf
--- /dev/null
+++ b/arch/arm/mm/static_vm.c
@@ -0,0 +1,97 @@
+/*
+ * arch/arm/mm/static_vm.c
+ *
+ * Copyright (C) 2012 LG Electronics, Joonsoo Kim <js1304@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/spinlock.h>
+
+#include <asm/mach/static_vm.h>
+
+struct static_vm *static_vmlist;
+DEFINE_SPINLOCK(static_vmlist_lock);
+
+struct static_vm *find_static_vm_paddr(phys_addr_t paddr,
+ size_t size, unsigned long flags)
+{
+ struct static_vm *area;
+
+ spin_lock(&static_vmlist_lock);
+ for (area = static_vmlist; area; area = area->next) {
+ if ((area->flags & flags) != flags)
+ continue;
+
+ if (area->paddr > paddr ||
+ paddr + size - 1 > area->paddr + area->size - 1)
+ continue;
+
+ spin_unlock(&static_vmlist_lock);
+ return area;
+ }
+ spin_unlock(&static_vmlist_lock);
+
+ return NULL;
+}
+
+struct static_vm *find_static_vm_vaddr(void *vaddr, unsigned long flags)
+{
+ struct static_vm *area;
+
+ spin_lock(&static_vmlist_lock);
+ for (area = static_vmlist; area; area = area->next) {
+ /* static_vmlist is ascending order */
+ if (area->vaddr > vaddr)
+ break;
+
+ if ((area->flags & flags) != flags)
+ continue;
+
+ if (area->vaddr <= vaddr && area->vaddr + area->size > vaddr) {
+ spin_unlock(&static_vmlist_lock);
+ return area;
+ }
+ }
+ spin_unlock(&static_vmlist_lock);
+
+ return NULL;
+}
+
+void init_static_vm(struct static_vm *static_vm,
+ struct vm_struct *vm, unsigned long flags)
+{
+ static_vm->vaddr = vm->addr;
+ static_vm->size = vm->size;
+ static_vm->paddr = vm->phys_addr;
+ static_vm->caller = vm->caller;
+ static_vm->flags = flags;
+}
+
+void insert_static_vm(struct static_vm *vm)
+{
+ struct static_vm *tmp, **p;
+
+ spin_lock(&static_vmlist_lock);
+ for (p = &static_vmlist; (tmp = *p) != NULL; p = &tmp->next) {
+ if (tmp->vaddr >= vm->vaddr) {
+ BUG_ON(tmp->vaddr < vm->vaddr + vm->size);
+ break;
+ } else
+ BUG_ON(tmp->vaddr + tmp->size > vm->vaddr);
+ }
+ vm->next = *p;
+ *p = vm;
+ spin_unlock(&static_vmlist_lock);
+}
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH 3/3] ARM: mm: use static_vm for managing static mapped areas
From: Joonsoo Kim @ 2012-11-14 16:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1352912154-16210-1-git-send-email-js1304@gmail.com>
A static mapped area is ARM-specific, so it is better not to use
generic vmalloc data structure, that is, vmlist and vmlist_lock
for managing static mapped area. And it causes some needless overhead and
reducing this overhead is better idea.
Now, we have newly introduced static_vm infrastructure.
With it, we don't need to iterate all mapped areas. Instead, we just
iterate static mapped areas. It helps to reduce an overhead of finding
matched area. And architecture dependency on vmalloc layer is removed,
so it will help to maintainability for vmalloc layer.
Signed-off-by: Joonsoo Kim <js1304@gmail.com>
diff --git a/arch/arm/include/asm/mach/static_vm.h b/arch/arm/include/asm/mach/static_vm.h
index 1bb6604..0d9c685 100644
--- a/arch/arm/include/asm/mach/static_vm.h
+++ b/arch/arm/include/asm/mach/static_vm.h
@@ -32,6 +32,12 @@ struct static_vm {
const void *caller;
};
+#define STATIC_VM_MEM 0x00000001
+#define STATIC_VM_EMPTY 0x00000002
+
+/* mtype should be less than 28 */
+#define STATIC_VM_MTYPE(mt) (1UL << ((mt) + 4))
+
extern struct static_vm *static_vmlist;
extern spinlock_t static_vmlist_lock;
diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c
index 5dcc2fd..b7f3c27 100644
--- a/arch/arm/mm/ioremap.c
+++ b/arch/arm/mm/ioremap.c
@@ -36,6 +36,7 @@
#include <asm/system_info.h>
#include <asm/mach/map.h>
+#include <asm/mach/static_vm.h>
#include <asm/mach/pci.h>
#include "mm.h"
@@ -197,7 +198,8 @@ void __iomem * __arm_ioremap_pfn_caller(unsigned long pfn,
const struct mem_type *type;
int err;
unsigned long addr;
- struct vm_struct * area;
+ struct vm_struct *area;
+ phys_addr_t paddr = __pfn_to_phys(pfn);
#ifndef CONFIG_ARM_LPAE
/*
@@ -219,24 +221,17 @@ void __iomem * __arm_ioremap_pfn_caller(unsigned long pfn,
/*
* Try to reuse one of the static mapping whenever possible.
*/
- read_lock(&vmlist_lock);
- for (area = vmlist; area; area = area->next) {
- if (!size || (sizeof(phys_addr_t) == 4 && pfn >= 0x100000))
- break;
- if (!(area->flags & VM_ARM_STATIC_MAPPING))
- continue;
- if ((area->flags & VM_ARM_MTYPE_MASK) != VM_ARM_MTYPE(mtype))
- continue;
- if (__phys_to_pfn(area->phys_addr) > pfn ||
- __pfn_to_phys(pfn) + size-1 > area->phys_addr + area->size-1)
- continue;
- /* we can drop the lock here as we know *area is static */
- read_unlock(&vmlist_lock);
- addr = (unsigned long)area->addr;
- addr += __pfn_to_phys(pfn) - area->phys_addr;
- return (void __iomem *) (offset + addr);
+ if (size && !((sizeof(phys_addr_t) == 4 && pfn >= 0x100000))) {
+ struct static_vm *static_vm;
+
+ static_vm = find_static_vm_paddr(__pfn_to_phys(pfn), size,
+ STATIC_VM_MEM | STATIC_VM_MTYPE(mtype));
+ if (static_vm) {
+ addr = (unsigned long)static_vm->vaddr;
+ addr += paddr - static_vm->paddr;
+ return (void __iomem *) (offset + addr);
+ }
}
- read_unlock(&vmlist_lock);
/*
* Don't allow RAM to be mapped - this causes problems with ARMv6+
@@ -248,7 +243,7 @@ void __iomem * __arm_ioremap_pfn_caller(unsigned long pfn,
if (!area)
return NULL;
addr = (unsigned long)area->addr;
- area->phys_addr = __pfn_to_phys(pfn);
+ area->phys_addr = paddr;
#if !defined(CONFIG_SMP) && !defined(CONFIG_ARM_LPAE)
if (DOMAIN_IO == 0 &&
@@ -346,34 +341,20 @@ __arm_ioremap_exec(unsigned long phys_addr, size_t size, bool cached)
void __iounmap(volatile void __iomem *io_addr)
{
void *addr = (void *)(PAGE_MASK & (unsigned long)io_addr);
- struct vm_struct *vm;
-
- read_lock(&vmlist_lock);
- for (vm = vmlist; vm; vm = vm->next) {
- if (vm->addr > addr)
- break;
- if (!(vm->flags & VM_IOREMAP))
- continue;
- /* If this is a static mapping we must leave it alone */
- if ((vm->flags & VM_ARM_STATIC_MAPPING) &&
- (vm->addr <= addr) && (vm->addr + vm->size > addr)) {
- read_unlock(&vmlist_lock);
- return;
- }
+ struct static_vm *static_vm;
+
+ static_vm = find_static_vm_vaddr(addr, STATIC_VM_MEM);
+ if (static_vm)
+ return;
+
#if !defined(CONFIG_SMP) && !defined(CONFIG_ARM_LPAE)
- /*
- * If this is a section based mapping we need to handle it
- * specially as the VM subsystem does not know how to handle
- * such a beast.
- */
- if ((vm->addr == addr) &&
- (vm->flags & VM_ARM_SECTION_MAPPING)) {
+ {
+ struct vm_struct *vm;
+ vm = find_vm_area(addr);
+ if (vm && (vm->flags & VM_ARM_SECTION_MAPPING))
unmap_area_sections((unsigned long)vm->addr, vm->size);
- break;
- }
-#endif
}
- read_unlock(&vmlist_lock);
+#endif
vunmap(addr);
}
diff --git a/arch/arm/mm/mm.h b/arch/arm/mm/mm.h
index a8ee92d..3ae75e5 100644
--- a/arch/arm/mm/mm.h
+++ b/arch/arm/mm/mm.h
@@ -52,16 +52,6 @@ extern void __flush_dcache_page(struct address_space *mapping, struct page *page
/* (super)section-mapped I/O regions used by ioremap()/iounmap() */
#define VM_ARM_SECTION_MAPPING 0x80000000
-/* permanent static mappings from iotable_init() */
-#define VM_ARM_STATIC_MAPPING 0x40000000
-
-/* empty mapping */
-#define VM_ARM_EMPTY_MAPPING 0x20000000
-
-/* mapping type (attributes) for permanent static mappings */
-#define VM_ARM_MTYPE(mt) ((mt) << 20)
-#define VM_ARM_MTYPE_MASK (0x1f << 20)
-
/* consistent regions used by dma_alloc_attrs() */
#define VM_ARM_DMA_CONSISTENT 0x20000000
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 941dfb9..6c154c1 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -31,6 +31,7 @@
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
+#include <asm/mach/static_vm.h>
#include <asm/mach/pci.h>
#include "mm.h"
@@ -757,21 +758,28 @@ void __init iotable_init(struct map_desc *io_desc, int nr)
{
struct map_desc *md;
struct vm_struct *vm;
+ struct static_vm *static_vm;
if (!nr)
return;
vm = early_alloc_aligned(sizeof(*vm) * nr, __alignof__(*vm));
+ static_vm = early_alloc_aligned(sizeof(*static_vm) * nr,
+ __alignof__(*static_vm));
for (md = io_desc; nr; md++, nr--) {
create_mapping(md);
+
vm->addr = (void *)(md->virtual & PAGE_MASK);
vm->size = PAGE_ALIGN(md->length + (md->virtual & ~PAGE_MASK));
vm->phys_addr = __pfn_to_phys(md->pfn);
- vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING;
- vm->flags |= VM_ARM_MTYPE(md->type);
+ vm->flags = VM_IOREMAP;
vm->caller = iotable_init;
+
+ init_static_vm(static_vm, vm, STATIC_VM_MEM |
+ STATIC_VM_MTYPE(md->type));
vm_area_add_early(vm++);
+ insert_static_vm(static_vm++);
}
}
@@ -779,13 +787,20 @@ void __init vm_reserve_area_early(unsigned long addr, unsigned long size,
void *caller)
{
struct vm_struct *vm;
+ struct static_vm *static_vm;
vm = early_alloc_aligned(sizeof(*vm), __alignof__(*vm));
+ static_vm = early_alloc_aligned(sizeof(*static_vm),
+ __alignof__(*static_vm));
+
vm->addr = (void *)addr;
vm->size = size;
- vm->flags = VM_IOREMAP | VM_ARM_EMPTY_MAPPING;
+ vm->flags = VM_IOREMAP;
vm->caller = caller;
+
+ init_static_vm(static_vm, vm, STATIC_VM_EMPTY);
vm_area_add_early(vm);
+ insert_static_vm(static_vm);
}
#ifndef CONFIG_ARM_LPAE
@@ -810,15 +825,19 @@ static void __init pmd_empty_section_gap(unsigned long addr)
static void __init fill_pmd_gaps(void)
{
- struct vm_struct *vm;
+ struct static_vm *area;
unsigned long addr, next = 0;
pmd_t *pmd;
- /* we're still single threaded hence no lock needed here */
- for (vm = vmlist; vm; vm = vm->next) {
- if (!(vm->flags & (VM_ARM_STATIC_MAPPING | VM_ARM_EMPTY_MAPPING)))
- continue;
- addr = (unsigned long)vm->addr;
+ /*
+ * We should not take a lock here, because pmd_empty_section_gap()
+ * invokes vm_reserve_area_early(), and then it call insert_static_vm()
+ * which try to take a lock.
+ * We're still single thread, so traverse whole list without a lock
+ * is safe for now. And inserting new entry is also safe.
+ */
+ for (area = static_vmlist; area; area = area->next) {
+ addr = (unsigned long)area->vaddr;
if (addr < next)
continue;
@@ -838,7 +857,7 @@ static void __init fill_pmd_gaps(void)
* If so and the second section entry for this PMD is empty
* then we block the corresponding virtual address.
*/
- addr += vm->size;
+ addr += area->size;
if ((addr & ~PMD_MASK) == SECTION_SIZE) {
pmd = pmd_off_k(addr) + 1;
if (pmd_none(*pmd))
@@ -857,19 +876,13 @@ static void __init fill_pmd_gaps(void)
#if defined(CONFIG_PCI) && !defined(CONFIG_NEED_MACH_IO_H)
static void __init pci_reserve_io(void)
{
- struct vm_struct *vm;
- unsigned long addr;
+ struct static_vm *static_vm;
- /* we're still single threaded hence no lock needed here */
- for (vm = vmlist; vm; vm = vm->next) {
- if (!(vm->flags & VM_ARM_STATIC_MAPPING))
- continue;
- addr = (unsigned long)vm->addr;
- addr &= ~(SZ_2M - 1);
- if (addr == PCI_IO_VIRT_BASE)
- return;
+ static_vm = find_static_vm_vaddr((void *)PCI_IO_VIRT_BASE,
+ STATIC_VM_MEM);
+ if (static_vm)
+ return;
- }
vm_reserve_area_early(PCI_IO_VIRT_BASE, SZ_2M, pci_reserve_io);
}
#else
--
1.7.9.5
^ permalink raw reply related
* [PATCH 0/8] I2C patches for v3.8 merge window
From: Wolfram Sang @ 2012-11-14 16:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAM=Q2ctS3hxngk5efcvScAdv-2GtH2pHRZoxRhRTiOWmQA-AXw@mail.gmail.com>
> >> here's another series for OMAP I2C driver. There are a few cleanups
> >> and one very nice new feature: we can now report how many bytes
> >> we transferred until NACK.
> >>
> >> Note that the implemementation for OMAP-I2C turned out to be a
> >> little more complex then I expected, mainly because of the way
> >> I2C_CNT register behaves and because of the very buggy register
> >> usage on that driver.
> >>
> >> I have boot tested all patches on beagle xM (3630) and pandaboard
> >> rev A3 (4430), will send boot-logs if anyone wants to see.
The series is a bit confusing mixing V1, V2 and V3 patches. Also, there
are a few comments unaddressed it seems to me (reading in hot path,
barriers). Please make sure these are properly handled and resend as a
seperate series (all patches V4). Bonus point if you rebase it to my
for-next, which I will push out soon.
--
Pengutronix e.K. | Wolfram Sang |
Industrial Linux Solutions | http://www.pengutronix.de/ |
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 198 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121114/abbaf878/attachment.sig>
^ permalink raw reply
* OMAP* Latest build failures
From: Tony Lindgren @ 2012-11-14 16:59 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20121114164801.GQ6801@atomide.com>
* Tony Lindgren <tony@atomide.com> [121114 08:50]:
> * Tomi Valkeinen <tomi.valkeinen@ti.com> [121114 03:47]:
> > On 2012-11-14 11:26, Russell King - ARM Linux wrote:
> > > OMAP* allnoconfig fails:
> > >
> > > arch/arm/mach-omap2/built-in.o: In function `omap_dss_set_min_bus_tput':
> > > twl-common.c:(.text+0x1e08): undefined reference to `omap_pm_set_min_bus_tput'
> > > arch/arm/mach-omap2/built-in.o: In function `omap_hwmod_init_postsetup':
> > > twl-common.c:(.init.text+0x8f8): undefined reference to `omap_pm_if_early_init'
> > > arch/arm/mach-omap2/built-in.o: In function `omap_serial_init_port':
> > > twl-common.c:(.init.text+0x1284): undefined reference to `omap_pm_get_dev_context_loss_count'
> > > arch/arm/mach-omap2/built-in.o: In function `omap_timer_init':
> > > twl-common.c:(.init.text+0x1544): undefined reference to `omap_pm_get_dev_context_loss_count'
> > > arch/arm/mach-omap2/built-in.o: In function `omap2_common_pm_init':
> > > twl-common.c:(.init.text+0x1af0): undefined reference to `omap_pm_if_init'
> > > arch/arm/mach-omap2/built-in.o: In function `omap2_gpio_dev_init':
> > > twl-common.c:(.init.text+0x2168): undefined reference to `omap_pm_get_dev_context_loss_count'
> > > arch/arm/mach-omap2/built-in.o: In function `omap_display_init':
> > > twl-common.c:(.init.text+0x25cc): undefined reference to `omap_pm_get_dev_context_loss_count'
> >
> > I'm not able to reproduce this. I took v3.7-rc5, and the omap4430-sdp
> > noconfig
> > (http://www.arm.linux.org.uk/developer/build/file.php?type=config&idx=2711),
> > and it builds fine for me.
>
> It happens if in arm-soc/for-next and rmk/for-next. Looks like the
> CONFIG_OMAP_PM_NOOP can't be under CONFIG_PM in the makefile where I moved it
> in commit 6e740f9a8.
This should say just "It happens in arm-soc/for-next".
> Looks like in my test configs I run make oldnoconfig on Russell's seed
> config, and I do get CONFIG_PM=y set while Russell's generated config
> does not have that. No ideas yet why oldnoconfig add CONFIG_PM=y..
>
> Anyways, patch below to make it behave like earlier.
>
> Regards,
>
> Tony
>
>
> From: Tony Lindgren <tony@atomide.com>
> Date: Wed, 14 Nov 2012 08:40:00 -0800
> Subject: [PATCH] ARM: OMAP: Fix compile for OMAP_PM_NOOP if PM is not selected
>
> Commit 6e740f9a8 (ARM: OMAP: Move omap-pm-noop.c local to mach-omap2)
> moved omap-pm-noop to be local to mach-omap2. However, the makefile
> entry got placed within ifeq ($(CONFIG_PM),y) which was not the
> case earlier.
>
> Fix the issue by moving it out of the ifeq ($(CONFIG_PM),y) in
> the makefile as these stubs are needed also when PM is not set.
>
> Reported-by: Russell King <rmk+kernel@arm.linux.org.uk>
> Signed-off-by: Tony Lindgren <tony@atomide.com>
>
> --- a/arch/arm/mach-omap2/Makefile
> +++ b/arch/arm/mach-omap2/Makefile
> @@ -68,6 +68,8 @@ obj-$(CONFIG_ARCH_OMAP4) += opp4xxx_data.o
> endif
>
> # Power Management
> +obj-$(CONFIG_OMAP_PM_NOOP) += omap-pm-noop.o
> +
> ifeq ($(CONFIG_PM),y)
> obj-$(CONFIG_ARCH_OMAP2) += pm24xx.o
> obj-$(CONFIG_ARCH_OMAP2) += sleep24xx.o
> @@ -75,7 +77,6 @@ obj-$(CONFIG_ARCH_OMAP3) += pm34xx.o sleep34xx.o
> obj-$(CONFIG_ARCH_OMAP4) += pm44xx.o omap-mpuss-lowpower.o
> obj-$(CONFIG_SOC_OMAP5) += omap-mpuss-lowpower.o
> obj-$(CONFIG_PM_DEBUG) += pm-debug.o
> -obj-$(CONFIG_OMAP_PM_NOOP) += omap-pm-noop.o
>
> obj-$(CONFIG_POWER_AVS_OMAP) += sr_device.o
> obj-$(CONFIG_POWER_AVS_OMAP_CLASS3) += smartreflex-class3.o
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH] ARM: tegra: Implement 6395/1 for Tegra
From: Sergei Shtylyov @ 2012-11-14 17:00 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1352903243-5389-1-git-send-email-pdeschrijver@nvidia.com>
Hello.
On 11/14/2012 05:27 PM, Peter De Schrijver wrote:
> This patch implements ARM linux patch 6395/1 for Tegra. See commit
> 1a8e41cd672f894bbd74874eac601e6cedf838fb for details.
You should give some details in this commit too, like specifying that commit
summary in parens.
> Signed-off-by: Peter De Schrijver <pdeschrijver@nvidia.com>
WBR, Sergei
^ permalink raw reply
* OMAP* Latest build failures
From: Tony Lindgren @ 2012-11-14 17:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20121114165947.GR6801@atomide.com>
* Tony Lindgren <tony@atomide.com> [121114 09:02]:
> * Tony Lindgren <tony@atomide.com> [121114 08:50]:
> > * Tomi Valkeinen <tomi.valkeinen@ti.com> [121114 03:47]:
> > > On 2012-11-14 11:26, Russell King - ARM Linux wrote:
> > > > OMAP* allnoconfig fails:
> > > >
> > > > arch/arm/mach-omap2/built-in.o: In function `omap_dss_set_min_bus_tput':
> > > > twl-common.c:(.text+0x1e08): undefined reference to `omap_pm_set_min_bus_tput'
> > > > arch/arm/mach-omap2/built-in.o: In function `omap_hwmod_init_postsetup':
> > > > twl-common.c:(.init.text+0x8f8): undefined reference to `omap_pm_if_early_init'
> > > > arch/arm/mach-omap2/built-in.o: In function `omap_serial_init_port':
> > > > twl-common.c:(.init.text+0x1284): undefined reference to `omap_pm_get_dev_context_loss_count'
> > > > arch/arm/mach-omap2/built-in.o: In function `omap_timer_init':
> > > > twl-common.c:(.init.text+0x1544): undefined reference to `omap_pm_get_dev_context_loss_count'
> > > > arch/arm/mach-omap2/built-in.o: In function `omap2_common_pm_init':
> > > > twl-common.c:(.init.text+0x1af0): undefined reference to `omap_pm_if_init'
> > > > arch/arm/mach-omap2/built-in.o: In function `omap2_gpio_dev_init':
> > > > twl-common.c:(.init.text+0x2168): undefined reference to `omap_pm_get_dev_context_loss_count'
> > > > arch/arm/mach-omap2/built-in.o: In function `omap_display_init':
> > > > twl-common.c:(.init.text+0x25cc): undefined reference to `omap_pm_get_dev_context_loss_count'
> > >
> > > I'm not able to reproduce this. I took v3.7-rc5, and the omap4430-sdp
> > > noconfig
> > > (http://www.arm.linux.org.uk/developer/build/file.php?type=config&idx=2711),
> > > and it builds fine for me.
> >
> > It happens if in arm-soc/for-next and rmk/for-next. Looks like the
> > CONFIG_OMAP_PM_NOOP can't be under CONFIG_PM in the makefile where I moved it
> > in commit 6e740f9a8.
>
> This should say just "It happens in arm-soc/for-next".
>
> > Looks like in my test configs I run make oldnoconfig on Russell's seed
> > config, and I do get CONFIG_PM=y set while Russell's generated config
> > does not have that. No ideas yet why oldnoconfig add CONFIG_PM=y..
Looks like the way to do this not to use oldnoconfig but to do:
$ make KCONFIG_ALLCONFIG=../configs/rmk-omap4430-sdp-noconfig allnoconfig
It seems that oldnoconfig will pick the new options that have default y?
Regards,
Tony
^ permalink raw reply
* [PATCH 1/2] arm/mm: L2CC shared mutex with ARM TZ
From: Catalin Marinas @ 2012-11-14 17:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <0154077FE026E54BB093CA7EB3FD1AE32DB61E4CC7@SAFEX1MAIL3.st.com>
On Wed, Nov 14, 2012 at 10:15:46AM +0000, Etienne CARRIERE ST wrote:
> > Tue 11-13-2012 8:23 PM
> > From: Abhimanyu Kapur <abhimanyu.kapur@outlook.com>
> >
> > > Secure code in TrustZone space may need to perform L2 cache
> > > maintenance operations. A shared mutex is required to synchronize
> > > linux l2cc maintenance and TZ l2cc maintenance.
> >
> > If you are using PL310 with thrustzone support then the L2 cache lines
> > are secure bit tagged ; your design should be such that the secure (TZ)
> > side only does operations on secure cache lines and non-secure side
> > does operations only on non-secure cache lines. So each entity (TZ
> > and nonTZ) if maintains their own cache and ensures integrity before
> > switching over via monitor, this might not be needed.
>
> I don't think 2 cores can safely write the LX20_CLEAN/INV_LINE_PA
> registers of the PL310 at the same time, even if targeting different
> lines.
Actually for the clean/invalidate operations by PA you can safely write
the registers from two different processors as they get serialised by
the hardware. What you don't get is protection around the background
operations (clean/inv by way). I think it depends on how the PL310 is
wired on your hardware but trying to do a PA operation while a
background one is in progress would trigger an external abort.
So the NS world could simply start a background cache operation without
taking the lock while the secure world thinks that it has the lock and
tries to do a PA operation which would abort.
My advise is to simply ignore the shared locking and only do atomic PA
operations on the secure side. The secure side also needs to poll for
the completion of any background operation that was started in
non-secure world. Of course, there is still a race, in which case,
depending on the hardware implementation, you would need to trap any
possible aborts while in secure mode when writing the PL310 registers.
--
Catalin
^ permalink raw reply
* Kernel uncompression error
From: Russell King - ARM Linux @ 2012-11-14 17:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <k809hq$1q3$1@ger.gmane.org>
On Wed, Nov 14, 2012 at 10:23:55PM +0800, woody wrote:
> I just built a 3.2.x ARM kernel and tried to have it boot by a boot
> loader (vivi) on my s3c2410a ARM board. The kernel was built with
> default configuration s3c2410.
I reported that S3C2410 is totally dead with 3.x kernels about a month
ago and got no response what so ever from anyone. I guess S3C2410 is
just not cared for anymore.
When I get sufficient motivation, I'll try and track down what's going
wrong, but it means taking the old mailing list server (and now list
archive) offline for a while.
I don't think it's cache related; different image sizes seem to behave
differently - and when they _do_ successfully decompress, they don't
boot at all.
^ permalink raw reply
* [PATCH 6/9] uprobes: flush cache after xol write
From: Oleg Nesterov @ 2012-11-14 17:37 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20121104142927.GA4087@in.ibm.com>
On 11/04, Ananth N Mavinakayanahalli wrote:
>
> On Sat, Nov 03, 2012 at 05:33:01PM +0100, Oleg Nesterov wrote:
> >
> > [PATCH] uprobes: flush cache after xol write
> >
> > From: Rabin Vincent <rabin@rab.in>
> >
> > Flush the cache so that the instructions written to the XOL area are
> > visible.
> >
> > Signed-off-by: Rabin Vincent <rabin@rab.in>
>
> Acked-by: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Thanks Ananth.
I assume that Srikar and Rabin agree, applied as 65b6ecc038
> >
> > --- x/kernel/events/uprobes.c
> > +++ x/kernel/events/uprobes.c
> > @@ -1199,6 +1199,11 @@ static unsigned long xol_get_insn_slot(s
> > vaddr = kmap_atomic(area->page);
> > memcpy(vaddr + offset, uprobe->arch.insn, MAX_UINSN_BYTES);
> > kunmap_atomic(vaddr);
> > + /*
> > + * We probably need flush_icache_user_range() but it needs vma.
> > + * This should work on supported architectures too.
> > + */
> > + flush_dcache_page(area->page);
> >
> > return current->utask->xol_vaddr;
> > }
^ permalink raw reply
* [RFC PATCH 0/3] introduce static_vm for ARM-specific static mapped area
From: Russell King - ARM Linux @ 2012-11-14 17:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1352912154-16210-1-git-send-email-js1304@gmail.com>
On Thu, Nov 15, 2012 at 01:55:51AM +0900, Joonsoo Kim wrote:
> In current implementation, we used ARM-specific flag, that is,
> VM_ARM_STATIC_MAPPING, for distinguishing ARM specific static mapped area.
> The purpose of static mapped area is to re-use static mapped area when
> entire physical address range of the ioremap request can be covered
> by this area.
>
> This implementation causes needless overhead for some cases.
In what cases?
> We unnecessarily iterate vmlist for finding matched area even if there
> is no static mapped area. And if there are some static mapped areas,
> iterating whole vmlist is not preferable.
Why not? Please put some explanation into your message rather than
just statements making unexplained assertions.
> Another reason for doing this work is for removing architecture dependency
> on vmalloc layer. I think that vmlist and vmlist_lock is internal data
> structure for vmalloc layer. Some codes for debugging and stat inevitably
> use vmlist and vmlist_lock. But it is preferable that they are used outside
> of vmalloc.c as least as possible.
The vmalloc layer is also made available for ioremap use, and it is
intended that architectures hook into this for ioremap support.
^ permalink raw reply
* OMAP* Latest build failures
From: Russell King - ARM Linux @ 2012-11-14 17:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <50A3844B.8040208@ti.com>
On Wed, Nov 14, 2012 at 01:45:15PM +0200, Tomi Valkeinen wrote:
> On 2012-11-14 11:26, Russell King - ARM Linux wrote:
> > OMAP* allnoconfig fails:
> >
> > arch/arm/mach-omap2/built-in.o: In function `omap_dss_set_min_bus_tput':
> > twl-common.c:(.text+0x1e08): undefined reference to `omap_pm_set_min_bus_tput'
> > arch/arm/mach-omap2/built-in.o: In function `omap_hwmod_init_postsetup':
> > twl-common.c:(.init.text+0x8f8): undefined reference to `omap_pm_if_early_init'
> > arch/arm/mach-omap2/built-in.o: In function `omap_serial_init_port':
> > twl-common.c:(.init.text+0x1284): undefined reference to `omap_pm_get_dev_context_loss_count'
> > arch/arm/mach-omap2/built-in.o: In function `omap_timer_init':
> > twl-common.c:(.init.text+0x1544): undefined reference to `omap_pm_get_dev_context_loss_count'
> > arch/arm/mach-omap2/built-in.o: In function `omap2_common_pm_init':
> > twl-common.c:(.init.text+0x1af0): undefined reference to `omap_pm_if_init'
> > arch/arm/mach-omap2/built-in.o: In function `omap2_gpio_dev_init':
> > twl-common.c:(.init.text+0x2168): undefined reference to `omap_pm_get_dev_context_loss_count'
> > arch/arm/mach-omap2/built-in.o: In function `omap_display_init':
> > twl-common.c:(.init.text+0x25cc): undefined reference to `omap_pm_get_dev_context_loss_count'
>
> I'm not able to reproduce this. I took v3.7-rc5, and the omap4430-sdp
> noconfig
> (http://www.arm.linux.org.uk/developer/build/file.php?type=config&idx=2711),
> and it builds fine for me.
That's not the kernel it builds - it builds mainline + my kernel (which
is basically for-next + a few bits more) + arm-soc.
This error only just poped up, so I'm guessing there is a change in arm-soc
which has broken it.
> I see that arch/arm/plat-omap/omap-pm-noop.c is not compiled, which is
> where the above functions are. However, the config contains
> CONFIG_OMAP_PM_NOOP=y, which should cause omap-pm-noop.c to be compiled.
Suggest you retry with v3.7-rc5 + arm-soc.
^ 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