* [PATCH RESEND] ARM: smp_twd: Reconfigure clockevents after cpufreq change
From: Thomas Gleixner @ 2011-10-06 17:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAKnu2ModYp+F0kq6qVo9SQJ88GR_EwGNgH2WZXJrXUeR1xyzQw@mail.gmail.com>
On Thu, 6 Oct 2011, Linus Walleij wrote:
> 2011/9/6 Linus Walleij <linus.walleij@stericsson.com>:
>
> > From: Colin Cross <ccross@android.com>
> >
> > The localtimer's clock changes with the cpu clock. After a
> > cpufreq transition, update the clockevent's frequency and
> > reprogram the next clock event.
>
> Thomas do you think you can have a look at this patch and ACK
> it if it looks OK to you? It's the use of clockevents_update_freq()
> function you added after we discussed this in Budapest.
>
> Since it's likely the first user of that infrastructure we need
> to get it right.
The usage is correct.
> Here is the entire patch i Russells tracker:
> http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=6956/2
The only thing what puzzles me is:
> + if (!IS_ERR_OR_NULL(twd_clk))
> + twd_timer_rate = clk_get_rate(twd_clk);
> + else
> + twd_calibrate_rate();
How is made sure that the cpu freq update thing is not called when
twd_clk is not available or am I missing something ?
Thanks,
tglx
^ permalink raw reply
* [GIT PULL] Samsung devel-2 for v3.2
From: Mark Brown @ 2011-10-06 17:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20111006155701.GA1470@opensource.wolfsonmicro.com>
On Thu, Oct 06, 2011 at 04:57:01PM +0100, Mark Brown wrote:
> The bisect did end up pointing at the GPIO commits, the build errors
> were causing issues. Not really made any further progress on this issue
> today, some other things came up.
So, I've been trying some other directions here. What I'm seeing by
pulling devices out of my config is that if I enable the LCD power
control then the board fails to boot. Also, the I2C controllers appear
to be non-functional - I'm getting timeouts waiting for the bus to
become free which halt the boot for long enough that it'd look like it
had crashed if all the devices came up (there's a lot of I2C devices
there).
I've not had time to actually drill down below that level but it did
occur to me that there may be a problem with the pinmux code?
^ permalink raw reply
* [PATCH v3] virtio: Add platform bus driver for memory mapped virtio device
From: Pawel Moll @ 2011-10-06 17:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1317919843-8343-1-git-send-email-pawel.moll@arm.com>
> I'll post the updated device spec shortly.
Here it goes. I'm actually happy about the "maximum queue size" solution
- it worked out quite neat in the end :-)
Please, do have a look at the hopefully final shape of things and
comment if you still see some potential issues :-)
Cheers!
Pawel
8<----------------------------------------------------------------------
\documentclass[12pt]{article}
\begin{document}
Virtual environments without PCI support (a common situation in embedded
devices models) might use simple memory mapped device (``virtio-mmio'')
instead of the PCI device.
The memory mapped virtio device behaviour is based on the PCI device
specification. Therefore most of operations like device initialization,
queues configuration and buffer transfers are nearly identical. Existing
differences are described in the following sections.
\subsection{Device Initialization}
Instead of using the PCI IO space for virtio header, the ``virtio-mmio''
device provides a set of memory mapped control registers, all 32 bits
wide, followed by device-specific configuration space. The following
list presents their layout:
\begin{itemize}
\item Offset from the device base address | Direction | Name \\
Description
\item 0x000 | R | MagicValue \\
``virt'' string.
\item 0x004 | R | Version \\
Device version number. Currently must be 1.
\item 0x008 | R | DeviceID \\
Virtio Subsystem Device ID (ie. 1 for network card).
\item 0x00c | R | VendorID \\
Virtio Subsystem Vendor ID.
\item 0x010 | R | HostFeatures \\
Flags representing features the device supports.\\
Reading from this register returns 32 consecutive flag bits, first bit
depending on the last value written to HostFeaturesSel register. Access
to this register returns bits $HostFeaturesSel*32$ to
$(HostFeaturesSel*32)+31$, eg. feature bits 0 to 31 if HostFeaturesSel
is set to 0 and features bits 32 to 63 if HostFeaturesSel is set to 1.
Also see p. 2.2.2.2 ``Feature Bits''.
\item 0x014 | W | HostFeaturesSel \\
Device (Host) features word selection.\\
Writing to this register selects a set of 32 device feature bits
accessible by reading from HostFeatures register. Device driver must
write a value to the HostFeaturesSel register before reading from the
HostFeatures register.
\item 0x020 | W | GuestFeatures \\
Flags representing device features understood and activated by the
driver.\\
Writing to this register sets 32 consecutive flag bits, first bit
depending on the last value written to GuestFeaturesSel register. Access
to this register sets bits $GuestFeaturesSel*32$ to
$(GuestFeaturesSel*32)+31$, eg. feature bits 0 to 31 if GuestFeaturesSel
is set to 0 and features bits 32 to 63 if GuestFeaturesSel is set to 1.\
\
Also see p. 2.2.2.2 ``Feature Bits''.
\item 0x024 | W | GuestFeaturesSel \\
Activated (Guest) features word selection.\\
Writing to this register selects a set of 32 activated feature bits
accessible by writing to the GuestFeatures register. Device driver must
write a value to the GuestFeaturesSel register before writing to the
GuestFeatures register.
\item 0x028 | W | GuestPageSize \\
Guest page size.\\
Device driver must write the guest page size in bytes to the register
during initialization, before any queues are used.
\item 0x030 | W | QueueSel \\
Virtual queue index (first queue is 0).\\
Writing to this register selects the virtual queue that the following
operations on QueueNum, QueueAlign and QueuePFN apply to.
\item 0x034 | R | QueueNumMax \\
Maximum virtual queue size. \\
Reading from the register returns the maximum size of the queue the Host
is ready to process or zero (0x0) if the queue is not available. This
applies to the queue selected by writing to QueueSel.
\item 0x038 | W | QueueNum \\
Virtual queue size.\\
Queue size is a number of elements in the queue, therefore size of the
descriptor table and both available and used rings.\\
Writing to this register notifies the Host what size of the queue the
Guest will use. This applies to the queue selected by writing to
QueueSel.
\item 0x03c | W | QueueAlign \\
Used Ring alignment in the virtual queue.\\
Writing to this register notifies the Host about alignment boundary of
the Used Ring in bytes. This applies to the queue selected by writing to
QueueSel.
\item 0x040 | RW | QueuePFN \\
Guest physical page number of the virtual queue.\\
Writing to this register notifies the host about location of the virtual
queue in the Guest's physical address space. This value is the index
number of a page starting with the queue Descriptor Table. Value zero
(0x0) means physical address zero (0x00000000) and is illegal. When the
Guest stops using the queue it must write zero (0x0) to this register.\\
Reading from this register returns the currently used page number of the
queue, therefore a value other than zero (0x0) means that the queue is
in use.\\
Both read and write accesses apply to the queue selected by writing to
QueueSel.
\item 0x050 | W | QueueNotify \\
Queue notifier.\\
Writing a queue index to this register notifies the Host that there are
new buffers to process in the queue.
\item 0x060 | W | InterruptACK \\
Interrupt acknowledge. \\
Writing to this register notifies the Host that the Guest finished
receiving used buffers from the device and therefore serviced an
asserted interrupt. Values written to this register are currently not
used, but for future extensions it must be set to one (0x1).
\item 0x070 | RW | Status \\
Device status. \\
Reading from this register returns the current device status flags. \\
Writing non-zero values to this register sets the status flags,
indicating the Guest progress. Writing zero (0x0) to this register
triggers a device reset. \\
Also see p. 2.2.2.1 ``Device Status''.
\item 0x100+ | RW | Config \\
Device-specific configuration space starts@an offset 0x100 and is
accessed with byte alignment. Its meaning and size depends on the device
and the driver.
\end{itemize}
Virtual queue size is a number of elements in the queue, therefore size
of the descriptor table and both available and used rings.
The endianness of the registers follows the native endianness of the
Guest. Writing to registers described as ``R'' and reading from
registers described as ``W'' is not permitted and can cause undefined
behavior.
The device initialization is performed as described in p. 2.2.1 ``Device
Initialization Sequence'' with one exception: the Guest must notify the
Host about its page size, writing the size in bytes to GuestPageSize
register before the initialization is finished.
The memory mapped virtio devices generate single interrupt only,
therefore no special configuration is required.
\subsection{Virtqueue Configuration}
The virtual queue configuration is performed in a similar way to the one
described in p 2.3 ``Virtqueue Configuration'' with a few additional
operations:
\begin{enumerate}
\item Select the queue writing its index (first queue is 0) to the
QueueSel register.
\item Check if the queue is not already in use: read QueuePFN register,
returned value should be zero (0x0).
\item Read maximum queue size (number of elements) from the QueueNumMax
register. If the returned value is zero (0x0) the queue is not
available.
\item Allocate and zero the queue pages in contiguous virtual memory,
aligning the Used Ring to an optimal boundary (usually page size). Size
of the allocated queue may be smaller than or equal to the maximum size
returned by the Host.
\item Notify the Host about the queue size by writing the size to
QueueNum register.
\item Notify the Host about the used alignment by writing its value in
bytes to QueueAlign register.
\item Write the physical number of the first page of the queue to the
QueuePFN register.
\end{enumerate}
The queue and the device are ready to begin normal operations now.
\subsection{Device Operation}
The memory mapped virtio device behaves in the same way as described in
p. 2.4 ``Device Operation'', with the following exceptions:
\begin{enumerate}
\item The device is notified about new buffers available in a queue by
writing the queue index to register QueueNum instead of the virtio
header in PCI I/O space (p. 2.4.1.4 ``Notifying The Device'').
\item As the memory mapped virtio device is using single, dedicated
interrupt signal, its handling is much simpler than in the PCI (MSI-X)
case (p. 2.4.2 ``Receiving Used Buffer From The Device''). Therefore
all the Guest interrupt handler should do after receiving used buffers
is acknowledging the interrupt by writing a value to the InterruptACK
register. Currently this value does not carry any meaning, but for
future extensions it must be set to one (0x1).
\item The dynamic configuration changes, as described in p. 2.4.3
``Dealing With Configuration Changes'' are not permitted.
\end{enumerate}
\end{document}
^ permalink raw reply
* [PATCH 11/16] spi: pl022: Enable module alias autogeneration for AMBA drivers
From: Linus Walleij @ 2011-10-06 17:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1317830707-17517-12-git-send-email-dave.martin@linaro.org>
2011/10/5 Dave Martin <dave.martin@linaro.org>:
> Signed-off-by: Dave Martin <dave.martin@linaro.org>
> ---
> ?drivers/spi/spi-pl022.c | ? ?2 ++
> ?1 files changed, 2 insertions(+), 0 deletions(-)
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Thanks,
Linus Walleij
^ permalink raw reply
* [PATCH RESEND] ARM: smp_twd: Reconfigure clockevents after cpufreq change
From: Linus Walleij @ 2011-10-06 17:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1315292775-4413-1-git-send-email-linus.walleij@stericsson.com>
2011/9/6 Linus Walleij <linus.walleij@stericsson.com>:
> From: Colin Cross <ccross@android.com>
>
> The localtimer's clock changes with the cpu clock. After a
> cpufreq transition, update the clockevent's frequency and
> reprogram the next clock event.
Thomas do you think you can have a look at this patch and ACK
it if it looks OK to you? It's the use of clockevents_update_freq()
function you added after we discussed this in Budapest.
Since it's likely the first user of that infrastructure we need
to get it right.
Here is the entire patch i Russells tracker:
http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=6956/2
Tell me if you want me to resend the patch again and
I'll fix.
Yours,
Linus Walleij
^ permalink raw reply
* [PATCH v3] virtio: Add platform bus driver for memory mapped virtio device
From: Pawel Moll @ 2011-10-06 16:50 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1317841030-17758-1-git-send-email-pawel.moll@arm.com>
This patch, based on virtio PCI driver, adds support for memory
mapped (platform) virtio device. This should allow environments
like qemu to use virtio-based block & network devices even on
platforms without PCI support.
One can define and register a platform device which resources
will describe memory mapped control registers and "mailbox"
interrupt. Such device can be also instantiated using the Device
Tree node with compatible property equal "virtio,mmio".
Cc: Rusty Russell <rusty@rustcorp.com.au>
Cc: Anthony Liguori <aliguori@us.ibm.com>
Cc: Michael S.Tsirkin <mst@redhat.com>
Signed-off-by: Pawel Moll <pawel.moll@arm.com>
---
Hello again,
While doing some extra testing I've discovered a bug in error path
of vm_find_vqs() (interrupt was freed twice, first in vm_del_vqs()
and then in vm_find_vqs() itself). Fixed now.
I'll post the updated device spec shortly.
Cheers!
Pawel
Documentation/devicetree/bindings/virtio/mmio.txt | 17 +
drivers/virtio/Kconfig | 11 +
drivers/virtio/Makefile | 1 +
drivers/virtio/virtio_mmio.c | 467 +++++++++++++++++++++
include/linux/virtio_mmio.h | 97 +++++
5 files changed, 593 insertions(+), 0 deletions(-)
create mode 100644 Documentation/devicetree/bindings/virtio/mmio.txt
create mode 100644 drivers/virtio/virtio_mmio.c
create mode 100644 include/linux/virtio_mmio.h
diff --git a/Documentation/devicetree/bindings/virtio/mmio.txt b/Documentation/devicetree/bindings/virtio/mmio.txt
new file mode 100644
index 0000000..5069c1b
--- /dev/null
+++ b/Documentation/devicetree/bindings/virtio/mmio.txt
@@ -0,0 +1,17 @@
+* virtio memory mapped device
+
+See http://ozlabs.org/~rusty/virtio-spec/ for more details.
+
+Required properties:
+
+- compatible: "virtio,mmio" compatibility string
+- reg: control registers base address and size including configuration space
+- interrupts: interrupt generated by the device
+
+Example:
+
+ virtio_block at 3000 {
+ compatible = "virtio,mmio";
+ reg = <0x3000 0x100>;
+ interrupts = <41>;
+ }
diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig
index 57e493b..816ed08 100644
--- a/drivers/virtio/Kconfig
+++ b/drivers/virtio/Kconfig
@@ -35,4 +35,15 @@ config VIRTIO_BALLOON
If unsure, say M.
+ config VIRTIO_MMIO
+ tristate "Platform bus driver for memory mapped virtio devices (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ select VIRTIO
+ select VIRTIO_RING
+ ---help---
+ This drivers provides support for memory mapped virtio
+ platform device driver.
+
+ If unsure, say N.
+
endmenu
diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile
index 6738c44..5a4c63c 100644
--- a/drivers/virtio/Makefile
+++ b/drivers/virtio/Makefile
@@ -1,4 +1,5 @@
obj-$(CONFIG_VIRTIO) += virtio.o
obj-$(CONFIG_VIRTIO_RING) += virtio_ring.o
+obj-$(CONFIG_VIRTIO_MMIO) += virtio_mmio.o
obj-$(CONFIG_VIRTIO_PCI) += virtio_pci.o
obj-$(CONFIG_VIRTIO_BALLOON) += virtio_balloon.o
diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c
new file mode 100644
index 0000000..d402629
--- /dev/null
+++ b/drivers/virtio/virtio_mmio.c
@@ -0,0 +1,467 @@
+/*
+ * Virtio memory mapped device driver
+ *
+ * Copyright 2011, ARM Ltd.
+ *
+ * This module allows virtio devices to be used over a virtual, memory mapped
+ * platform device.
+ *
+ * Registers layout (all 32-bit wide):
+ *
+ * offset d. name description
+ * ------ -- ---------------- -----------------
+ *
+ * 0x000 R MagicValue Magic value "virt"
+ * 0x004 R Version Device version (current max. 1)
+ * 0x008 R DeviceID Virtio device ID
+ * 0x00c R VendorID Virtio vendor ID
+ *
+ * 0x010 R HostFeatures Features supported by the host
+ * 0x014 W HostFeaturesSel Set of host features to access via HostFeatures
+ *
+ * 0x020 W GuestFeatures Features activated by the guest
+ * 0x024 W GuestFeaturesSel Set of activated features to set via GuestFeatures
+ * 0x028 W GuestPageSize Size of guest's memory page in bytes
+ *
+ * 0x030 W QueueSel Queue selector
+ * 0x034 R QueueNumMax Maximum size of the currently selected queue
+ * 0x038 W QueueNum Queue size for the currently selected queue
+ * 0x03c W QueueAlign Used Ring alignment for the current queue
+ * 0x040 RW QueuePFN PFN for the currently selected queue
+ *
+ * 0x050 W QueueNotify Queue notifier
+ * 0x060 W InterruptACK Interrupt acknowledge register
+ * 0x070 RW Status Device status register
+ *
+ * 0x100+ RW Device-specific configuration space
+ *
+ * Based on Virtio PCI driver by Anthony Liguori, copyright IBM Corp. 2007
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <linux/highmem.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/virtio.h>
+#include <linux/virtio_config.h>
+#include <linux/virtio_mmio.h>
+#include <linux/virtio_ring.h>
+
+
+
+/* The alignment to use between consumer and producer parts of vring.
+ * Currently hardcoded to the page size. */
+#define VIRTIO_MMIO_VRING_ALIGN PAGE_SIZE
+
+
+
+#define to_virtio_mmio_device(_plat_dev) \
+ container_of(_plat_dev, struct virtio_mmio_device, vdev)
+
+struct virtio_mmio_device {
+ struct virtio_device vdev;
+ struct platform_device *pdev;
+
+ void __iomem *base;
+ unsigned long version;
+
+ /* a list of queues so we can dispatch IRQs */
+ spinlock_t lock;
+ struct list_head virtqueues;
+};
+
+struct virtio_mmio_vq_info {
+ /* the actual virtqueue */
+ struct virtqueue *vq;
+
+ /* the number of entries in the queue */
+ unsigned int num;
+
+ /* the index of the queue */
+ int queue_index;
+
+ /* the virtual address of the ring queue */
+ void *queue;
+
+ /* the list node for the virtqueues list */
+ struct list_head node;
+};
+
+
+
+/* Configuration interface */
+
+static u32 vm_get_features(struct virtio_device *vdev)
+{
+ struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
+
+ /* TODO: Features > 32 bits */
+ writel(0, vm_dev->base + VIRTIO_MMIO_HOST_FEATURES_SEL);
+
+ return readl(vm_dev->base + VIRTIO_MMIO_HOST_FEATURES);
+}
+
+static void vm_finalize_features(struct virtio_device *vdev)
+{
+ struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
+ int i;
+
+ /* Give virtio_ring a chance to accept features. */
+ vring_transport_features(vdev);
+
+ for (i = 0; i < ARRAY_SIZE(vdev->features); i++) {
+ writel(i, vm_dev->base + VIRTIO_MMIO_GUEST_FEATURES_SET);
+ writel(vdev->features[i],
+ vm_dev->base + VIRTIO_MMIO_GUEST_FEATURES);
+ }
+}
+
+static void vm_get(struct virtio_device *vdev, unsigned offset,
+ void *buf, unsigned len)
+{
+ struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
+ u8 *ptr = buf;
+ int i;
+
+ for (i = 0; i < len; i++)
+ ptr[i] = readb(vm_dev->base + VIRTIO_MMIO_CONFIG + offset + i);
+}
+
+static void vm_set(struct virtio_device *vdev, unsigned offset,
+ const void *buf, unsigned len)
+{
+ struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
+ const u8 *ptr = buf;
+ int i;
+
+ for (i = 0; i < len; i++)
+ writeb(ptr[i], vm_dev->base + VIRTIO_MMIO_CONFIG + offset + i);
+}
+
+static u8 vm_get_status(struct virtio_device *vdev)
+{
+ struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
+
+ return readl(vm_dev->base + VIRTIO_MMIO_STATUS) & 0xff;
+}
+
+static void vm_set_status(struct virtio_device *vdev, u8 status)
+{
+ struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
+
+ /* We should never be setting status to 0. */
+ BUG_ON(status == 0);
+
+ writel(status, vm_dev->base + VIRTIO_MMIO_STATUS);
+}
+
+static void vm_reset(struct virtio_device *vdev)
+{
+ struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
+
+ /* 0 status means a reset. */
+ writel(0, vm_dev->base + VIRTIO_MMIO_STATUS);
+}
+
+
+
+/* Transport interface */
+
+/* the notify function used when creating a virt queue */
+static void vm_notify(struct virtqueue *vq)
+{
+ struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vq->vdev);
+ struct virtio_mmio_vq_info *info = vq->priv;
+
+ /* We write the queue's selector into the notification register to
+ * signal the other end */
+ writel(info->queue_index, vm_dev->base + VIRTIO_MMIO_QUEUE_NOTIFY);
+}
+
+/* Notify all virtqueues on an interrupt. */
+static irqreturn_t vm_interrupt(int irq, void *opaque)
+{
+ struct virtio_mmio_device *vm_dev = opaque;
+ struct virtio_mmio_vq_info *info;
+ irqreturn_t ret = IRQ_NONE;
+ unsigned long flags;
+
+ writel(1, vm_dev->base + VIRTIO_MMIO_INTERRUPT_ACK);
+
+ spin_lock_irqsave(&vm_dev->lock, flags);
+ list_for_each_entry(info, &vm_dev->virtqueues, node) {
+ if (vring_interrupt(irq, info->vq) == IRQ_HANDLED)
+ ret = IRQ_HANDLED;
+ }
+ spin_unlock_irqrestore(&vm_dev->lock, flags);
+
+ return ret;
+}
+
+
+
+static void vm_del_vq(struct virtqueue *vq)
+{
+ struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vq->vdev);
+ struct virtio_mmio_vq_info *info = vq->priv;
+ unsigned long flags, size;
+
+ spin_lock_irqsave(&vm_dev->lock, flags);
+ list_del(&info->node);
+ spin_unlock_irqrestore(&vm_dev->lock, flags);
+
+ vring_del_virtqueue(vq);
+
+ /* Select and deactivate the queue */
+ writel(info->queue_index, vm_dev->base + VIRTIO_MMIO_QUEUE_SEL);
+ writel(0, vm_dev->base + VIRTIO_MMIO_QUEUE_PFN);
+
+ size = PAGE_ALIGN(vring_size(info->num, VIRTIO_MMIO_VRING_ALIGN));
+ free_pages_exact(info->queue, size);
+ kfree(info);
+}
+
+static void vm_del_vqs(struct virtio_device *vdev)
+{
+ struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
+ struct virtqueue *vq, *n;
+
+ list_for_each_entry_safe(vq, n, &vdev->vqs, list)
+ vm_del_vq(vq);
+
+ free_irq(platform_get_irq(vm_dev->pdev, 0), vm_dev);
+}
+
+
+
+static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, unsigned index,
+ void (*callback)(struct virtqueue *vq),
+ const char *name)
+{
+ struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
+ struct virtio_mmio_vq_info *info;
+ struct virtqueue *vq;
+ unsigned long flags, size;
+ int err;
+
+ /* Select the queue we're interested in */
+ writel(index, vm_dev->base + VIRTIO_MMIO_QUEUE_SEL);
+
+ /* Queue shouldn't already be set up. */
+ if (readl(vm_dev->base + VIRTIO_MMIO_QUEUE_PFN)) {
+ err = -ENOENT;
+ goto error_available;
+ }
+
+ /* Allocate and fill out our active queue description */
+ info = kmalloc(sizeof(*info), GFP_KERNEL);
+ if (!info) {
+ err = -ENOMEM;
+ goto error_kmalloc;
+ }
+ info->queue_index = index;
+
+ /* Allocate pages for the queue - start with a queue as big as
+ * possible (limited by maximum size allowed by device), drop down
+ * to a minimal size, just big enough to fit descriptor table
+ * and two rings (which makes it "alignment_size * 2")
+ */
+ info->num = readl(vm_dev->base + VIRTIO_MMIO_QUEUE_NUM_MAX);
+ while (1) {
+ size = PAGE_ALIGN(vring_size(info->num,
+ VIRTIO_MMIO_VRING_ALIGN));
+ /* Already smallest possible allocation? */
+ if (size <= VIRTIO_MMIO_VRING_ALIGN * 2) {
+ err = -ENOMEM;
+ goto error_alloc_pages;
+ }
+
+ info->queue = alloc_pages_exact(size, GFP_KERNEL | __GFP_ZERO);
+ if (info->queue)
+ break;
+
+ info->num /= 2;
+ }
+
+ /* Activate the queue */
+ writel(info->num, vm_dev->base + VIRTIO_MMIO_QUEUE_NUM);
+ writel(VIRTIO_MMIO_VRING_ALIGN,
+ vm_dev->base + VIRTIO_MMIO_QUEUE_ALIGN);
+ writel(virt_to_phys(info->queue) >> PAGE_SHIFT,
+ vm_dev->base + VIRTIO_MMIO_QUEUE_PFN);
+
+ /* Create the vring */
+ vq = vring_new_virtqueue(info->num, VIRTIO_MMIO_VRING_ALIGN,
+ vdev, info->queue, vm_notify, callback, name);
+ if (!vq) {
+ err = -ENOMEM;
+ goto error_new_virtqueue;
+ }
+
+ vq->priv = info;
+ info->vq = vq;
+
+ spin_lock_irqsave(&vm_dev->lock, flags);
+ list_add(&info->node, &vm_dev->virtqueues);
+ spin_unlock_irqrestore(&vm_dev->lock, flags);
+
+ return vq;
+
+error_new_virtqueue:
+ writel(0, vm_dev->base + VIRTIO_MMIO_QUEUE_PFN);
+ free_pages_exact(info->queue, size);
+error_alloc_pages:
+ kfree(info);
+error_kmalloc:
+error_available:
+ return ERR_PTR(err);
+}
+
+static int vm_find_vqs(struct virtio_device *vdev, unsigned nvqs,
+ struct virtqueue *vqs[],
+ vq_callback_t *callbacks[],
+ const char *names[])
+{
+ struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
+ unsigned int irq = platform_get_irq(vm_dev->pdev, 0);
+ int i, err;
+
+ err = request_irq(irq, vm_interrupt, IRQF_SHARED,
+ dev_name(&vdev->dev), vm_dev);
+ if (err)
+ return err;
+
+ for (i = 0; i < nvqs; ++i) {
+ vqs[i] = vm_setup_vq(vdev, i, callbacks[i], names[i]);
+ if (IS_ERR(vqs[i])) {
+ vm_del_vqs(vdev);
+ return PTR_ERR(vqs[i]);
+ }
+ }
+
+ return 0;
+}
+
+
+
+static struct virtio_config_ops virtio_mmio_config_ops = {
+ .get = vm_get,
+ .set = vm_set,
+ .get_status = vm_get_status,
+ .set_status = vm_set_status,
+ .reset = vm_reset,
+ .find_vqs = vm_find_vqs,
+ .del_vqs = vm_del_vqs,
+ .get_features = vm_get_features,
+ .finalize_features = vm_finalize_features,
+};
+
+
+
+/* Platform device */
+
+static int __devinit virtio_mmio_probe(struct platform_device *pdev)
+{
+ struct virtio_mmio_device *vm_dev;
+ struct resource *mem;
+ unsigned long magic;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem)
+ return -EINVAL;
+
+ if (!devm_request_mem_region(&pdev->dev, mem->start,
+ resource_size(mem), pdev->name))
+ return -EBUSY;
+
+ vm_dev = devm_kzalloc(&pdev->dev, sizeof(*vm_dev), GFP_KERNEL);
+ if (!vm_dev)
+ return -ENOMEM;
+
+ vm_dev->vdev.dev.parent = &pdev->dev;
+ vm_dev->vdev.config = &virtio_mmio_config_ops;
+ vm_dev->pdev = pdev;
+ INIT_LIST_HEAD(&vm_dev->virtqueues);
+ spin_lock_init(&vm_dev->lock);
+
+ vm_dev->base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
+ if (vm_dev->base == NULL)
+ return -EFAULT;
+
+ /* Check magic value */
+ magic = readl(vm_dev->base + VIRTIO_MMIO_MAGIC_VALUE);
+ if (memcmp(&magic, "virt", 4) != 0) {
+ dev_warn(&pdev->dev, "Wrong magic value 0x%08lx!\n", magic);
+ return -ENODEV;
+ }
+
+ /* Check device version */
+ vm_dev->version = readl(vm_dev->base + VIRTIO_MMIO_VERSION);
+ if (vm_dev->version != 1) {
+ dev_err(&pdev->dev, "Version %ld not supported!\n",
+ vm_dev->version);
+ return -ENXIO;
+ }
+
+ vm_dev->vdev.id.device = readl(vm_dev->base + VIRTIO_MMIO_DEVICE_ID);
+ vm_dev->vdev.id.vendor = readl(vm_dev->base + VIRTIO_MMIO_VENDOR_ID);
+
+ writel(PAGE_SIZE, vm_dev->base + VIRTIO_MMIO_GUEST_PAGE_SIZE);
+
+ platform_set_drvdata(pdev, vm_dev);
+
+ return register_virtio_device(&vm_dev->vdev);
+}
+
+static int __devexit virtio_mmio_remove(struct platform_device *pdev)
+{
+ struct virtio_mmio_device *vm_dev = platform_get_drvdata(pdev);
+
+ unregister_virtio_device(&vm_dev->vdev);
+
+ return 0;
+}
+
+
+
+/* Platform driver */
+
+static struct of_device_id virtio_mmio_match[] = {
+ { .compatible = "virtio,mmio", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, virtio_mmio_match);
+
+static struct platform_driver virtio_mmio_driver = {
+ .probe = virtio_mmio_probe,
+ .remove = __devexit_p(virtio_mmio_remove),
+ .driver = {
+ .name = "virtio-mmio",
+ .owner = THIS_MODULE,
+ .of_match_table = virtio_mmio_match,
+ },
+};
+
+static int __init virtio_mmio_init(void)
+{
+ return platform_driver_register(&virtio_mmio_driver);
+}
+
+static void __exit virtio_mmio_exit(void)
+{
+ platform_driver_unregister(&virtio_mmio_driver);
+}
+
+module_init(virtio_mmio_init);
+module_exit(virtio_mmio_exit);
+
+MODULE_AUTHOR("Pawel Moll <pawel.moll@arm.com>");
+MODULE_DESCRIPTION("Platform bus driver for memory mapped virtio devices");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/virtio_mmio.h b/include/linux/virtio_mmio.h
new file mode 100644
index 0000000..ffa9210
--- /dev/null
+++ b/include/linux/virtio_mmio.h
@@ -0,0 +1,97 @@
+/*
+ * Virtio platform device driver
+ *
+ * Copyright 2011, ARM Ltd.
+ *
+ * Based on Virtio PCI driver by Anthony Liguori, copyright IBM Corp. 2007
+ *
+ * This header is BSD licensed so anyone can use the definitions to implement
+ * compatible drivers/servers.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of IBM nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LINUX_VIRTIO_MMIO_H
+#define _LINUX_VIRTIO_MMIO_H
+
+/* Magic value ("virt" string) - Read Only */
+#define VIRTIO_MMIO_MAGIC_VALUE 0x000
+
+/* Virtio device version - Read Only */
+#define VIRTIO_MMIO_VERSION 0x004
+
+/* Virtio device ID - Read Only */
+#define VIRTIO_MMIO_DEVICE_ID 0x008
+
+/* Virtio vendor ID - Read Only */
+#define VIRTIO_MMIO_VENDOR_ID 0x00c
+
+/* Bitmask of the features supported by the host
+ * (32 bits per set) - Read Only */
+#define VIRTIO_MMIO_HOST_FEATURES 0x010
+
+/* Host features set selector - Write Only */
+#define VIRTIO_MMIO_HOST_FEATURES_SEL 0x014
+
+/* Bitmask of features activated by the guest
+ * (32 bits per set) - Write Only */
+#define VIRTIO_MMIO_GUEST_FEATURES 0x020
+
+/* Activated features set selector - Write Only */
+#define VIRTIO_MMIO_GUEST_FEATURES_SET 0x024
+
+/* Guest's memory page size in bytes - Write Only */
+#define VIRTIO_MMIO_GUEST_PAGE_SIZE 0x028
+
+/* Queue selector - Write Only */
+#define VIRTIO_MMIO_QUEUE_SEL 0x030
+
+/* Maximum size of the currently selected queue - Read Only */
+#define VIRTIO_MMIO_QUEUE_NUM_MAX 0x034
+
+/* Queue size for the currently selected queue - Write Only */
+#define VIRTIO_MMIO_QUEUE_NUM 0x038
+
+/* Used Ring alignment for the currently selected queue - Write Only */
+#define VIRTIO_MMIO_QUEUE_ALIGN 0x03c
+
+/* Guest's PFN for the currently selected queue - Read Write */
+#define VIRTIO_MMIO_QUEUE_PFN 0x040
+
+/* Queue notifier - Write Only */
+#define VIRTIO_MMIO_QUEUE_NOTIFY 0x050
+
+/* Interrupt acknowledge - Write Only */
+#define VIRTIO_MMIO_INTERRUPT_ACK 0x060
+
+/* Device status register - Read Write */
+#define VIRTIO_MMIO_STATUS 0x070
+
+/* The config space is defined by each driver as
+ * the per-driver configuration space - Read Write */
+#define VIRTIO_MMIO_CONFIG 0x100
+
+
+
+#endif
--
1.6.3.3
^ permalink raw reply related
* [RFC/PATCH 6/7] ARM: ARM11 MPCore: DMA_CACHE_RWFO operations are not preempt safe
From: Russell King - ARM Linux @ 2011-10-06 16:40 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1317877714-11355-7-git-send-email-gdavis@mvista.com>
On Thu, Oct 06, 2011 at 01:08:33AM -0400, gdavis at mvista.com wrote:
> v6_dma_inv_range:
> #ifdef CONFIG_DMA_CACHE_RWFO
> +#ifdef CONFIG_PREEMPT
> + stmdb sp!, {r4, r10, r11}
> + get_thread_info r10
> + ldr r4, [r10, #TI_PREEMPT] @ get preempt count
> + add r11, r4, #1 @ increment it
> + str r11, [r10, #TI_PREEMPT] @ disable preempt
> +#endif
r11 is the frame pointer. On kernels built with the frame pointer
enabled, this register must either be a valid frame pointer or zero.
There's no reason to use r4, r10 and r11 here - you could use r4, r5
and ip (r12) - and then there's no need to save ip as that's allowed
to be corrupted by called functions.
^ permalink raw reply
* [RFC/PATCH 1/7] ARM: ARM11 MPCore: pgd_alloc is not preempt safe
From: Russell King - ARM Linux @ 2011-10-06 16:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1317877714-11355-2-git-send-email-gdavis@mvista.com>
On Thu, Oct 06, 2011 at 01:08:28AM -0400, gdavis at mvista.com wrote:
> @@ -31,6 +32,9 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
> if (!new_pgd)
> goto no_pgd;
>
> + if (cache_ops_need_broadcast())
> + get_cpu();
Is there something wrong with preempt_disable() here and preempt_enable()
below? If it's preempt that we're concerned about, these are the correct
interfaces to be used.
> +
> memset(new_pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
>
> /*
> @@ -42,6 +46,9 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
>
> clean_dcache_area(new_pgd, PTRS_PER_PGD * sizeof(pgd_t));
>
> + if (cache_ops_need_broadcast())
> + put_cpu();
> +
^ permalink raw reply
* [PATCH] omap: dmtimer: convert printk to pr_*
From: Víctor M. Jáquez L. @ 2011-10-06 16:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1317914379.10495.5.camel@Joe-Laptop>
On Thu, Oct 06, 2011 at 08:19:39AM -0700, Joe Perches wrote:
> On Thu, 2011-10-06 at 12:48 +0200, V?ctor Manuel J?quez Leal wrote:
> > Convert all the printk(<level>) messages in the driver to pr_<level>().
> []
> > diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
> []
> > @@ -397,8 +397,7 @@ struct omap_dm_timer *omap_dm_timer_request_specific(int id)
> > spin_lock_irqsave(&dm_timer_lock, flags);
> > if (id <= 0 || id > dm_timer_count || dm_timers[id-1].reserved) {
> > spin_unlock_irqrestore(&dm_timer_lock, flags);
> > - printk("BUG: warning at %s:%d/%s(): unable to get timer %d\n",
> > - __FILE__, __LINE__, __func__, id);
> > + pr_warning("unable to get timer %d\n", id);
>
> For new conversions, please use pr_warn not pr_warning.
> It's shorter and similar to other dev_warn/netdev_warn
> uses.
>
> > dump_stack();
>
> To emit a message then dump stack, please use
> WARN(1, fmt, ...)
>
Thanks a lot!
I'll do that and then resend.
vmjl
^ permalink raw reply
* [PATCH 3/4] ARM: OMAP: Remove calls to SRAM allocations for framebuffer
From: Tony Lindgren @ 2011-10-06 16:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1317890284.1945.38.camel@deskari>
* Tomi Valkeinen <tomi.valkeinen@ti.com> [111006 01:04]:
> On Wed, 2011-10-05 at 15:41 -0700, Tony Lindgren wrote:
> > * Tomi Valkeinen <tomi.valkeinen@ti.com> [111004 23:11]:
> > > On Tue, 2011-10-04 at 17:45 -0700, Tony Lindgren wrote:
> > > > This assumes fixed mappings which will not work once we move
> > > > to use ioremap_exec(). It seems that these are currently
> > > > not in use, or in use for some out of tree corner cases.
> > > >
> > > > If SRAM support for framebuffer is wanted, it should be done
> > > > with ioremap in the driver.
> > > >
> > > > Note that further removal of the code can now be done,
> > > > but that can be done seprately by the driver maintainers.
> > > >
> > > > Cc: Tomi Valkeinen <tomi.valkeinen@ti.com>
> > > > Signed-off-by: Tony Lindgren <tony@atomide.com>
> > >
> > > Looks good to me. I have similar changes in my working branch for omapfb
> > > cleanup.
> > >
> > > Acked-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
> >
> > Thanks. FYI, looks like there's a warning in display.c:
> >
> > arch/arm/mach-omap2/display.c: In function 'omap_display_init':
> > arch/arm/mach-omap2/display.c:93: warning: assignment from incompatible pointer type
> >
> > Do you have a patch for that already?
>
> Paul should have a patch for that in queue ("OMAP: change
> get_context_loss_count ret value to int"). DSS is already using the new
> style function pointer, which uses int for return value (versus the
> current function which returns u32).
OK thanks.
Tony
^ permalink raw reply
* [PATCH v2 1/7] clk: Add a generic clock infrastructure
From: Turquette, Mike @ 2011-10-06 16:11 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4E8D01BE.3020202@codeaurora.org>
On Wed, Oct 5, 2011 at 6:17 PM, Saravana Kannan <skannan@codeaurora.org> wrote:
> On 09/22/2011 03:26 PM, Mike Turquette wrote:
>> + ? ? ? unsigned long ? (*recalc_rate)(struct clk_hw *);
>> + ? ? ? long ? ? ? ? ? ?(*round_rate)(struct clk_hw *, unsigned long);
>> + ? ? ? struct clk * ? ?(*get_parent)(struct clk_hw *);
>> +};
>
> I would like to understand the need for recalc rate if that's something that
> we want to go into the common framework (even if it's optional). I have
> mostly heard only second hand explanations of the need for recalc_rate(), so
> I might not have the full picture. But for all the cases that I can think
> of, recalc_rate seems like a paradox.
Recalc rate has four main uses that I can think of off the top of my head:
1) clk_set_rate is called on clock0, which is a non-leaf clock. All
clocks "below" clock0 have had their rates changed, yet no one called
clk_set_rate on those child clocks. We use recalc to walk the
sub-tree of children and recalculate their rates based on the new rate
of their parent, clock0.
2) exact same as #1, but using clk_set_parent instead of clk_set_rate.
Again, changing the rate of a clock "high up" in the tree will affect
the rates of many child clocks below it.
3) at boot-time/init-time when we don't trust the bootloader and need
to determine the clock rates by parsing registers
4) modeling rates for clocks that we don't really control. This is
not as common as the above three, but there are times when we're
interested in knowing a clock rate (perhaps for debug purposes), but
it's scaling logic is in firmware or somehow independent of the Linux
clock framework.
> If recalc_rate() is used to make sure the "current rate" of a "clock A" is
> always known even if it's parent "clock B"'s rate is changed, then it also
> means that the rate of "clock A" can change without clk_set_rate(clock A,
> new rate). That in turn means that the clk_get_rate() just gives the
> instantaneous snapshot of the rate. So, any use of clk_get_rate(clock A) for
> anything other than printing/logging the return value is broken code. In
For most clocks, the first three examples I give above will cover all
of the times that a clock's rate will change. As long as a
recalc/tree-walk is present then clk->rate is not out of sync and thus
printing/reading that value is not broken.
> which case, do we really care for recalc_rate()? We could just return the
> rate that it was set to when clk_set_rate() was called and call it a day or
> return 0 for such clocks to indicate that the clock rate is "unknown".
What's the point of tracking a rate if it can't be trusted? Also, it
is important to recalc rates whenever changes are made "high up" in
the clock tree once we start to work on rate-change-arbitration
issues, etc.
Regards,
Mike
> The whole concept of trying to recalculate the rate for a clock makes me
> feel uneasy since it promotes misunderstanding the behavior of the clock and
> writing bad code based on that misunderstanding.
>
> I would like to hear to real usecases before I propose some alternatives
> that I have in mind.
>
> Thanks,
> Saravana
>
> --
> Sent by an employee of the Qualcomm Innovation Center, Inc.
> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
>
^ permalink raw reply
* [PATCH 2/2] hw_random: add driver for atmel true hardware random number generator
From: Jamie Iles @ 2011-10-06 16:02 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1317915694-27564-2-git-send-email-jacmet@sunsite.dk>
Hi Peter,
A couple of minor nits inline, but otherwise looks nice to me!
Jamie
On Thu, Oct 06, 2011 at 05:41:34PM +0200, Peter Korsgaard wrote:
> diff --git a/drivers/char/hw_random/atmel-rng.c b/drivers/char/hw_random/atmel-rng.c
> new file mode 100644
> index 0000000..c69eccb
> --- /dev/null
> +++ b/drivers/char/hw_random/atmel-rng.c
> @@ -0,0 +1,168 @@
> +/*
> + * Copyright (c) 2011 Peter Korsgaard <jacmet@sunsite.dk>
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2. This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/err.h>
> +#include <linux/clk.h>
> +#include <linux/io.h>
> +#include <linux/hw_random.h>
> +#include <linux/platform_device.h>
> +
> +#define TRNG_CR 0x00
> +#define TRNG_ISR 0x1c
> +#define TRNG_ODATA 0x50
> +
> +#define TRNG_KEY 0x524e4700 /* RNG */
> +
> +struct atmel_trng {
> + struct clk *clk;
> + void __iomem *base;
> +};
> +
> +static int atmel_trng_read(struct hwrng *rng, void *buf, size_t max,
> + bool wait)
> +{
> + struct atmel_trng *trng = (struct atmel_trng *)rng->priv;
> + u32 *data = buf;
> +
> + /* data ready? */
> + if (readl(trng->base + TRNG_ODATA) & 1) {
> + *data = readl(trng->base + TRNG_ODATA);
> + return 4;
> + } else
> + return 0;
> +}
> +
> +static struct hwrng atmel_trng = {
> + .name = "atmel-trng",
> + .read = atmel_trng_read,
> +};
Could you do:
struct atmel_trng {
struct clk *clk;
void __iomem *base;
struct hwrng rng;
};
#define to_atmel_trng(rng) \
container_of(rng, struct amtel_trng, rng)
which would allow you to support more than one TRNG (although unlikely)
but also means you don't need the cast for priv.
> +static int atmel_trng_probe(struct platform_device *pdev)
> +{
> + struct atmel_trng *trng;
> + struct resource *res;
> + int ret;
> +
> + if (atmel_trng.priv) {
> + dev_err(&pdev->dev, "multiple instances not supported\n");
> + return -EBUSY;
> + }
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (!res)
> + return -EINVAL;
> +
> + trng = devm_kzalloc(&pdev->dev, sizeof(*trng), GFP_KERNEL);
> + if (!trng)
> + return -ENOMEM;
> +
> + if (!devm_request_mem_region(&pdev->dev, res->start,
> + resource_size(res), pdev->name))
> + return -EBUSY;
> +
> + trng->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
> + if (!trng->base)
> + return -EBUSY;
> +
> + trng->clk = clk_get(&pdev->dev, NULL);
> + if (IS_ERR(trng->clk))
> + return PTR_ERR(trng->clk);
> +
> + ret = clk_enable(trng->clk);
> + if (ret)
> + goto err_enable;
> +
> + writel(TRNG_KEY | 1, trng->base + TRNG_CR);
> +
> + atmel_trng.priv = (unsigned long)trng;
> +
> + ret = hwrng_register(&atmel_trng);
> + if (ret)
> + goto err_register;
> +
> + platform_set_drvdata(pdev, trng);
> +
> + return 0;
> +
> +err_register:
> + atmel_trng.priv = 0;
> + clk_disable(trng->clk);
> +err_enable:
> + clk_put(trng->clk);
> +
> + return ret;
> +}
> +
> +static int __devexit atmel_trng_remove(struct platform_device *pdev)
> +{
> + struct atmel_trng *trng = platform_get_drvdata(pdev);
> +
> + hwrng_unregister(&atmel_trng);
> +
> + writel(TRNG_KEY, trng->base + TRNG_CR);
> + clk_disable(trng->clk);
> + clk_put(trng->clk);
> +
> + atmel_trng.priv = 0;
I think this should have a platform_set_drvdata(pdev, NULL) too.
^ permalink raw reply
* [PATCH 1/3 v3] ARM Realview PCIX map include file changes
From: Arnd Bergmann @ 2011-10-06 15:57 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <F01D8B85CFF58440B2A13965FBA90CA47375AC17BD@GEORGE.Emea.Arm.com>
On Thursday 06 October 2011, Colin Tuckley wrote:
> Ah, that wasn't clear from the original email - I was making the changes incrementally and testing as I went.
>
> > This is how it works:
> >
> > 1. The PCI IO window is supposed to be 64K in size.
>
> Yes, that bit was obvious after a bit of thought. I suspect the original value was just a cut 'n paste error.
>
> > 2. "pcibios_min_io" sets the minimum offset into the PCI IO window
> > which
> > PCI IO BARs should be assigned. It is assumed that a PCI IO BAR
> > value
> > of 0 corresponds with the virtual base address of this window.
> > 3. inb() et.al. take the PCI IO offset and not the physical address
> > nor the virtual address of the desired access.
>
> That seems sensible.
>
> However, after changing both __io() and pcibios_min_io as Arnd suggested
> the boot still hangs after " Uncompressing Linux... done, booting the kernel."
No idea. If you send me the full patch, I'll have a look if I can spot
something odd. I can very much recommend debugging this in qemu,
which should support booting your kernels and provide you a
gdb interface to see what's going on.
I noticed that the original code (without your patch) describes a 4KB
I/O space window. Maybe there is a hardware limitation and you actually
have to set PCIBIOS_MIN_IO to zero and IO_SPACE_LIMIT to 0xFFF.
This would however be a fairly unusual hw quirk.
> I did notice that there seems to have been some code changes and
> refactoring in the pci sub-system between 3.1 and 2.6.38 where I
> was testing before. Are there any significant changes I should be
> aware of?
Nothing major, no. There are always patches going in there, but
the fundamental bits stay very stable.
Arnd
^ permalink raw reply
* [PATCH 2/2] hw_random: add driver for atmel true hardware random number generator
From: Peter Korsgaard @ 2011-10-06 15:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20111006154904.GE12975@sirena.org.uk>
>>>>> "Mark" == Mark Brown <broonie@opensource.wolfsonmicro.com> writes:
Mark> On Thu, Oct 06, 2011 at 05:41:34PM +0200, Peter Korsgaard wrote:
>> + trng->clk = clk_get(&pdev->dev, NULL);
>> + if (IS_ERR(trng->clk))
>> + return PTR_ERR(trng->clk);
>> +
>> + ret = clk_enable(trng->clk);
>> + if (ret)
>> + goto err_enable;
Mark> Is it worth enabling the hardware enabled only when the device is open?
Potentially, though I doubt it uses significant power. I kept it like
this for simplicity, to match the other drivers and because hw_random
doesn't have an open/close callback (init is called right away in
hwrng_register or on current change).
--
Bye, Peter Korsgaard
^ permalink raw reply
* [PATCH 2/2] hw_random: add driver for atmel true hardware random number generator
From: Mark Brown @ 2011-10-06 15:49 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1317915694-27564-2-git-send-email-jacmet@sunsite.dk>
On Thu, Oct 06, 2011 at 05:41:34PM +0200, Peter Korsgaard wrote:
> + trng->clk = clk_get(&pdev->dev, NULL);
> + if (IS_ERR(trng->clk))
> + return PTR_ERR(trng->clk);
> +
> + ret = clk_enable(trng->clk);
> + if (ret)
> + goto err_enable;
Is it worth enabling the hardware enabled only when the device is open?
^ permalink raw reply
* [PATCH 1/3] sam9g20ek/9m10g45ek/stam9g20: unbreak build after 'use -EINVAL for invalid gpio'
From: Peter Korsgaard @ 2011-10-06 15:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1317915587-27474-1-git-send-email-jacmet@sunsite.dk>
>>>>> "Peter" == Peter Korsgaard <jacmet@sunsite.dk> writes:
Peter> Commit 36706ab70b26 (ARM: at91/boards: use -EINVAL for invalid gpio)
Peter> broke the build as it used ';' rather than ',' in structure initializers.
Ups, ignore the 1/3 part, this is the only patch in this series.
--
Bye, Peter Korsgaard
^ permalink raw reply
* [PATCH 2/2] hw_random: add driver for atmel true hardware random number generator
From: Peter Korsgaard @ 2011-10-06 15:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1317915694-27564-1-git-send-email-jacmet@sunsite.dk>
For the IP block on 9g45/9g46/9m10/9m11.
Signed-off-by: Peter Korsgaard <jacmet@sunsite.dk>
---
drivers/char/hw_random/Kconfig | 13 +++
drivers/char/hw_random/Makefile | 1 +
drivers/char/hw_random/atmel-rng.c | 168 ++++++++++++++++++++++++++++++++++++
3 files changed, 182 insertions(+), 0 deletions(-)
create mode 100644 drivers/char/hw_random/atmel-rng.c
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index 1d2ebc7..e013587 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -60,6 +60,19 @@ config HW_RANDOM_AMD
If unsure, say Y.
+config HW_RANDOM_ATMEL
+ tristate "Atmel Random Number Generator support"
+ depends on HW_RANDOM && ARCH_AT91SAM9G45
+ default HW_RANDOM
+ ---help---
+ This driver provides kernel-side support for the Random Number
+ Generator hardware found on Atmel AT91 devices.
+
+ To compile this driver as a module, choose M here: the
+ module will be called atmel-rng.
+
+ If unsure, say Y.
+
config HW_RANDOM_GEODE
tristate "AMD Geode HW Random Number Generator support"
depends on HW_RANDOM && X86_32 && PCI
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
index c88f244..b2ff526 100644
--- a/drivers/char/hw_random/Makefile
+++ b/drivers/char/hw_random/Makefile
@@ -7,6 +7,7 @@ rng-core-y := core.o
obj-$(CONFIG_HW_RANDOM_TIMERIOMEM) += timeriomem-rng.o
obj-$(CONFIG_HW_RANDOM_INTEL) += intel-rng.o
obj-$(CONFIG_HW_RANDOM_AMD) += amd-rng.o
+obj-$(CONFIG_HW_RANDOM_ATMEL) += atmel-rng.o
obj-$(CONFIG_HW_RANDOM_GEODE) += geode-rng.o
obj-$(CONFIG_HW_RANDOM_N2RNG) += n2-rng.o
n2-rng-y := n2-drv.o n2-asm.o
diff --git a/drivers/char/hw_random/atmel-rng.c b/drivers/char/hw_random/atmel-rng.c
new file mode 100644
index 0000000..c69eccb
--- /dev/null
+++ b/drivers/char/hw_random/atmel-rng.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2011 Peter Korsgaard <jacmet@sunsite.dk>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/hw_random.h>
+#include <linux/platform_device.h>
+
+#define TRNG_CR 0x00
+#define TRNG_ISR 0x1c
+#define TRNG_ODATA 0x50
+
+#define TRNG_KEY 0x524e4700 /* RNG */
+
+struct atmel_trng {
+ struct clk *clk;
+ void __iomem *base;
+};
+
+static int atmel_trng_read(struct hwrng *rng, void *buf, size_t max,
+ bool wait)
+{
+ struct atmel_trng *trng = (struct atmel_trng *)rng->priv;
+ u32 *data = buf;
+
+ /* data ready? */
+ if (readl(trng->base + TRNG_ODATA) & 1) {
+ *data = readl(trng->base + TRNG_ODATA);
+ return 4;
+ } else
+ return 0;
+}
+
+static struct hwrng atmel_trng = {
+ .name = "atmel-trng",
+ .read = atmel_trng_read,
+};
+
+static int atmel_trng_probe(struct platform_device *pdev)
+{
+ struct atmel_trng *trng;
+ struct resource *res;
+ int ret;
+
+ if (atmel_trng.priv) {
+ dev_err(&pdev->dev, "multiple instances not supported\n");
+ return -EBUSY;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -EINVAL;
+
+ trng = devm_kzalloc(&pdev->dev, sizeof(*trng), GFP_KERNEL);
+ if (!trng)
+ return -ENOMEM;
+
+ if (!devm_request_mem_region(&pdev->dev, res->start,
+ resource_size(res), pdev->name))
+ return -EBUSY;
+
+ trng->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!trng->base)
+ return -EBUSY;
+
+ trng->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(trng->clk))
+ return PTR_ERR(trng->clk);
+
+ ret = clk_enable(trng->clk);
+ if (ret)
+ goto err_enable;
+
+ writel(TRNG_KEY | 1, trng->base + TRNG_CR);
+
+ atmel_trng.priv = (unsigned long)trng;
+
+ ret = hwrng_register(&atmel_trng);
+ if (ret)
+ goto err_register;
+
+ platform_set_drvdata(pdev, trng);
+
+ return 0;
+
+err_register:
+ atmel_trng.priv = 0;
+ clk_disable(trng->clk);
+err_enable:
+ clk_put(trng->clk);
+
+ return ret;
+}
+
+static int __devexit atmel_trng_remove(struct platform_device *pdev)
+{
+ struct atmel_trng *trng = platform_get_drvdata(pdev);
+
+ hwrng_unregister(&atmel_trng);
+
+ writel(TRNG_KEY, trng->base + TRNG_CR);
+ clk_disable(trng->clk);
+ clk_put(trng->clk);
+
+ atmel_trng.priv = 0;
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int atmel_trng_suspend(struct device *dev)
+{
+ struct atmel_trng *trng = dev_get_drvdata(dev);
+
+ clk_disable(trng->clk);
+
+ return 0;
+}
+
+static int atmel_trng_resume(struct device *dev)
+{
+ struct atmel_trng *trng = dev_get_drvdata(dev);
+
+ return clk_enable(trng->clk);
+}
+
+static const struct dev_pm_ops atmel_trng_pm_ops = {
+ .suspend = atmel_trng_suspend,
+ .resume = atmel_trng_resume,
+};
+#endif /* CONFIG_PM */
+
+static struct platform_driver atmel_trng_driver = {
+ .probe = atmel_trng_probe,
+ .remove = __devexit_p(atmel_trng_remove),
+ .driver = {
+ .name = "atmel-trng",
+ .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &atmel_trng_pm_ops,
+#endif /* CONFIG_PM */
+ },
+};
+
+static int __init atmel_trng_init(void)
+{
+ return platform_driver_register(&atmel_trng_driver);
+}
+module_init(atmel_trng_init);
+
+static void __exit atmel_trng_exit(void)
+{
+ platform_driver_unregister(&atmel_trng_driver);
+}
+module_exit(atmel_trng_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>");
+MODULE_DESCRIPTION("Atmel true random number generator driver");
--
1.7.6.3
^ permalink raw reply related
* [PATCH 1/2] sam9g45: add trng clock and platform device
From: Peter Korsgaard @ 2011-10-06 15:41 UTC (permalink / raw)
To: linux-arm-kernel
For the new hw_random driver.
Signed-off-by: Peter Korsgaard <jacmet@sunsite.dk>
---
arch/arm/mach-at91/at91sam9g45.c | 7 +++++++
arch/arm/mach-at91/at91sam9g45_devices.c | 29 +++++++++++++++++++++++++++++
2 files changed, 36 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
index 6da8ace..6850f1d 100644
--- a/arch/arm/mach-at91/at91sam9g45.c
+++ b/arch/arm/mach-at91/at91sam9g45.c
@@ -54,6 +54,11 @@ static struct clk pioDE_clk = {
.pmc_mask = 1 << AT91SAM9G45_ID_PIODE,
.type = CLK_TYPE_PERIPHERAL,
};
+static struct clk trng_clk = {
+ .name = "trng_clk",
+ .pmc_mask = 1 << AT91SAM9G45_ID_TRNG,
+ .type = CLK_TYPE_PERIPHERAL,
+};
static struct clk usart0_clk = {
.name = "usart0_clk",
.pmc_mask = 1 << AT91SAM9G45_ID_US0,
@@ -177,6 +182,7 @@ static struct clk *periph_clocks[] __initdata = {
&pioB_clk,
&pioC_clk,
&pioDE_clk,
+ &trng_clk,
&usart0_clk,
&usart1_clk,
&usart2_clk,
@@ -216,6 +222,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.1", &tcb0_clk),
CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
+ CLKDEV_CON_DEV_ID(NULL, "atmel-trng", &trng_clk),
/* fake hclk clock */
CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &uhphs_clk),
};
diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
index 2ee20bd..1ca6c62 100644
--- a/arch/arm/mach-at91/at91sam9g45_devices.c
+++ b/arch/arm/mach-at91/at91sam9g45_devices.c
@@ -1101,6 +1101,34 @@ static void __init at91_add_device_rtt(void)
/* --------------------------------------------------------------------
+ * TRNG
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_HW_RANDOM_ATMEL) || defined(CONFIG_HW_RANDOM_ATMEL_MODULE)
+static struct resource trng_resources[] = {
+ {
+ .start = AT91SAM9G45_BASE_TRNG,
+ .end = AT91SAM9G45_BASE_TRNG + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device at91sam9g45_trng_device = {
+ .name = "atmel-trng",
+ .id = -1,
+ .resource = trng_resources,
+ .num_resources = ARRAY_SIZE(trng_resources),
+};
+
+static void __init at91_add_device_trng(void)
+{
+ platform_device_register(&at91sam9g45_trng_device);
+}
+#else
+static void __init at91_add_device_trng(void) {}
+#endif
+
+/* --------------------------------------------------------------------
* Watchdog
* -------------------------------------------------------------------- */
@@ -1589,6 +1617,7 @@ static int __init at91_add_standard_devices(void)
at91_add_device_hdmac();
at91_add_device_rtc();
at91_add_device_rtt();
+ at91_add_device_trng();
at91_add_device_watchdog();
at91_add_device_tc();
return 0;
--
1.7.6.3
^ permalink raw reply related
* [PATCH 1/3] sam9g20ek/9m10g45ek/stam9g20: unbreak build after 'use -EINVAL for invalid gpio'
From: Peter Korsgaard @ 2011-10-06 15:39 UTC (permalink / raw)
To: linux-arm-kernel
Commit 36706ab70b26 (ARM: at91/boards: use -EINVAL for invalid gpio)
broke the build as it used ';' rather than ',' in structure initializers.
Signed-off-by: Peter Korsgaard <jacmet@sunsite.dk>
---
arch/arm/mach-at91/board-sam9g20ek.c | 2 +-
arch/arm/mach-at91/board-sam9m10g45ek.c | 2 +-
arch/arm/mach-at91/board-stamp9g20.c | 4 ++--
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/arch/arm/mach-at91/board-sam9g20ek.c b/arch/arm/mach-at91/board-sam9g20ek.c
index 1c6dfbb..27943c2 100644
--- a/arch/arm/mach-at91/board-sam9g20ek.c
+++ b/arch/arm/mach-at91/board-sam9g20ek.c
@@ -212,7 +212,7 @@ static struct mci_platform_data __initdata ek_mmc_data = {
.slot[1] = {
.bus_width = 4,
.detect_pin = AT91_PIN_PC9,
- .wp_pin = -1;
+ .wp_pin = -1,
},
};
diff --git a/arch/arm/mach-at91/board-sam9m10g45ek.c b/arch/arm/mach-at91/board-sam9m10g45ek.c
index 3d68ead..008088a 100644
--- a/arch/arm/mach-at91/board-sam9m10g45ek.c
+++ b/arch/arm/mach-at91/board-sam9m10g45ek.c
@@ -100,7 +100,7 @@ static struct mci_platform_data __initdata mci0_data = {
.slot[0] = {
.bus_width = 4,
.detect_pin = AT91_PIN_PD10,
- .wp_pin = -1;
+ .wp_pin = -1,
},
};
diff --git a/arch/arm/mach-at91/board-stamp9g20.c b/arch/arm/mach-at91/board-stamp9g20.c
index 3c0cc86..cb4a840 100644
--- a/arch/arm/mach-at91/board-stamp9g20.c
+++ b/arch/arm/mach-at91/board-stamp9g20.c
@@ -123,8 +123,8 @@ static void __init add_device_nand(void)
static struct mci_platform_data __initdata mmc_data = {
.slot[0] = {
.bus_width = 4,
- .detect_pin = -1;
- .wp_pin = -1;
+ .detect_pin = -1,
+ .wp_pin = -1,
},
};
#else
--
1.7.6.3
^ permalink raw reply related
* [PATCH] omap: dmtimer: convert printk to pr_*
From: Joe Perches @ 2011-10-06 15:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1317898106-1891-1-git-send-email-vjaquez@igalia.com>
On Thu, 2011-10-06 at 12:48 +0200, V?ctor Manuel J?quez Leal wrote:
> Convert all the printk(<level>) messages in the driver to pr_<level>().
[]
> diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
[]
> @@ -397,8 +397,7 @@ struct omap_dm_timer *omap_dm_timer_request_specific(int id)
> spin_lock_irqsave(&dm_timer_lock, flags);
> if (id <= 0 || id > dm_timer_count || dm_timers[id-1].reserved) {
> spin_unlock_irqrestore(&dm_timer_lock, flags);
> - printk("BUG: warning at %s:%d/%s(): unable to get timer %d\n",
> - __FILE__, __LINE__, __func__, id);
> + pr_warning("unable to get timer %d\n", id);
For new conversions, please use pr_warn not pr_warning.
It's shorter and similar to other dev_warn/netdev_warn
uses.
> dump_stack();
To emit a message then dump stack, please use
WARN(1, fmt, ...)
^ permalink raw reply
* [PATCH] arm: Add VIRTUALIZATION configuration menu and virtio options
From: Pawel Moll @ 2011-10-06 15:00 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20111006144601.GE26349@n2100.arm.linux.org.uk>
> > This patch adds menuconfig VIRTUALIZATION to arm Kconfig
> > and includes virtio Kconfig in it.
I had another look and it's actually not needed any more, as since
e72542191cbba4cf7fda21cb22e26b42d7415daf "virtio: expose for
non-virtualization users too" the drivers/virtio/Kconfig is included in
drivers/Kconfig.
> Please resubmit without the line above. default n is default's default
> default, so it's completely redundant by default.
We have 606 redundant defaults then:
$ find . -name Kconfig\* | xargs grep "default n" | wc -l
606
Not something that would make me sleepless ;-)
Cheers!
Pawe?
^ permalink raw reply
* [PATCH 1/3 v3] ARM Realview PCIX map include file changes
From: Colin Tuckley @ 2011-10-06 14:50 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20111006142350.GD26349@n2100.arm.linux.org.uk>
> -----Original Message-----
> From: Russell King - ARM Linux [mailto:linux at arm.linux.org.uk]
> Subject: Re: [PATCH 1/3 v3] ARM Realview PCIX map include file changes
> All the points in this email all go together.
Ah, that wasn't clear from the original email - I was making the changes incrementally and testing as I went.
> This is how it works:
>
> 1. The PCI IO window is _supposed_ to be 64K in size.
Yes, that bit was obvious after a bit of thought. I suspect the original value was just a cut 'n paste error.
> 2. "pcibios_min_io" sets the minimum offset into the PCI IO window
> which
> PCI IO BARs should be assigned. It is assumed that a PCI IO BAR
> value
> of 0 corresponds with the virtual base address of this window.
> 3. inb() et.al. take the PCI IO offset and _not_ the physical address
> nor the virtual address of the desired access.
That seems sensible.
However, after changing both __io() and pcibios_min_io as Arnd suggested the boot still hangs after " Uncompressing Linux... done, booting the kernel."
I did notice that there seems to have been some code changes and refactoring in the pci sub-system between 3.1 and 2.6.38 where I was testing before. Are there any significant changes I should be aware of?
Colin
-- IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.
^ permalink raw reply
* [PATCH] arm: Add VIRTUALIZATION configuration menu and virtio options
From: Russell King - ARM Linux @ 2011-10-06 14:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1317224886-3925-1-git-send-email-pawel.moll@arm.com>
On Wed, Sep 28, 2011 at 04:48:06PM +0100, Pawel Moll wrote:
> This patch adds menuconfig VIRTUALIZATION to arm Kconfig
> and includes virtio Kconfig in it.
>
> Signed-off-by: Pawel Moll <pawel.moll@arm.com>
> ---
> arch/arm/Kconfig | 16 ++++++++++++++++
> 1 files changed, 16 insertions(+), 0 deletions(-)
>
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index 3269576..426f330 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -2101,4 +2101,20 @@ source "security/Kconfig"
>
> source "crypto/Kconfig"
>
> +menuconfig VIRTUALIZATION
> + bool "Virtualization"
> + default n
Please resubmit without the line above. default n is default's default
default, so it's completely redundant by default.
^ permalink raw reply
* [PATCH RESEND] mmc: sdio: rw extended, use a sg entry for each block
From: Nicolas Ferre @ 2011-10-06 14:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316598039-30238-1-git-send-email-nicolas.ferre@atmel.com>
On 09/21/2011 11:40 AM, Nicolas Ferre :
> While using io multiple blocks operations, change the way that sg is built:
> use one sg entry for each block instead of aggregating the whole buffer
> in a single sg entry.
> Using a single sg entry for a multiple block command may lead to
> misunderstanding between the sd/mmc and the DMA controllers. In fact, the
> knowledge of the block length will allow both controllers to optimize burst
> sizes on internal bus while dealing with those data.
After having performed some tests I realize that it seems quite
difficult to benchmark this particular case (SDIO, CMD53, multi-block
case). Moreover, the SDIO card that I use is triggering this case on
pretty small blocks (16 x 32 bytes). For the record, I use Marvell 8686
with libertas driver.
The benchmark results hardly show an improvement! I guess that the
benefit of having optimized transfers on internal bus is completely
concealed by the overhead of multiple small blocks management by DMA...
Hopefully another SDIO card can use bigger multiple blocks but it could
be difficult to adapt this piece of code to the size of the block itself...
So, do you have ideas about how I can trigger bigger multiple SDIO and
test further?
> Use a sg table to store start addresses of blocks within the data buffer.
>
> Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
> ---
> drivers/mmc/core/sdio_ops.c | 38 +++++++++++++++++++++++++++++---------
For my platform the alternative would be to re-configure at runtime the
chunck size (max size of bursts between sd controller and DMA).
This operation will be conditioned by the identification of this case
(SDIO, CMD53, multi-block) and will involve both DMA and sd/mmc drivers.
I fear that it can be heavyweight.
> 1 files changed, 29 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c
> index f087d87..aea6978 100644
> --- a/drivers/mmc/core/sdio_ops.c
> +++ b/drivers/mmc/core/sdio_ops.c
> @@ -124,7 +124,7 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
> struct mmc_request mrq = {0};
> struct mmc_command cmd = {0};
> struct mmc_data data = {0};
> - struct scatterlist sg;
> + struct sg_table sgt;
>
> BUG_ON(!card);
> BUG_ON(fn > 7);
> @@ -144,24 +144,44 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
> cmd.arg |= fn << 28;
> cmd.arg |= incr_addr ? 0x04000000 : 0x00000000;
> cmd.arg |= addr << 9;
> - if (blocks == 1 && blksz <= 512)
> - cmd.arg |= (blksz == 512) ? 0 : blksz; /* byte mode */
> - else
> - cmd.arg |= 0x08000000 | blocks; /* block mode */
> + if (blocks == 1 && blksz <= 512) {
> + /* byte mode */
> + struct scatterlist sg;
> +
> + cmd.arg |= (blksz == 512) ? 0 : blksz;
> + sg_init_one(&sg, buf, blksz * blocks);
> +
> + data.sg = &sg;
> + data.sg_len = 1;
> + } else {
> + /* block mode */
> + struct scatterlist *sg_ptr;
> + int i;
> +
> + cmd.arg |= 0x08000000 | blocks;
> + if (sg_alloc_table(&sgt, blocks, GFP_KERNEL))
> + return -ENOMEM;
> + for_each_sg(sgt.sgl, sg_ptr, sgt.nents, i) {
> + sg_set_buf(sg_ptr, buf + i * blksz, blksz);
> + }
> +
> + data.sg = sgt.sgl;
> + data.sg_len = sgt.nents;
> + }
> +
> cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC;
>
> data.blksz = blksz;
> data.blocks = blocks;
> data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
> - data.sg = &sg;
> - data.sg_len = 1;
> -
> - sg_init_one(&sg, buf, blksz * blocks);
>
> mmc_set_data_timeout(&data, card);
>
> mmc_wait_for_req(card->host, &mrq);
>
> + if (blocks != 1 || blksz > 512)
> + sg_free_table(&sgt);
> +
> if (cmd.error)
> return cmd.error;
> if (data.error)
Best regards,
--
Nicolas Ferre
^ permalink raw reply
* [PATCH 1/3 v3] ARM Realview PCIX map include file changes
From: Russell King - ARM Linux @ 2011-10-06 14:23 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <F01D8B85CFF58440B2A13965FBA90CA47375AC1794@GEORGE.Emea.Arm.com>
On Thu, Oct 06, 2011 at 03:00:50PM +0100, Colin Tuckley wrote:
> > pcibios_min_io should be 0x1000 as a constant, in order to get the
> > ISA addresses out of the way, but there is no need to make it
> > board dependent.
>
> REALVIEW_PB_PCI_IO_BASE is currently 0x90050000, which works, so
> why would I change pcibios_min_io to 0x1000 ?
All the points in this email all go together.
This is how it works:
1. The PCI IO window is _supposed_ to be 64K in size.
2. "pcibios_min_io" sets the minimum offset into the PCI IO window which
PCI IO BARs should be assigned. It is assumed that a PCI IO BAR value
of 0 corresponds with the virtual base address of this window.
3. inb() et.al. take the PCI IO offset and _not_ the physical address nor
the virtual address of the desired access.
This is so that existing drivers - including VGA card drivers - can work.
There are many PCI cards which require accesses to specific IO locations
not listed in their BARs for initialization etc.
Moreover, we're trying to work towards having a single fixed 64k PCI IO
virtual mapping across all platforms (so that this shows up at the same
virtual address no matter what platform.) Not having this is a blocker
to the multi-platform activity which Linaro is tasked with.
^ 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