[PATCHv2 01/10] remoteproc: Bugfix: Deallocate firmware image on shutdown

2013-02-21 Thread sjur . brandeland
From: Dmitry Tarnyagin 

Fixes coherent memory leakage, caused by non-deallocated
firmware image chunk.

Signed-off-by: Dmitry Tarnyagin 
---
 drivers/remoteproc/ste_modem_rproc.c |7 ++-
 1 files changed, 6 insertions(+), 1 deletions(-)

diff --git a/drivers/remoteproc/ste_modem_rproc.c 
b/drivers/remoteproc/ste_modem_rproc.c
index a7743c0..fb95c42 100644
--- a/drivers/remoteproc/ste_modem_rproc.c
+++ b/drivers/remoteproc/ste_modem_rproc.c
@@ -240,6 +240,8 @@ static int sproc_drv_remove(struct platform_device *pdev)
 
/* Unregister as remoteproc device */
rproc_del(sproc->rproc);
+   dma_free_coherent(sproc->rproc->dev.parent, SPROC_FW_SIZE,
+ sproc->fw_addr, sproc->fw_dma_addr);
rproc_put(sproc->rproc);
 
mdev->drv_data = NULL;
@@ -297,10 +299,13 @@ static int sproc_probe(struct platform_device *pdev)
/* Register as a remoteproc device */
err = rproc_add(rproc);
if (err)
-   goto free_rproc;
+   goto free_mem;
 
return 0;
 
+free_mem:
+   dma_free_coherent(rproc->dev.parent, SPROC_FW_SIZE,
+ sproc->fw_addr, sproc->fw_dma_addr);
 free_rproc:
/* Reset device data upon error */
mdev->drv_data = NULL;
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCHv2 10/10] remoteproc: Set vring addresses in resource table

2013-02-21 Thread sjur . brandeland
From: Sjur Brændeland 

Set the vring addresses in the resource table so that
the remote device can read the actual addresses used.

Signed-off-by: Sjur Brændeland 
---
 drivers/remoteproc/remoteproc_core.c |   19 +--
 1 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_core.c 
b/drivers/remoteproc/remoteproc_core.c
index 93529e3..63f3d07 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -194,6 +194,7 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i)
struct rproc *rproc = rvdev->rproc;
struct device *dev = &rproc->dev;
struct rproc_vring *rvring = &rvdev->vring[i];
+   struct fw_rsc_vdev *rsc;
dma_addr_t dma;
void *va;
int ret, size, notifyid;
@@ -209,7 +210,6 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i)
/*
 * Allocate non-cacheable memory for the vring. In the future
 * this call will also configure the IOMMU for us
-* TODO: let the rproc know the da of this vring
 */
va = dma_alloc_coherent(dev->parent, size, &dma, GFP_KERNEL);
if (!va) {
@@ -220,7 +220,6 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i)
/*
 * Assign an rproc-wide unique index for this vring
 * TODO: assign a notifyid for rvdev updates as well
-* TODO: let the rproc know the notifyid of this vring
 * TODO: support predefined notifyids (via resource table)
 */
ret = idr_get_new(&rproc->notifyids, rvring, ¬ifyid);
@@ -237,6 +236,15 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i)
rvring->dma = dma;
rvring->notifyid = notifyid;
 
+   /*
+* Let the rproc know the notifyid and da of this vring.
+* Not all platforms use dma_alloc_coherent to automatically
+* set up the iommu. In this case the device address (da) will
+* hold the physical address and not the device address.
+*/
+   rsc = (void *)rproc->rsc + rvdev->rsc_offset;
+   rsc->vring[i].da = dma;
+   rsc->vring[i].notifyid = notifyid;
return 0;
 }
 
@@ -275,9 +283,16 @@ void rproc_free_vring(struct rproc_vring *rvring)
 {
int size = PAGE_ALIGN(vring_size(rvring->len, rvring->align));
struct rproc *rproc = rvring->rvdev->rproc;
+   int idx = rvring->rvdev->vring - rvring;
+   struct fw_rsc_vdev *rsc;
 
dma_free_coherent(rproc->dev.parent, size, rvring->va, rvring->dma);
idr_remove(&rproc->notifyids, rvring->notifyid);
+
+   /* reset resource entry info */
+   rsc = (void *)rproc->rsc + rvring->rvdev->rsc_offset;
+   rsc->vring[idx].da = 0;
+   rsc->vring[idx].notifyid = -1;
 }
 
 /**
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCHv2 08/10] remoteproc: Always perserve resource table data

2013-02-21 Thread sjur . brandeland
From: Sjur Brændeland 

Copy resource table from first to second firmware loading.
After firmware is loaded to memory, update the vdevs resource
pointer to the resource table kept in device memory.

Signed-off-by: Sjur Brændeland 
---
 drivers/remoteproc/Kconfig   |1 +
 drivers/remoteproc/remoteproc_core.c |   99 ++---
 include/linux/remoteproc.h   |9 +++
 3 files changed, 88 insertions(+), 21 deletions(-)

diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index 96ce101..ea060e9 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -5,6 +5,7 @@ config REMOTEPROC
tristate
depends on EXPERIMENTAL
depends on HAS_DMA
+   select CRC32
select FW_CONFIG
select VIRTIO
 
diff --git a/drivers/remoteproc/remoteproc_core.c 
b/drivers/remoteproc/remoteproc_core.c
index a747d95..6466f39 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -37,6 +37,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -45,7 +46,8 @@
 
 typedef int (*rproc_handle_resources_t)(struct rproc *rproc,
struct resource_table *table, int len);
-typedef int (*rproc_handle_resource_t)(struct rproc *rproc, void *, int avail);
+typedef int (*rproc_handle_resource_t)(struct rproc *rproc,
+void *, int offset, int avail);
 
 /* Unique indices for remoteproc devices */
 static DEFINE_IDA(rproc_dev_index);
@@ -306,7 +308,7 @@ void rproc_free_vring(struct rproc_vring *rvring)
  * Returns 0 on success, or an appropriate error code otherwise
  */
 static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc,
-   int avail)
+   int offset, int avail)
 {
struct device *dev = &rproc->dev;
struct rproc_vdev *rvdev;
@@ -350,6 +352,9 @@ static int rproc_handle_vdev(struct rproc *rproc, struct 
fw_rsc_vdev *rsc,
/* remember the device features */
rvdev->dfeatures = rsc->dfeatures;
 
+   /* remember the resource offset*/
+   rvdev->rsc_offset = offset;
+
list_add_tail(&rvdev->node, &rproc->rvdevs);
 
/* it is now safe to add the virtio device */
@@ -383,7 +388,7 @@ free_rvdev:
  * Returns 0 on success, or an appropriate error code otherwise
  */
 static int rproc_handle_trace(struct rproc *rproc, struct fw_rsc_trace *rsc,
-   int avail)
+   int offset, int avail)
 {
struct rproc_mem_entry *trace;
struct device *dev = &rproc->dev;
@@ -465,7 +470,7 @@ static int rproc_handle_trace(struct rproc *rproc, struct 
fw_rsc_trace *rsc,
  * are outside those ranges.
  */
 static int rproc_handle_devmem(struct rproc *rproc, struct fw_rsc_devmem *rsc,
-   int avail)
+   int offset, int avail)
 {
struct rproc_mem_entry *mapping;
struct device *dev = &rproc->dev;
@@ -538,7 +543,9 @@ out:
  * pressure is important; it may have a substantial impact on performance.
  */
 static int rproc_handle_carveout(struct rproc *rproc,
-   struct fw_rsc_carveout *rsc, int avail)
+   struct fw_rsc_carveout *rsc,
+   int offset, int avail)
+
 {
struct rproc_mem_entry *carveout, *mapping;
struct device *dev = &rproc->dev;
@@ -661,7 +668,7 @@ free_carv:
 }
 
 static int rproc_handle_notifyid(struct rproc *rproc, struct fw_rsc_vdev *rsc,
-   int avail)
+   int offset, int avail)
 {
/* Summerize the number of notification IDs */
rproc->max_notifyid += rsc->num_of_vrings;
@@ -690,17 +697,16 @@ static rproc_handle_resource_t 
rproc_handle_notifyid_rsc[RSC_LAST] = {
 
 /* handle firmware resource entries before booting the remote processor */
 static int
-rproc_handle_resource(struct rproc *rproc, struct resource_table *table,
-   int len,
-   rproc_handle_resource_t handlers[RSC_LAST])
+rproc_handle_resource(struct rproc *rproc, int len,
+ rproc_handle_resource_t handlers[RSC_LAST])
 {
struct device *dev = &rproc->dev;
rproc_handle_resource_t handler;
int ret = 0, i;
 
-   for (i = 0; i < table->num; i++) {
-   int offset = table->offset[i];
-   struct fw_rsc_hdr *hdr = (void *)table + offset;
+   for (i = 0; i < rproc->rsc->num; i++) {
+   int offset = rproc->rsc->offset[i];
+   struct fw_rsc_hd

[PATCHv2 09/10] remoteproc: Support virtio config space.

2013-02-21 Thread sjur . brandeland
From: Sjur Brændeland 

Support virtio configuration space and device status. The virtio
device can now access the resource table in shared memory.

Signed-off-by: Sjur Brændeland 
---
 drivers/remoteproc/remoteproc_core.c   |3 --
 drivers/remoteproc/remoteproc_virtio.c |   61 
 include/linux/remoteproc.h |4 --
 3 files changed, 46 insertions(+), 22 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_core.c 
b/drivers/remoteproc/remoteproc_core.c
index 6466f39..93529e3 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -349,9 +349,6 @@ static int rproc_handle_vdev(struct rproc *rproc, struct 
fw_rsc_vdev *rsc,
goto free_rvdev;
}
 
-   /* remember the device features */
-   rvdev->dfeatures = rsc->dfeatures;
-
/* remember the resource offset*/
rvdev->rsc_offset = offset;
 
diff --git a/drivers/remoteproc/remoteproc_virtio.c 
b/drivers/remoteproc/remoteproc_virtio.c
index 9e198e5..b32bf1f 100644
--- a/drivers/remoteproc/remoteproc_virtio.c
+++ b/drivers/remoteproc/remoteproc_virtio.c
@@ -173,25 +173,29 @@ error:
return ret;
 }
 
-/*
- * We don't support yet real virtio status semantics.
- *
- * The plan is to provide this via the VDEV resource entry
- * which is part of the firmware: this way the remote processor
- * will be able to access the status values as set by us.
- */
 static u8 rproc_virtio_get_status(struct virtio_device *vdev)
 {
-   return 0;
+   struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
+   struct fw_rsc_vdev *rsc = (void *)rvdev->rproc->rsc + rvdev->rsc_offset;
+
+   return rsc->status;
 }
 
 static void rproc_virtio_set_status(struct virtio_device *vdev, u8 status)
 {
+   struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
+   struct fw_rsc_vdev *rsc = (void *)rvdev->rproc->rsc + rvdev->rsc_offset;
+
+   rsc->status = status;
dev_dbg(&vdev->dev, "status: %d\n", status);
 }
 
 static void rproc_virtio_reset(struct virtio_device *vdev)
 {
+   struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
+   struct fw_rsc_vdev *rsc = (void *)rvdev->rproc->rsc + rvdev->rsc_offset;
+
+   rsc->status = 0;
dev_dbg(&vdev->dev, "reset !\n");
 }
 
@@ -199,13 +203,15 @@ static void rproc_virtio_reset(struct virtio_device *vdev)
 static u32 rproc_virtio_get_features(struct virtio_device *vdev)
 {
struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
+   struct fw_rsc_vdev *rsc = (void *)rvdev->rproc->rsc + rvdev->rsc_offset;
 
-   return rvdev->dfeatures;
+   return rsc->dfeatures;
 }
 
 static void rproc_virtio_finalize_features(struct virtio_device *vdev)
 {
struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
+   struct fw_rsc_vdev *rsc = (void *)rvdev->rproc->rsc + rvdev->rsc_offset;
 
/* Give virtio_ring a chance to accept features */
vring_transport_features(vdev);
@@ -213,13 +219,36 @@ static void rproc_virtio_finalize_features(struct 
virtio_device *vdev)
/*
 * Remember the finalized features of our vdev, and provide it
 * to the remote processor once it is powered on.
-*
-* Similarly to the status field, we don't expose yet the negotiated
-* features to the remote processors at this point. This will be
-* fixed as part of a small resource table overhaul and then an
-* extension of the virtio resource entries.
 */
-   rvdev->gfeatures = vdev->features[0];
+   rsc->gfeatures = vdev->features[0];
+}
+
+static void rproc_virtio_get(struct virtio_device *vdev, unsigned offset,
+   void *buf, unsigned len)
+{
+   struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
+   struct fw_rsc_vdev *rsc = (void *)rvdev->rproc->rsc + rvdev->rsc_offset;
+   void *cfg = &rsc->vring[rsc->num_of_vrings];
+
+   if (offset + len > rsc->config_len || offset + len < len)
+   dev_err(&vdev->dev,
+   "rproc_virtio_get: access out of bounds\n");
+   else
+   memcpy(buf, cfg + offset, len);
+}
+
+static void rproc_virtio_set(struct virtio_device *vdev, unsigned offset,
+ const void *buf, unsigned len)
+{
+   struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
+   struct fw_rsc_vdev *rsc = (void *)rvdev->rproc->rsc + rvdev->rsc_offset;
+   void *cfg = &rsc->vring[rsc->num_of_vrings];
+
+   if (offset + len > rsc->config_len || offset + len < len)
+   dev_err(&vdev->dev,
+   "rproc_virtio_set: access out of bounds\n");
+   else
+   memcpy(cfg + offset, buf, len);
 }
 
 static struct virtio_config_ops rproc_virtio_config_ops = {
@@ -230,6 +259,8 @@ static struct virtio_config_ops rproc_virtio_config_ops = {
.reset  = rproc_virtio_reset,
.set_status = rproc_virtio_set_status,
.get_statu

[PATCHv2 05/10] remoteproc: Parse STE-firmware and find resource table address

2013-02-21 Thread sjur . brandeland
From: Sjur Brændeland 

Parse the STE firmware and scan the TOC-table to find the address
of the resource table.

Signed-off-by: Sjur Brændeland 
---
 drivers/remoteproc/remoteproc_elf_loader.c |2 +-
 drivers/remoteproc/remoteproc_internal.h   |6 ++--
 drivers/remoteproc/ste_modem_rproc.c   |   43 +++-
 3 files changed, 33 insertions(+), 18 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_elf_loader.c 
b/drivers/remoteproc/remoteproc_elf_loader.c
index 3d6ec76..b93551f 100644
--- a/drivers/remoteproc/remoteproc_elf_loader.c
+++ b/drivers/remoteproc/remoteproc_elf_loader.c
@@ -323,5 +323,5 @@ const struct rproc_fw_ops rproc_elf_fw_ops = {
.find_rsc_table = rproc_elf_find_rsc_table,
.sanity_check = rproc_elf_sanity_check,
.get_boot_addr = rproc_elf_get_boot_addr,
-   .get_rsctab_va = rproc_elf_get_rsctab_addr
+   .get_rsctab_va = rproc_elf_get_rsctab_va
 };
diff --git a/drivers/remoteproc/remoteproc_internal.h 
b/drivers/remoteproc/remoteproc_internal.h
index b7372b1..91aa7ca 100644
--- a/drivers/remoteproc/remoteproc_internal.h
+++ b/drivers/remoteproc/remoteproc_internal.h
@@ -106,11 +106,11 @@ struct resource_table *rproc_find_rsc_table(struct rproc 
*rproc,
 }
 
 static inline
-struct resource_table *rproc_get_rsctab_addr(struct rproc *rproc,
+struct resource_table *rproc_get_rsctab_va(struct rproc *rproc,
const struct firmware *fw)
 {
-   if (rproc->fw_ops->get_rsctab_addr)
-   return rproc->fw_ops->get_rsctab_addr(rproc, fw);
+   if (rproc->fw_ops->get_rsctab_va)
+   return rproc->fw_ops->get_rsctab_va(rproc, fw);
 
return NULL;
 }
diff --git a/drivers/remoteproc/ste_modem_rproc.c 
b/drivers/remoteproc/ste_modem_rproc.c
index fb95c42..09f1b4e 100644
--- a/drivers/remoteproc/ste_modem_rproc.c
+++ b/drivers/remoteproc/ste_modem_rproc.c
@@ -64,26 +64,18 @@ static int sproc_load_segments(struct rproc *rproc, const 
struct firmware *fw)
 }
 
 /* Find the entry for resource table in the Table of Content */
-static struct ste_toc_entry *sproc_find_rsc_entry(const struct firmware *fw)
+static const struct ste_toc_entry *sproc_find_rsc_entry(const void *data)
 {
int i;
-   struct ste_toc *toc;
-
-   if (!fw)
-   return NULL;
-
-   toc = (void *)fw->data;
+   const struct ste_toc *toc;
+   toc = data;
 
/* Search the table for the resource table */
for (i = 0; i < SPROC_MAX_TOC_ENTRIES &&
toc->table[i].start != 0x; i++) {
-
if (!strncmp(toc->table[i].name, SPROC_RESOURCE_NAME,
-sizeof(toc->table[i].name))) {
-   if (toc->table[i].start > fw->size)
-   return NULL;
+sizeof(toc->table[i].name)))
return &toc->table[i];
-   }
}
 
return NULL;
@@ -96,9 +88,12 @@ sproc_find_rsc_table(struct rproc *rproc, const struct 
firmware *fw,
 {
struct sproc *sproc = rproc->priv;
struct resource_table *table;
-   struct ste_toc_entry *entry;
+   const struct ste_toc_entry *entry;
 
-   entry = sproc_find_rsc_entry(fw);
+   if (!fw)
+   return NULL;
+
+   entry = sproc_find_rsc_entry(fw->data);
if (!entry) {
sproc_err(sproc, "resource table not found in fw\n");
return NULL;
@@ -149,10 +144,30 @@ sproc_find_rsc_table(struct rproc *rproc, const struct 
firmware *fw,
return table;
 }
 
+/* Find the resource table inside the remote processor's firmware. */
+static struct resource_table *
+sproc_get_rsctab_va(struct rproc *rproc, const struct firmware *fw)
+{
+   struct sproc *sproc = rproc->priv;
+   const struct ste_toc_entry *entry;
+
+   if (!fw || !sproc->fw_addr)
+   return NULL;
+
+   entry = sproc_find_rsc_entry(sproc->fw_addr);
+   if (!entry) {
+   sproc_err(sproc, "resource table not found in fw\n");
+   return NULL;
+   }
+
+   return sproc->fw_addr + entry->start;
+}
+
 /* STE modem firmware handler operations */
 const struct rproc_fw_ops sproc_fw_ops = {
.load = sproc_load_segments,
.find_rsc_table = sproc_find_rsc_table,
+   .get_rsctab_va = sproc_get_rsctab_va,
 };
 
 /* Kick the modem with specified notification id */
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCHv2 07/10] remoteproc: Calculate max_notifyid by counting vrings

2013-02-21 Thread sjur . brandeland
From: Sjur Brændeland 

Simplify handling of max_notifyid by simply counting the
number of vrings.

Signed-off-by: Sjur Brændeland 
---
 drivers/remoteproc/remoteproc_core.c |   33 ++---
 drivers/remoteproc/ste_modem_rproc.c |2 +-
 2 files changed, 19 insertions(+), 16 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_core.c 
b/drivers/remoteproc/remoteproc_core.c
index 6e515d7..a747d95 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -228,9 +228,6 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i)
return ret;
}
 
-   /* Store largest notifyid */
-   rproc->max_notifyid = max(rproc->max_notifyid, notifyid);
-
dev_dbg(dev, "vring%d: va %p dma %llx size %x idr %d\n", i, va,
(unsigned long long)dma, size, notifyid);
 
@@ -272,25 +269,13 @@ rproc_parse_vring(struct rproc_vdev *rvdev, struct 
fw_rsc_vdev *rsc, int i)
return 0;
 }
 
-static int rproc_max_notifyid(int id, void *p, void *data)
-{
-   int *maxid = data;
-   *maxid = max(*maxid, id);
-   return 0;
-}
-
 void rproc_free_vring(struct rproc_vring *rvring)
 {
int size = PAGE_ALIGN(vring_size(rvring->len, rvring->align));
struct rproc *rproc = rvring->rvdev->rproc;
-   int maxid = 0;
 
dma_free_coherent(rproc->dev.parent, size, rvring->va, rvring->dma);
idr_remove(&rproc->notifyids, rvring->notifyid);
-
-   /* Find the largest remaining notifyid */
-   idr_for_each(&rproc->notifyids, rproc_max_notifyid, &maxid);
-   rproc->max_notifyid = maxid;
 }
 
 /**
@@ -675,6 +660,15 @@ free_carv:
return ret;
 }
 
+static int rproc_handle_notifyid(struct rproc *rproc, struct fw_rsc_vdev *rsc,
+   int avail)
+{
+   /* Summerize the number of notification IDs */
+   rproc->max_notifyid += rsc->num_of_vrings;
+
+   return 0;
+}
+
 /*
  * A lookup table for resource handlers. The indices are defined in
  * enum fw_resource_type.
@@ -690,6 +684,10 @@ static rproc_handle_resource_t 
rproc_handle_vdev_rsc[RSC_LAST] = {
[RSC_VDEV] = (rproc_handle_resource_t)rproc_handle_vdev,
 };
 
+static rproc_handle_resource_t rproc_handle_notifyid_rsc[RSC_LAST] = {
+   [RSC_VDEV] = (rproc_handle_resource_t)rproc_handle_notifyid,
+};
+
 /* handle firmware resource entries before booting the remote processor */
 static int
 rproc_handle_resource(struct rproc *rproc, struct resource_table *table,
@@ -864,6 +862,11 @@ static void rproc_fw_config_virtio(const struct firmware 
*fw, void *context)
if (!table)
goto out;
 
+   /* count the number of notify-ids */
+   rproc->max_notifyid = -1;
+   ret = rproc_handle_resource(rproc, table, tablesz,
+   rproc_handle_notifyid_rsc);
+
/* look for virtio devices and register them */
ret = rproc_handle_resource(rproc, table, tablesz,
rproc_handle_vdev_rsc);
diff --git a/drivers/remoteproc/ste_modem_rproc.c 
b/drivers/remoteproc/ste_modem_rproc.c
index 09f1b4e..bcb2b2d 100644
--- a/drivers/remoteproc/ste_modem_rproc.c
+++ b/drivers/remoteproc/ste_modem_rproc.c
@@ -213,7 +213,7 @@ static int sproc_start(struct rproc *rproc)
}
 
/* Subscribe to notifications */
-   for (i = 0; i < rproc->max_notifyid; i++) {
+   for (i = 0; i <= rproc->max_notifyid; i++) {
err = sproc->mdev->ops.kick_subscribe(sproc->mdev, i);
if (err) {
sproc_err(sproc,
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCHv2 06/10] remoteproc: Code cleanup of resource parsing

2013-02-21 Thread sjur . brandeland
From: Sjur Brændeland 

Combine the almost identical functions rproc_handle_virtio_rsc
and rproc_handle_boot_rsc.

Signed-off-by: Sjur Brændeland 
---
 drivers/remoteproc/remoteproc_core.c |   51 --
 1 files changed, 12 insertions(+), 39 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_core.c 
b/drivers/remoteproc/remoteproc_core.c
index 752b507..6e515d7 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -679,16 +679,22 @@ free_carv:
  * A lookup table for resource handlers. The indices are defined in
  * enum fw_resource_type.
  */
-static rproc_handle_resource_t rproc_handle_rsc[] = {
+static rproc_handle_resource_t rproc_handle_rsc[RSC_LAST] = {
[RSC_CARVEOUT] = (rproc_handle_resource_t)rproc_handle_carveout,
[RSC_DEVMEM] = (rproc_handle_resource_t)rproc_handle_devmem,
[RSC_TRACE] = (rproc_handle_resource_t)rproc_handle_trace,
[RSC_VDEV] = NULL, /* VDEVs were handled upon registrarion */
 };
 
+static rproc_handle_resource_t rproc_handle_vdev_rsc[RSC_LAST] = {
+   [RSC_VDEV] = (rproc_handle_resource_t)rproc_handle_vdev,
+};
+
 /* handle firmware resource entries before booting the remote processor */
 static int
-rproc_handle_boot_rsc(struct rproc *rproc, struct resource_table *table, int 
len)
+rproc_handle_resource(struct rproc *rproc, struct resource_table *table,
+   int len,
+   rproc_handle_resource_t handlers[RSC_LAST])
 {
struct device *dev = &rproc->dev;
rproc_handle_resource_t handler;
@@ -713,7 +719,7 @@ rproc_handle_boot_rsc(struct rproc *rproc, struct 
resource_table *table, int len
continue;
}
 
-   handler = rproc_handle_rsc[hdr->type];
+   handler = handlers[hdr->type];
if (!handler)
continue;
 
@@ -725,40 +731,6 @@ rproc_handle_boot_rsc(struct rproc *rproc, struct 
resource_table *table, int len
return ret;
 }
 
-/* handle firmware resource entries while registering the remote processor */
-static int
-rproc_handle_virtio_rsc(struct rproc *rproc, struct resource_table *table, int 
len)
-{
-   struct device *dev = &rproc->dev;
-   int ret = 0, i;
-
-   for (i = 0; i < table->num; i++) {
-   int offset = table->offset[i];
-   struct fw_rsc_hdr *hdr = (void *)table + offset;
-   int avail = len - offset - sizeof(*hdr);
-   struct fw_rsc_vdev *vrsc;
-
-   /* make sure table isn't truncated */
-   if (avail < 0) {
-   dev_err(dev, "rsc table is truncated\n");
-   return -EINVAL;
-   }
-
-   dev_dbg(dev, "%s: rsc type %d\n", __func__, hdr->type);
-
-   if (hdr->type != RSC_VDEV)
-   continue;
-
-   vrsc = (struct fw_rsc_vdev *)hdr->data;
-
-   ret = rproc_handle_vdev(rproc, vrsc, avail);
-   if (ret)
-   break;
-   }
-
-   return ret;
-}
-
 /**
  * rproc_resource_cleanup() - clean up and free all acquired resources
  * @rproc: rproc handle
@@ -838,7 +810,7 @@ static int rproc_fw_boot(struct rproc *rproc, const struct 
firmware *fw)
}
 
/* handle fw resources which are required to boot rproc */
-   ret = rproc_handle_boot_rsc(rproc, table, tablesz);
+   ret = rproc_handle_resource(rproc, table, tablesz, rproc_handle_rsc);
if (ret) {
dev_err(dev, "Failed to process resources: %d\n", ret);
goto clean_up;
@@ -893,7 +865,8 @@ static void rproc_fw_config_virtio(const struct firmware 
*fw, void *context)
goto out;
 
/* look for virtio devices and register them */
-   ret = rproc_handle_virtio_rsc(rproc, table, tablesz);
+   ret = rproc_handle_resource(rproc, table, tablesz,
+   rproc_handle_vdev_rsc);
if (ret)
goto out;
 
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCHv2 04/10] remoteproc: Parse ELF file to find resource table address

2013-02-21 Thread sjur . brandeland
From: Sjur Brændeland 

Add function find_rsc_table_va to firmware ops. This function
returns the location of the resource table in shared memory
after loading.

Signed-off-by: Sjur Brændeland 
---
 drivers/remoteproc/remoteproc_elf_loader.c |   17 -
 drivers/remoteproc/remoteproc_internal.h   |   13 +
 2 files changed, 29 insertions(+), 1 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_elf_loader.c 
b/drivers/remoteproc/remoteproc_elf_loader.c
index ed12c16..3d6ec76 100644
--- a/drivers/remoteproc/remoteproc_elf_loader.c
+++ b/drivers/remoteproc/remoteproc_elf_loader.c
@@ -304,9 +304,24 @@ rproc_elf_find_rsc_table(struct rproc *rproc, const struct 
firmware *fw,
return table;
 }
 
+static struct resource_table *rproc_elf_get_rsctab_va(struct rproc *rproc,
+const struct firmware *fw)
+{
+   struct elf32_shdr *shdr;
+
+   shdr = find_rsc_shdr(&rproc->dev, (struct elf32_hdr *)fw->data,
+   fw->size);
+   if (!shdr)
+   return NULL;
+
+   /* Find resource table in loaded segments */
+   return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size);
+}
+
 const struct rproc_fw_ops rproc_elf_fw_ops = {
.load = rproc_elf_load_segments,
.find_rsc_table = rproc_elf_find_rsc_table,
.sanity_check = rproc_elf_sanity_check,
-   .get_boot_addr = rproc_elf_get_boot_addr
+   .get_boot_addr = rproc_elf_get_boot_addr,
+   .get_rsctab_va = rproc_elf_get_rsctab_addr
 };
diff --git a/drivers/remoteproc/remoteproc_internal.h 
b/drivers/remoteproc/remoteproc_internal.h
index 7bb6648..b7372b1 100644
--- a/drivers/remoteproc/remoteproc_internal.h
+++ b/drivers/remoteproc/remoteproc_internal.h
@@ -32,6 +32,7 @@ struct rproc;
  * expects to find it
  * @sanity_check:  sanity check the fw image
  * @get_boot_addr: get boot address to entry point specified in firmware
+ * @get_rsctab_va: get resouce table address as specified in firmware
  */
 struct rproc_fw_ops {
struct resource_table *(*find_rsc_table) (struct rproc *rproc,
@@ -40,6 +41,8 @@ struct rproc_fw_ops {
int (*load)(struct rproc *rproc, const struct firmware *fw);
int (*sanity_check)(struct rproc *rproc, const struct firmware *fw);
u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
+   struct resource_table *(*get_rsctab_va)(struct rproc *rproc,
+   const struct firmware *fw);
 };
 
 /* from remoteproc_core.c */
@@ -102,6 +105,16 @@ struct resource_table *rproc_find_rsc_table(struct rproc 
*rproc,
return NULL;
 }
 
+static inline
+struct resource_table *rproc_get_rsctab_addr(struct rproc *rproc,
+   const struct firmware *fw)
+{
+   if (rproc->fw_ops->get_rsctab_addr)
+   return rproc->fw_ops->get_rsctab_addr(rproc, fw);
+
+   return NULL;
+}
+
 extern const struct rproc_fw_ops rproc_elf_fw_ops;
 
 #endif /* REMOTEPROC_INTERNAL_H */
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCHv2 03/10] remoteproc: Refactor function rproc_elf_find_rsc_table

2013-02-21 Thread sjur . brandeland
From: Sjur Brændeland 

Refactor rproc_elf_find_rsc_table and split out the scanning
for the section header named resource table. This is done to
prepare for loading firmware once.

Signed-off-by: Sjur Brændeland 
---
 drivers/remoteproc/remoteproc_elf_loader.c |   75 +---
 1 files changed, 46 insertions(+), 29 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_elf_loader.c 
b/drivers/remoteproc/remoteproc_elf_loader.c
index 0d36f94..ed12c16 100644
--- a/drivers/remoteproc/remoteproc_elf_loader.c
+++ b/drivers/remoteproc/remoteproc_elf_loader.c
@@ -208,41 +208,22 @@ rproc_elf_load_segments(struct rproc *rproc, const struct 
firmware *fw)
return ret;
 }
 
-/**
- * rproc_elf_find_rsc_table() - find the resource table
- * @rproc: the rproc handle
- * @fw: the ELF firmware image
- * @tablesz: place holder for providing back the table size
- *
- * This function finds the resource table inside the remote processor's
- * firmware. It is used both upon the registration of @rproc (in order
- * to look for and register the supported virito devices), and when the
- * @rproc is booted.
- *
- * Returns the pointer to the resource table if it is found, and write its
- * size into @tablesz. If a valid table isn't found, NULL is returned
- * (and @tablesz isn't set).
- */
-static struct resource_table *
-rproc_elf_find_rsc_table(struct rproc *rproc, const struct firmware *fw,
-   int *tablesz)
+static struct elf32_shdr *
+find_rsc_shdr(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
 {
-   struct elf32_hdr *ehdr;
struct elf32_shdr *shdr;
+   int i;
const char *name_table;
-   struct device *dev = &rproc->dev;
struct resource_table *table = NULL;
-   int i;
-   const u8 *elf_data = fw->data;
+   const u8 *elf_data = (void *)ehdr;
 
-   ehdr = (struct elf32_hdr *)elf_data;
+   /* look for the resource table and handle it */
shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
name_table = elf_data + shdr[ehdr->e_shstrndx].sh_offset;
 
-   /* look for the resource table and handle it */
for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
-   int size = shdr->sh_size;
-   int offset = shdr->sh_offset;
+   u32 size = shdr->sh_size;
+   u32 offset = shdr->sh_offset;
 
if (strcmp(name_table + shdr->sh_name, ".resource_table"))
continue;
@@ -250,7 +231,7 @@ rproc_elf_find_rsc_table(struct rproc *rproc, const struct 
firmware *fw,
table = (struct resource_table *)(elf_data + offset);
 
/* make sure we have the entire table */
-   if (offset + size > fw->size) {
+   if (offset + size > fw_size || offset + size < size) {
dev_err(dev, "resource table truncated\n");
return NULL;
}
@@ -280,10 +261,46 @@ rproc_elf_find_rsc_table(struct rproc *rproc, const 
struct firmware *fw,
return NULL;
}
 
-   *tablesz = shdr->sh_size;
-   break;
+   return shdr;
}
 
+   return NULL;
+}
+
+/**
+ * rproc_elf_find_rsc_table() - find the resource table
+ * @rproc: the rproc handle
+ * @fw: the ELF firmware image
+ * @tablesz: place holder for providing back the table size
+ *
+ * This function finds the resource table inside the remote processor's
+ * firmware. It is used both upon the registration of @rproc (in order
+ * to look for and register the supported virito devices), and when the
+ * @rproc is booted.
+ *
+ * Returns the pointer to the resource table if it is found, and write its
+ * size into @tablesz. If a valid table isn't found, NULL is returned
+ * (and @tablesz isn't set).
+ */
+static struct resource_table *
+rproc_elf_find_rsc_table(struct rproc *rproc, const struct firmware *fw,
+   int *tablesz)
+{
+   struct elf32_hdr *ehdr;
+   struct elf32_shdr *shdr;
+   struct device *dev = &rproc->dev;
+   struct resource_table *table = NULL;
+   const u8 *elf_data = fw->data;
+
+   ehdr = (struct elf32_hdr *)elf_data;
+
+   shdr = find_rsc_shdr(dev, ehdr, fw->size);
+   if (!shdr)
+   return NULL;
+
+   table = (struct resource_table *)(elf_data + shdr->sh_offset);
+   *tablesz = shdr->sh_size;
+
return table;
 }
 
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCHv2 02/10] remoteproc: Bugfix remove entry from list before freeing it

2013-02-21 Thread sjur . brandeland
From: Sjur Brændeland 

Remove the vdev entry from the list before freeing it,
otherwise the rproc->vdevs list get corrupted.

Signed-off-by: Sjur Brændeland 
---
 drivers/remoteproc/remoteproc_core.c |4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_core.c 
b/drivers/remoteproc/remoteproc_core.c
index dd3bfaf..752b507 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -370,10 +370,12 @@ static int rproc_handle_vdev(struct rproc *rproc, struct 
fw_rsc_vdev *rsc,
/* it is now safe to add the virtio device */
ret = rproc_add_virtio_dev(rvdev, rsc->id);
if (ret)
-   goto free_rvdev;
+   goto remove_rvdev;
 
return 0;
 
+remove_rvdev:
+   list_del(&rvdev->node);
 free_rvdev:
kfree(rvdev);
return ret;
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCHv2 00/10] remoteproc: Support bi-directional vdev config space

2013-02-21 Thread sjur . brandeland
From: Sjur Brændeland 

This patch-set adds support for shared resource table between
Linux kernel and remote devices. 
- dynamically-allocated address of the vrings can be communicated
- vdev statuses can be communicated
- virtio config space becomes bi-directional
- virtio feature negotiation is two-way 

Changes since v1:
- Address all of Ido's review comments on the previous patch-set.

Thanks,
Sjur

Dmitry Tarnyagin (1):
  remoteproc: Bugfix: Deallocate firmware image on shutdown

Sjur Brændeland (9):
  remoteproc: Bugfix remove entry from list before freeing it
  remoteproc: Refactor function rproc_elf_find_rsc_table
  remoteproc: Parse ELF file to find resource table address
  remoteproc: Parse STE-firmware and find resource table address
  remoteproc: Code cleanup of resource parsing
  remoteproc: Calculate max_notifyid by counting vrings
  remoteproc: Always perserve resource table data
  remoteproc: Support virtio config space.
  remoteproc: Set vring addresses in resource table

 drivers/remoteproc/Kconfig |1 +
 drivers/remoteproc/remoteproc_core.c   |  185 +--
 drivers/remoteproc/remoteproc_elf_loader.c |   92 +-
 drivers/remoteproc/remoteproc_internal.h   |   13 ++
 drivers/remoteproc/remoteproc_virtio.c |   61 +++---
 drivers/remoteproc/ste_modem_rproc.c   |   52 ++---
 include/linux/remoteproc.h |   13 ++-
 7 files changed, 283 insertions(+), 134 deletions(-)

-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCHv2 vringh 3/3] caif_virtio: Introduce caif over virtio

2013-02-12 Thread sjur . brandeland
From: Vikram ARV 

Add the the Virtio shared memory driver for STE Modems.
caif_virtio is implemented utilizing the virtio framework
for data transport and is managed with the remoteproc frameworks.

The Virtio queue is used for transmitting data to the modem, and
the new vringh implementation is receiving data over the vring.

Signed-off-by: Vikram ARV 
Signed-off-by: Sjur Brændeland 

cc: David S. Miller 
cc: Ohad Ben-Cohen 
cc: Rusty Russell 
cc: Ido Yariv 
cc: Erwan Yvin 
---
As mentioned earlier this patch-set will go via Rusty's git.

Changes since V1: 
- update to new vringh API, 
- use module_virtio_driver macro
- call tasklet_kill from cfv_remove().

Thanks,
Sjur

 drivers/net/caif/Kconfig|8 +
 drivers/net/caif/Makefile   |3 +
 drivers/net/caif/caif_virtio.c  |  547 +++
 include/linux/virtio_caif.h |   24 ++
 include/uapi/linux/virtio_ids.h |1 +
 5 files changed, 583 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/caif/caif_virtio.c
 create mode 100644 include/linux/virtio_caif.h

diff --git a/drivers/net/caif/Kconfig b/drivers/net/caif/Kconfig
index abf4d7a..a8b67e9 100644
--- a/drivers/net/caif/Kconfig
+++ b/drivers/net/caif/Kconfig
@@ -47,3 +47,11 @@ config CAIF_HSI
The caif low level driver for CAIF over HSI.
Be aware that if you enable this then you also need to
enable a low-level HSI driver.
+
+config CAIF_VIRTIO
+   tristate "CAIF virtio transport driver"
+   depends on CAIF
+   depends on REMOTEPROC
+   default n
+   ---help---
+   The caif driver for CAIF over Virtio.
diff --git a/drivers/net/caif/Makefile b/drivers/net/caif/Makefile
index 91dff86..d9ee26a 100644
--- a/drivers/net/caif/Makefile
+++ b/drivers/net/caif/Makefile
@@ -13,3 +13,6 @@ obj-$(CONFIG_CAIF_SHM) += caif_shm.o
 
 # HSI interface
 obj-$(CONFIG_CAIF_HSI) += caif_hsi.o
+
+# Virtio interface
+obj-$(CONFIG_CAIF_VIRTIO) += caif_virtio.o
diff --git a/drivers/net/caif/caif_virtio.c b/drivers/net/caif/caif_virtio.c
new file mode 100644
index 000..d4f339c
--- /dev/null
+++ b/drivers/net/caif/caif_virtio.c
@@ -0,0 +1,547 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2012
+ * Contact: Sjur Brendeland / sjur.brandel...@stericsson.com
+ * Authors: Vicram Arv / vikram@stericsson.com,
+ * Dmitry Tarnyagin / dmitry.tarnya...@stericsson.com
+ * Sjur Brendeland / sjur.brandel...@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Vicram Arv ");
+MODULE_AUTHOR("Sjur Brendeland vdev->priv;
+   tasklet_schedule(&cfv->tx_release_tasklet);
+}
+
+/* This is invoked whenever the remote processor completed processing
+ * a TX msg we just sent it, and the buffer is put back to the used ring.
+ */
+static void cfv_release_used_buf(struct virtqueue *vq_tx)
+{
+   struct cfv_info *cfv = vq_tx->vdev->priv;
+   unsigned long flags;
+
+   BUG_ON(vq_tx != cfv->vq_tx);
+   WARN_ON_ONCE(irqs_disabled());
+
+   for (;;) {
+   unsigned int len;
+   struct token_info *buf_info;
+
+   /* Get used buffer from used ring to recycle used descriptors */
+   spin_lock_irqsave(&cfv->tx_lock, flags);
+   buf_info = virtqueue_get_buf(vq_tx, &len);
+
+   if (!buf_info)
+   goto out;
+
+   BUG_ON(!cfv->queued_tx);
+   if (--cfv->queued_tx <= cfv->watermark_tx) {
+   cfv->watermark_tx = 0;
+   netif_tx_wake_all_queues(cfv->ndev);
+   }
+   spin_unlock_irqrestore(&cfv->tx_lock, flags);
+
+   dma_free_coherent(vq_tx->vdev->dev.parent->parent,
+ buf_info->size, buf_info->vaddr,
+ buf_info->dma_handle);
+   kfree(buf_info);
+   }
+   return;
+out:
+   spin_unlock_irqrestore(&cfv->tx_lock, flags);
+}
+
+static struct sk_buff *cfv_alloc_and_copy_skb(int *err,
+ struct cfv_info *cfv,
+ u8 *frm, u32 frm_len)
+{
+   struct sk_buff *skb;
+   u32 cfpkt_len, pad_len;
+
+   *err = 0;
+   /* Verify that packet size with down-link header and mtu size */
+   if (frm_len > cfv->mru || frm_len <= cfv->rx_hr + cfv->rx_tr) {
+   netdev_err(cfv->ndev,
+  "Invalid frmlen:%u  mtu:%u hr:%d tr:%d\n",
+  frm_len, cfv->mru,  cfv->rx_hr,
+  cfv->rx_tr);
+   *err = -EPROTO;
+   return NULL;
+   }
+
+   cfpkt_len = frm_len - (cfv->rx_hr + cfv->rx_tr);
+
+   pad_len = (unsigned long)(frm + cfv->rx_hr) & (IP_HDR_ALIGN - 1);

[PATCHv2 vringh 2/3] virtio: Add module driver macro for virtio drivers.

2013-02-12 Thread sjur . brandeland
From: Sjur Brændeland 

Add helper macro for drivers that don't do anything
special in module init/exit.

Signed-off-by: Sjur Brændeland 
---
 include/linux/virtio.h |9 +
 1 files changed, 9 insertions(+), 0 deletions(-)

diff --git a/include/linux/virtio.h b/include/linux/virtio.h
index cf8adb1..00ccc40 100644
--- a/include/linux/virtio.h
+++ b/include/linux/virtio.h
@@ -126,4 +126,13 @@ static inline struct virtio_driver *drv_to_virtio(struct 
device_driver *drv)
 
 int register_virtio_driver(struct virtio_driver *drv);
 void unregister_virtio_driver(struct virtio_driver *drv);
+
+/* module_virtio_driver() - Helper macro for drivers that don't do
+ * anything special in module init/exit.  This eliminates a lot of
+ * boilerplate.  Each module may only use this macro once, and
+ * calling it replaces module_init() and module_exit()
+ */
+#define module_virtio_driver(__virtio_driver) \
+   module_driver(__virtio_driver, register_virtio_driver, \
+   unregister_virtio_driver)
 #endif /* _LINUX_VIRTIO_H */
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCHv2 vringh 1/3] remoteproc: Add support for vringh (Host vrings)

2013-02-12 Thread sjur . brandeland
From: Sjur Brændeland 

Add functions for creating, deleting and kicking host-side virtio rings.

The host ring is not integrated with virtiqueues and cannot be managed
through virtio-config. Remoteproc must export functions for handling the
host-side virtio rings.

The functions rproc_virtio_get_vringh(), rproc_virtio_del_vringh(),
rproc_virtio_kick_vringh() are added to remoteproc_virtio.c. The
existing functions rproc_vq_interrupt() and rproc_virtio_find_vqs()
are updated to handle the new vhost rings.

Signed-off-by: Sjur Brændeland 
cc: Ohad Ben-Cohen 
cc: Rusty Russell 
cc: Ido Yariv 
cc: Erwan Yvin 
---
 drivers/remoteproc/Kconfig |3 +
 drivers/remoteproc/remoteproc_virtio.c |  127 ++--
 include/linux/remoteproc.h |   14 
 3 files changed, 137 insertions(+), 7 deletions(-)

diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index 96ce101..c7d1d36 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -7,6 +7,9 @@ config REMOTEPROC
depends on HAS_DMA
select FW_CONFIG
select VIRTIO
+   select VHOST_RING
+
+source drivers/vhost/Kconfig
 
 config OMAP_REMOTEPROC
tristate "OMAP remoteproc support"
diff --git a/drivers/remoteproc/remoteproc_virtio.c 
b/drivers/remoteproc/remoteproc_virtio.c
index 9e198e5..fa7bf7b 100644
--- a/drivers/remoteproc/remoteproc_virtio.c
+++ b/drivers/remoteproc/remoteproc_virtio.c
@@ -23,6 +23,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -60,10 +61,15 @@ irqreturn_t rproc_vq_interrupt(struct rproc *rproc, int 
notifyid)
dev_dbg(&rproc->dev, "vq index %d is interrupted\n", notifyid);
 
rvring = idr_find(&rproc->notifyids, notifyid);
-   if (!rvring || !rvring->vq)
+   if (!rvring)
return IRQ_NONE;
 
-   return vring_interrupt(0, rvring->vq);
+   if (rvring->vringh && rvring->vringh_cb)
+   return rvring->vringh_cb(&rvring->rvdev->vdev, rvring->vringh);
+   else if (rvring->vq)
+   return vring_interrupt(0, rvring->vq);
+   else
+   return IRQ_NONE;
 }
 EXPORT_SYMBOL(rproc_vq_interrupt);
 
@@ -149,14 +155,21 @@ static int rproc_virtio_find_vqs(struct virtio_device 
*vdev, unsigned nvqs,
   const char *names[])
 {
struct rproc *rproc = vdev_to_rproc(vdev);
-   int i, ret;
+   struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
+   int rng, id, ret, nrings = ARRAY_SIZE(rvdev->vring);
+
+   for (id = 0, rng = 0; rng < nrings; ++rng) {
+   struct rproc_vring *rvring = &rvdev->vring[rng];
+   /* Skip the host side rings */
+   if (rvring->vringh)
+   continue;
 
-   for (i = 0; i < nvqs; ++i) {
-   vqs[i] = rp_find_vq(vdev, i, callbacks[i], names[i]);
-   if (IS_ERR(vqs[i])) {
-   ret = PTR_ERR(vqs[i]);
+   vqs[id] = rp_find_vq(vdev, rng, callbacks[id], names[id]);
+   if (IS_ERR(vqs[id])) {
+   ret = PTR_ERR(vqs[id]);
goto error;
}
+   ++id;
}
 
/* now that the vqs are all set, boot the remote processor */
@@ -173,6 +186,106 @@ error:
return ret;
 }
 
+/**
+ * rproc_virtio_new_vringh() - create a reversed virtio ring.
+ * @vdev: the virtio device
+ * @index: the virtio ring index
+ * @cb: callback for the reversed virtio ring
+ *
+ * This function should be called by the virtio-driver
+ * before calling find_vqs(). It returns a struct vringh for
+ * accessing the virtio ring.
+ *
+ * Return: struct vhost, or NULL upon error.
+ */
+struct vringh *
+rproc_virtio_new_vringh(struct virtio_device *vdev, unsigned index,
+   irqreturn_t (*cb)(struct virtio_device *vdev,
+ struct vringh *vring))
+{
+   struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
+   struct rproc_vring *rvring;
+   struct vringh *vrh;
+   int err;
+
+   if (index > ARRAY_SIZE(rvdev->vring)) {
+   dev_err(&rvdev->vdev.dev, "bad vring index: %d\n", index);
+   return NULL;
+   }
+
+   vrh = kzalloc(sizeof(*vrh), GFP_KERNEL);
+   if (!vrh)
+   return NULL;
+
+   err = rproc_alloc_vring(rvdev, index);
+   if (err)
+   goto free_vring;
+
+
+   rvring = &rvdev->vring[index];
+   /* zero vring */
+   memset(rvring->va, 0, vring_size(rvring->len, rvring->align));
+   vring_init(&vrh->vring, rvring->len, rvring->va, rvring->align);
+
+   rvring->vringh_cb = cb;
+   rvring->vringh = vrh;
+
+   err = vringh_init_kern(vrh,
+  rvdev->dfeatures,
+  rvring->len,
+  false,
+  vrh->vring.desc,
+  vrh->vring.

[PATCHv2 vringh 0/3] Introduce CAIF Virtio driver

2013-02-12 Thread sjur . brandeland
From: Sjur Brændeland 

This driver depends on Rusty's new host virtio ring implementation,
so this patch-set is based on the vringh branch in Rusty's git.

Changes since V1:
- Use the new iov helper functions, and simplify iov handling.
  However this triggers compile warnings, as it takes struct iov
  while kernel api uses struct kiov
- Introduced the module_virtio_driver macro
- Pass NULL as wiov to vringh_getdesc_kern() 

Regards,
Sjur

Sjur Brændeland (2):
  remoteproc: Add support for vringh (Host vrings)
  virtio: Add module driver macro for virtio drivers.

Vikram ARV (1):
  caif_virtio: Introduce caif over virtio

 drivers/net/caif/Kconfig   |8 +
 drivers/net/caif/Makefile  |3 +
 drivers/net/caif/caif_virtio.c |  547 
 drivers/remoteproc/Kconfig |3 +
 drivers/remoteproc/remoteproc_virtio.c |  127 +++-
 include/linux/remoteproc.h |   14 +
 include/linux/virtio.h |9 +
 include/linux/virtio_caif.h|   24 ++
 include/uapi/linux/virtio_ids.h|1 +
 9 files changed, 729 insertions(+), 7 deletions(-)
 create mode 100644 drivers/net/caif/caif_virtio.c
 create mode 100644 include/linux/virtio_caif.h

-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 4/9] remoteproc: Parse STE-firmware and find resource table address

2013-02-10 Thread sjur . brandeland
From: Sjur Brændeland 

Parse the STE firmware and scan the TOC-table to find the address
of the resource table.

Signed-off-by: Sjur Brændeland 
---
 drivers/remoteproc/ste_modem_rproc.c |   43 +++---
 1 files changed, 29 insertions(+), 14 deletions(-)

diff --git a/drivers/remoteproc/ste_modem_rproc.c 
b/drivers/remoteproc/ste_modem_rproc.c
index fb95c42..932e97d 100644
--- a/drivers/remoteproc/ste_modem_rproc.c
+++ b/drivers/remoteproc/ste_modem_rproc.c
@@ -64,26 +64,18 @@ static int sproc_load_segments(struct rproc *rproc, const 
struct firmware *fw)
 }
 
 /* Find the entry for resource table in the Table of Content */
-static struct ste_toc_entry *sproc_find_rsc_entry(const struct firmware *fw)
+static const struct ste_toc_entry *sproc_find_rsc_entry(const void *data)
 {
int i;
-   struct ste_toc *toc;
-
-   if (!fw)
-   return NULL;
-
-   toc = (void *)fw->data;
+   const struct ste_toc *toc;
+   toc = data;
 
/* Search the table for the resource table */
for (i = 0; i < SPROC_MAX_TOC_ENTRIES &&
toc->table[i].start != 0x; i++) {
-
if (!strncmp(toc->table[i].name, SPROC_RESOURCE_NAME,
-sizeof(toc->table[i].name))) {
-   if (toc->table[i].start > fw->size)
-   return NULL;
+sizeof(toc->table[i].name)))
return &toc->table[i];
-   }
}
 
return NULL;
@@ -96,9 +88,12 @@ sproc_find_rsc_table(struct rproc *rproc, const struct 
firmware *fw,
 {
struct sproc *sproc = rproc->priv;
struct resource_table *table;
-   struct ste_toc_entry *entry;
+   const struct ste_toc_entry *entry;
 
-   entry = sproc_find_rsc_entry(fw);
+   if (!fw)
+   return NULL;
+
+   entry = sproc_find_rsc_entry(fw->data);
if (!entry) {
sproc_err(sproc, "resource table not found in fw\n");
return NULL;
@@ -149,10 +144,30 @@ sproc_find_rsc_table(struct rproc *rproc, const struct 
firmware *fw,
return table;
 }
 
+/* Find the resource table inside the remote processor's firmware. */
+static struct resource_table *
+sproc_get_rsctab_addr(struct rproc *rproc, const struct firmware *fw)
+{
+   struct sproc *sproc = rproc->priv;
+   const struct ste_toc_entry *entry;
+
+   if (!fw || !sproc->fw_addr)
+   return NULL;
+
+   entry = sproc_find_rsc_entry(sproc->fw_addr);
+   if (!entry) {
+   sproc_err(sproc, "resource table not found in fw\n");
+   return NULL;
+   }
+
+   return sproc->fw_addr + entry->start;
+}
+
 /* STE modem firmware handler operations */
 const struct rproc_fw_ops sproc_fw_ops = {
.load = sproc_load_segments,
.find_rsc_table = sproc_find_rsc_table,
+   .get_rsctab_addr = sproc_get_rsctab_addr,
 };
 
 /* Kick the modem with specified notification id */
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 2/9] remoteproc: Refactor function rproc_elf_find_rsc_table

2013-02-10 Thread sjur . brandeland
From: Sjur Brændeland 

Refactor rproc_elf_find_rsc_table and split out the scanning
for the section header named resource table. This is done to
prepare for loading firmware once.

Signed-off-by: Sjur Brændeland 
---
 drivers/remoteproc/remoteproc_elf_loader.c |   79 ++--
 1 files changed, 52 insertions(+), 27 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_elf_loader.c 
b/drivers/remoteproc/remoteproc_elf_loader.c
index 0d36f94..a958950 100644
--- a/drivers/remoteproc/remoteproc_elf_loader.c
+++ b/drivers/remoteproc/remoteproc_elf_loader.c
@@ -208,38 +208,19 @@ rproc_elf_load_segments(struct rproc *rproc, const struct 
firmware *fw)
return ret;
 }
 
-/**
- * rproc_elf_find_rsc_table() - find the resource table
- * @rproc: the rproc handle
- * @fw: the ELF firmware image
- * @tablesz: place holder for providing back the table size
- *
- * This function finds the resource table inside the remote processor's
- * firmware. It is used both upon the registration of @rproc (in order
- * to look for and register the supported virito devices), and when the
- * @rproc is booted.
- *
- * Returns the pointer to the resource table if it is found, and write its
- * size into @tablesz. If a valid table isn't found, NULL is returned
- * (and @tablesz isn't set).
- */
-static struct resource_table *
-rproc_elf_find_rsc_table(struct rproc *rproc, const struct firmware *fw,
-   int *tablesz)
+static struct elf32_shdr *
+find_rsc_shdr(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
 {
-   struct elf32_hdr *ehdr;
struct elf32_shdr *shdr;
+   int i;
const char *name_table;
-   struct device *dev = &rproc->dev;
struct resource_table *table = NULL;
-   int i;
-   const u8 *elf_data = fw->data;
+   const u8 *elf_data = (void *)ehdr;
 
-   ehdr = (struct elf32_hdr *)elf_data;
+   /* look for the resource table and handle it */
shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
name_table = elf_data + shdr[ehdr->e_shstrndx].sh_offset;
 
-   /* look for the resource table and handle it */
for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
int size = shdr->sh_size;
int offset = shdr->sh_offset;
@@ -250,7 +231,7 @@ rproc_elf_find_rsc_table(struct rproc *rproc, const struct 
firmware *fw,
table = (struct resource_table *)(elf_data + offset);
 
/* make sure we have the entire table */
-   if (offset + size > fw->size) {
+   if (offset + size > fw_size) {
dev_err(dev, "resource table truncated\n");
return NULL;
}
@@ -280,10 +261,54 @@ rproc_elf_find_rsc_table(struct rproc *rproc, const 
struct firmware *fw,
return NULL;
}
 
-   *tablesz = shdr->sh_size;
-   break;
+   return shdr;
}
 
+   return NULL;
+}
+
+/**
+ * rproc_elf_find_rsc_table() - find the resource table
+ * @rproc: the rproc handle
+ * @fw: the ELF firmware image
+ * @tablesz: place holder for providing back the table size
+ *
+ * This function finds the resource table inside the remote processor's
+ * firmware. It is used both upon the registration of @rproc (in order
+ * to look for and register the supported virito devices), and when the
+ * @rproc is booted.
+ *
+ * Returns the pointer to the resource table if it is found, and write its
+ * size into @tablesz. If a valid table isn't found, NULL is returned
+ * (and @tablesz isn't set).
+ */
+static struct resource_table *
+rproc_elf_find_rsc_table(struct rproc *rproc, const struct firmware *fw,
+   int *tablesz)
+{
+   struct elf32_hdr *ehdr;
+   struct elf32_shdr *shdr;
+
+   struct device *dev = &rproc->dev;
+   struct resource_table *table = NULL;
+
+   const u8 *elf_data = fw->data;
+
+   ehdr = (struct elf32_hdr *)elf_data;
+
+   shdr = find_rsc_shdr(dev, ehdr, fw->size);
+   if (!shdr)
+   return NULL;
+
+   /* make sure we have the entire table */
+   if (shdr->sh_offset + shdr->sh_size > fw->size) {
+   dev_err(dev, "resource table truncated\n");
+   return NULL;
+   }
+
+   table = (struct resource_table *)(elf_data + shdr->sh_offset);
+   *tablesz = shdr->sh_size;
+
return table;
 }
 
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 1/9] remoteproc: Bugfix: Deallocate firmware image on shutdown

2013-02-10 Thread sjur . brandeland
From: Dmitry Tarnyagin 

Fixes coherent memory leakage, caused by non-deallocated
firmware image chunk.

Signed-off-by: Dmitry Tarnyagin 
---
 drivers/remoteproc/ste_modem_rproc.c |7 ++-
 1 files changed, 6 insertions(+), 1 deletions(-)

diff --git a/drivers/remoteproc/ste_modem_rproc.c 
b/drivers/remoteproc/ste_modem_rproc.c
index a7743c0..fb95c42 100644
--- a/drivers/remoteproc/ste_modem_rproc.c
+++ b/drivers/remoteproc/ste_modem_rproc.c
@@ -240,6 +240,8 @@ static int sproc_drv_remove(struct platform_device *pdev)
 
/* Unregister as remoteproc device */
rproc_del(sproc->rproc);
+   dma_free_coherent(sproc->rproc->dev.parent, SPROC_FW_SIZE,
+ sproc->fw_addr, sproc->fw_dma_addr);
rproc_put(sproc->rproc);
 
mdev->drv_data = NULL;
@@ -297,10 +299,13 @@ static int sproc_probe(struct platform_device *pdev)
/* Register as a remoteproc device */
err = rproc_add(rproc);
if (err)
-   goto free_rproc;
+   goto free_mem;
 
return 0;
 
+free_mem:
+   dma_free_coherent(rproc->dev.parent, SPROC_FW_SIZE,
+ sproc->fw_addr, sproc->fw_dma_addr);
 free_rproc:
/* Reset device data upon error */
mdev->drv_data = NULL;
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 8/9] remoteproc: Calculate max_notifyid by counting vrings

2013-02-10 Thread sjur . brandeland
From: Sjur Brændeland 

Simplify handling of max_notifyid by simply counting the
number of vrings.

Signed-off-by: Sjur Brændeland 
---
 drivers/remoteproc/remoteproc_core.c |   34 +++---
 1 files changed, 19 insertions(+), 15 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_core.c 
b/drivers/remoteproc/remoteproc_core.c
index ec9f81e..14f40eb 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -226,9 +226,6 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i)
return ret;
}
 
-   /* Store largest notifyid */
-   rproc->max_notifyid = max(rproc->max_notifyid, notifyid);
-
dev_dbg(dev, "vring%d: va %p dma %llx size %x idr %d\n", i, va,
(unsigned long long)dma, size, notifyid);
 
@@ -278,25 +275,13 @@ rproc_parse_vring(struct rproc_vdev *rvdev, struct 
fw_rsc_vdev *rsc, int i)
return 0;
 }
 
-static int rproc_max_notifyid(int id, void *p, void *data)
-{
-   int *maxid = data;
-   *maxid = max(*maxid, id);
-   return 0;
-}
-
 void rproc_free_vring(struct rproc_vring *rvring)
 {
int size = PAGE_ALIGN(vring_size(rvring->len, rvring->align));
struct rproc *rproc = rvring->rvdev->rproc;
-   int maxid = 0;
 
dma_free_coherent(rproc->dev.parent, size, rvring->va, rvring->dma);
idr_remove(&rproc->notifyids, rvring->notifyid);
-
-   /* Find the largest remaining notifyid */
-   idr_for_each(&rproc->notifyids, rproc_max_notifyid, &maxid);
-   rproc->max_notifyid = maxid;
 }
 
 /**
@@ -679,6 +664,15 @@ free_carv:
return ret;
 }
 
+static int rproc_handle_notifyid(struct rproc *rproc, struct fw_rsc_vdev *rsc,
+   int avail)
+{
+   /* Summerize the number of notification IDs */
+   rproc->max_notifyid += rsc->num_of_vrings;
+
+   return 0;
+}
+
 /*
  * A lookup table for resource handlers. The indices are defined in
  * enum fw_resource_type.
@@ -694,6 +688,10 @@ static rproc_handle_resource_t 
rproc_handle_vdev_rsc[RSC_LAST] = {
[RSC_VDEV] = (rproc_handle_resource_t)rproc_handle_vdev,
 };
 
+static rproc_handle_resource_t rproc_handle_notifyid_rsc[RSC_LAST] = {
+   [RSC_VDEV] = (rproc_handle_resource_t)rproc_handle_notifyid,
+};
+
 /* handle firmware resource entries before booting the remote processor */
 static int
 rproc_handle_resource(struct rproc *rproc, struct resource_table *table,
@@ -868,6 +866,12 @@ static void rproc_fw_config_virtio(const struct firmware 
*fw, void *context)
if (!table)
goto out;
 
+   rproc->max_notifyid = 0;
+
+   /* count the numbe of notify-ids */
+   ret = rproc_handle_resource(rproc, table, tablesz,
+   rproc_handle_notifyid_rsc);
+
/* look for virtio devices and register them */
ret = rproc_handle_resource(rproc, table, tablesz,
rproc_handle_vdev_rsc);
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 6/9] remoteproc: Support virtio config space.

2013-02-10 Thread sjur . brandeland
From: Sjur Brændeland 

Support virtio configuration space and device status and
feature negotiation with remote device. This virtio device
can now access the resource table in shared memory.

Signed-off-by: Sjur Brændeland 
---
 drivers/remoteproc/remoteproc_core.c   |3 --
 drivers/remoteproc/remoteproc_virtio.c |   38 +--
 include/linux/remoteproc.h |2 -
 3 files changed, 35 insertions(+), 8 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_core.c 
b/drivers/remoteproc/remoteproc_core.c
index c12a385..1bf410d 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -368,9 +368,6 @@ static int rproc_handle_vdev(struct rproc *rproc, struct 
fw_rsc_vdev *rsc,
goto free_rvdev;
}
 
-   /* remember the device features */
-   rvdev->dfeatures = rsc->dfeatures;
-
/* remember the resource entry */
rvdev->rsc = rsc;
 
diff --git a/drivers/remoteproc/remoteproc_virtio.c 
b/drivers/remoteproc/remoteproc_virtio.c
index 9e198e5..d98cdd8 100644
--- a/drivers/remoteproc/remoteproc_virtio.c
+++ b/drivers/remoteproc/remoteproc_virtio.c
@@ -182,16 +182,21 @@ error:
  */
 static u8 rproc_virtio_get_status(struct virtio_device *vdev)
 {
-   return 0;
+   struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
+   return rvdev->rsc->status;
 }
 
 static void rproc_virtio_set_status(struct virtio_device *vdev, u8 status)
 {
+   struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
+   rvdev->rsc->status = status;
dev_dbg(&vdev->dev, "status: %d\n", status);
 }
 
 static void rproc_virtio_reset(struct virtio_device *vdev)
 {
+   struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
+   rvdev->rsc->status = 0;
dev_dbg(&vdev->dev, "reset !\n");
 }
 
@@ -200,7 +205,7 @@ static u32 rproc_virtio_get_features(struct virtio_device 
*vdev)
 {
struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
 
-   return rvdev->dfeatures;
+   return rvdev->rsc->dfeatures;
 }
 
 static void rproc_virtio_finalize_features(struct virtio_device *vdev)
@@ -219,7 +224,31 @@ static void rproc_virtio_finalize_features(struct 
virtio_device *vdev)
 * fixed as part of a small resource table overhaul and then an
 * extension of the virtio resource entries.
 */
-   rvdev->gfeatures = vdev->features[0];
+   rvdev->rsc->gfeatures = vdev->features[0];
+}
+
+void rproc_virtio_get(struct virtio_device *vdev, unsigned offset,
+   void *buf, unsigned len)
+{
+   struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
+   void *cfg = &rvdev->rsc->vring[rvdev->rsc->num_of_vrings];
+   if (offset + len > rvdev->rsc->config_len)
+   dev_err(&vdev->dev,
+   "rproc_virtio_get: access out of bounds\n");
+   else
+   memcpy(buf, cfg + offset, len);
+}
+
+void rproc_virtio_set(struct virtio_device *vdev, unsigned offset,
+ const void *buf, unsigned len)
+{
+   struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
+   void *cfg = &rvdev->rsc->vring[rvdev->rsc->num_of_vrings];
+   if (offset + len > rvdev->rsc->config_len)
+   dev_err(&vdev->dev,
+   "rproc_virtio_set: access out of bounds\n");
+   else
+   memcpy(cfg + offset, buf, len);
 }
 
 static struct virtio_config_ops rproc_virtio_config_ops = {
@@ -230,6 +259,9 @@ static struct virtio_config_ops rproc_virtio_config_ops = {
.reset  = rproc_virtio_reset,
.set_status = rproc_virtio_set_status,
.get_status = rproc_virtio_get_status,
+   .get= rproc_virtio_get,
+   .set= rproc_virtio_set,
+
 };
 
 /*
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index cdacd66..c0c363c 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -471,8 +471,6 @@ struct rproc_vdev {
struct rproc *rproc;
struct virtio_device vdev;
struct rproc_vring vring[RVDEV_NUM_VRINGS];
-   unsigned long dfeatures;
-   unsigned long gfeatures;
struct fw_rsc_vdev *rsc;
 };
 
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 7/9] remoteproc: Code cleanup of resource parsing

2013-02-10 Thread sjur . brandeland
From: Sjur Brændeland 

Combine the almost identical functions rproc_handle_virtio_rsc
and rproc_handle_boot_rsc.

Signed-off-by: Sjur Brændeland 
---
 drivers/remoteproc/remoteproc_core.c |   51 --
 1 files changed, 12 insertions(+), 39 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_core.c 
b/drivers/remoteproc/remoteproc_core.c
index 1bf410d..ec9f81e 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -683,16 +683,22 @@ free_carv:
  * A lookup table for resource handlers. The indices are defined in
  * enum fw_resource_type.
  */
-static rproc_handle_resource_t rproc_handle_rsc[] = {
+static rproc_handle_resource_t rproc_handle_rsc[RSC_LAST] = {
[RSC_CARVEOUT] = (rproc_handle_resource_t)rproc_handle_carveout,
[RSC_DEVMEM] = (rproc_handle_resource_t)rproc_handle_devmem,
[RSC_TRACE] = (rproc_handle_resource_t)rproc_handle_trace,
[RSC_VDEV] = NULL, /* VDEVs were handled upon registrarion */
 };
 
+static rproc_handle_resource_t rproc_handle_vdev_rsc[RSC_LAST] = {
+   [RSC_VDEV] = (rproc_handle_resource_t)rproc_handle_vdev,
+};
+
 /* handle firmware resource entries before booting the remote processor */
 static int
-rproc_handle_boot_rsc(struct rproc *rproc, struct resource_table *table, int 
len)
+rproc_handle_resource(struct rproc *rproc, struct resource_table *table,
+   int len,
+   rproc_handle_resource_t handlers[RSC_LAST])
 {
struct device *dev = &rproc->dev;
rproc_handle_resource_t handler;
@@ -717,7 +723,7 @@ rproc_handle_boot_rsc(struct rproc *rproc, struct 
resource_table *table, int len
continue;
}
 
-   handler = rproc_handle_rsc[hdr->type];
+   handler = handlers[hdr->type];
if (!handler)
continue;
 
@@ -729,40 +735,6 @@ rproc_handle_boot_rsc(struct rproc *rproc, struct 
resource_table *table, int len
return ret;
 }
 
-/* handle firmware resource entries while registering the remote processor */
-static int
-rproc_handle_virtio_rsc(struct rproc *rproc, struct resource_table *table, int 
len)
-{
-   struct device *dev = &rproc->dev;
-   int ret = 0, i;
-
-   for (i = 0; i < table->num; i++) {
-   int offset = table->offset[i];
-   struct fw_rsc_hdr *hdr = (void *)table + offset;
-   int avail = len - offset - sizeof(*hdr);
-   struct fw_rsc_vdev *vrsc;
-
-   /* make sure table isn't truncated */
-   if (avail < 0) {
-   dev_err(dev, "rsc table is truncated\n");
-   return -EINVAL;
-   }
-
-   dev_dbg(dev, "%s: rsc type %d\n", __func__, hdr->type);
-
-   if (hdr->type != RSC_VDEV)
-   continue;
-
-   vrsc = (struct fw_rsc_vdev *)hdr->data;
-
-   ret = rproc_handle_vdev(rproc, vrsc, avail);
-   if (ret)
-   break;
-   }
-
-   return ret;
-}
-
 /**
  * rproc_resource_cleanup() - clean up and free all acquired resources
  * @rproc: rproc handle
@@ -842,7 +814,7 @@ static int rproc_fw_boot(struct rproc *rproc, const struct 
firmware *fw)
}
 
/* handle fw resources which are required to boot rproc */
-   ret = rproc_handle_boot_rsc(rproc, table, tablesz);
+   ret = rproc_handle_resource(rproc, table, tablesz, rproc_handle_rsc);
if (ret) {
dev_err(dev, "Failed to process resources: %d\n", ret);
goto clean_up;
@@ -897,7 +869,8 @@ static void rproc_fw_config_virtio(const struct firmware 
*fw, void *context)
goto out;
 
/* look for virtio devices and register them */
-   ret = rproc_handle_virtio_rsc(rproc, table, tablesz);
+   ret = rproc_handle_resource(rproc, table, tablesz,
+   rproc_handle_vdev_rsc);
if (ret)
goto out;
 
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 5/9] remoteproc: Set vring addresses in resource table

2013-02-10 Thread sjur . brandeland
From: Sjur Brændeland 

Set the vring addresses in the resource table so that
the remote device can read the actual addresses used.

Signed-off-by: Sjur Brændeland 
---
 drivers/remoteproc/remoteproc_core.c |   13 +++--
 include/linux/remoteproc.h   |2 ++
 2 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_core.c 
b/drivers/remoteproc/remoteproc_core.c
index dd3bfaf..c12a385 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -207,7 +207,6 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i)
/*
 * Allocate non-cacheable memory for the vring. In the future
 * this call will also configure the IOMMU for us
-* TODO: let the rproc know the da of this vring
 */
va = dma_alloc_coherent(dev->parent, size, &dma, GFP_KERNEL);
if (!va) {
@@ -218,7 +217,6 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i)
/*
 * Assign an rproc-wide unique index for this vring
 * TODO: assign a notifyid for rvdev updates as well
-* TODO: let the rproc know the notifyid of this vring
 * TODO: support predefined notifyids (via resource table)
 */
ret = idr_get_new(&rproc->notifyids, rvring, ¬ifyid);
@@ -238,6 +236,14 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i)
rvring->dma = dma;
rvring->notifyid = notifyid;
 
+   /*
+* Let the rproc know the notifyid and da of this vring.
+* Not all platforms use dma_alloc_coherent to automatically
+* set up the iommu. In this case the device address (da) will
+* hold the physical address and not the device address.
+*/
+   rvdev->rsc->vring[i].da = dma;
+   rvdev->rsc->vring[i].notifyid = notifyid;
return 0;
 }
 
@@ -365,6 +371,9 @@ static int rproc_handle_vdev(struct rproc *rproc, struct 
fw_rsc_vdev *rsc,
/* remember the device features */
rvdev->dfeatures = rsc->dfeatures;
 
+   /* remember the resource entry */
+   rvdev->rsc = rsc;
+
list_add_tail(&rvdev->node, &rproc->rvdevs);
 
/* it is now safe to add the virtio device */
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index faf3332..cdacd66 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -464,6 +464,7 @@ struct rproc_vring {
  * @vring: the vrings for this vdev
  * @dfeatures: virtio device features
  * @gfeatures: virtio guest features
+ * @rsc: vdev resource entry
  */
 struct rproc_vdev {
struct list_head node;
@@ -472,6 +473,7 @@ struct rproc_vdev {
struct rproc_vring vring[RVDEV_NUM_VRINGS];
unsigned long dfeatures;
unsigned long gfeatures;
+   struct fw_rsc_vdev *rsc;
 };
 
 struct rproc *rproc_alloc(struct device *dev, const char *name,
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 9/9] remoteproc: Always perserve resource table data

2013-02-10 Thread sjur . brandeland
From: Sjur Brændeland 

Copy resource table from first to second firmware loading.
After firmware is loaded to memory, update the vdevs resource
pointer to the resource table kept in device memory.

Signed-off-by: Sjur Brændeland 
---
 drivers/remoteproc/remoteproc_core.c |   61 +++--
 include/linux/remoteproc.h   |3 ++
 2 files changed, 53 insertions(+), 11 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_core.c 
b/drivers/remoteproc/remoteproc_core.c
index 14f40eb..13dc7b4 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -694,17 +694,16 @@ static rproc_handle_resource_t 
rproc_handle_notifyid_rsc[RSC_LAST] = {
 
 /* handle firmware resource entries before booting the remote processor */
 static int
-rproc_handle_resource(struct rproc *rproc, struct resource_table *table,
-   int len,
-   rproc_handle_resource_t handlers[RSC_LAST])
+rproc_handle_resource(struct rproc *rproc, int len,
+ rproc_handle_resource_t handlers[RSC_LAST])
 {
struct device *dev = &rproc->dev;
rproc_handle_resource_t handler;
int ret = 0, i;
 
-   for (i = 0; i < table->num; i++) {
-   int offset = table->offset[i];
-   struct fw_rsc_hdr *hdr = (void *)table + offset;
+   for (i = 0; i < rproc->rsc->num; i++) {
+   int offset = rproc->rsc->offset[i];
+   struct fw_rsc_hdr *hdr = (void *)rproc->rsc + offset;
int avail = len - offset - sizeof(*hdr);
void *rsc = (void *)hdr + sizeof(*hdr);
 
@@ -783,9 +782,13 @@ static int rproc_fw_boot(struct rproc *rproc, const struct 
firmware *fw)
 {
struct device *dev = &rproc->dev;
const char *name = rproc->firmware;
-   struct resource_table *table;
+   struct rproc_vdev *rvdev;
+   struct resource_table *table, *devmem_rsc, *tmp;
int ret, tablesz;
 
+   if (!rproc->rsc)
+   return -ENOMEM;
+
ret = rproc_fw_sanity_check(rproc, fw);
if (ret)
return ret;
@@ -811,8 +814,17 @@ static int rproc_fw_boot(struct rproc *rproc, const struct 
firmware *fw)
goto clean_up;
}
 
+   /* Verify that resource table in loaded fw is unchanged */
+   if (rproc->rsc_csum != ip_compute_csum(table, tablesz)) {
+   dev_err(dev, "resource checksum failed, fw changed?\n");
+   ret = -EINVAL;
+   goto clean_up;
+   }
+
+
/* handle fw resources which are required to boot rproc */
-   ret = rproc_handle_resource(rproc, table, tablesz, rproc_handle_rsc);
+   ret = rproc_handle_resource(rproc, tablesz,
+   rproc_handle_rsc);
if (ret) {
dev_err(dev, "Failed to process resources: %d\n", ret);
goto clean_up;
@@ -825,6 +837,26 @@ static int rproc_fw_boot(struct rproc *rproc, const struct 
firmware *fw)
goto clean_up;
}
 
+   /* Get the resource table address in device memory */
+   devmem_rsc = rproc_get_rsctab_addr(rproc, fw);
+
+   /* Copy the updated resource table to device memory */
+   memcpy(devmem_rsc, rproc->rsc, tablesz);
+
+   /* Free the copy of the resource table */
+   tmp = rproc->rsc;
+   rproc->rsc = devmem_rsc;
+   kfree(tmp);
+
+   /* Update the vdev rsc address */
+   list_for_each_entry(rvdev, &rproc->rvdevs, node) {
+   int offset = (void *)rvdev->rsc - (void *)tmp;
+   rvdev->rsc = (void *)devmem_rsc + offset;
+   }
+
+   /* Other virtio drivers will see the rsc table in device memory */
+   rproc->rsc = devmem_rsc;
+
/* power up the remote processor */
ret = rproc->ops->start(rproc);
if (ret) {
@@ -866,14 +898,21 @@ static void rproc_fw_config_virtio(const struct firmware 
*fw, void *context)
if (!table)
goto out;
 
-   rproc->max_notifyid = 0;
+   rproc->rsc_csum = ip_compute_csum(table, tablesz);
 
/* count the numbe of notify-ids */
-   ret = rproc_handle_resource(rproc, table, tablesz,
+   rproc->max_notifyid = 0;
+   rproc->rsc = table;
+   ret = rproc_handle_resource(rproc, tablesz,
rproc_handle_notifyid_rsc);
 
+   /* Copy resource table containing vdev config info */
+   rproc->rsc = kmalloc(tablesz, GFP_KERNEL);
+   if (rproc->rsc)
+   memcpy(rproc->rsc, table, tablesz);
+
/* look for virtio devices and register them */
-   ret = rproc_handle_resource(rproc, table, tablesz,
+   ret = rproc_handle_resource(rproc, tablesz,
rproc_handle_vdev_rsc);
if (ret)
goto out;
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index c0c363c.

[PATCH 0/9] remoteproc: Support bi-directional vdev config space

2013-02-10 Thread sjur . brandeland
From: Sjur Brændeland 

This patch-set adds support for shared resource table between
Linux kernel and remote devices.
- dynamically-allocated address of the vrings can be communicated
- vdev statuses can be communicated
- virtio config space becomes bi-directional
- virtio feature negotiation is two-way
- max_nofiyid is reported correctly

No device firmware changes are required for this patch-set.

Cheers,
Sjur

Dmitry Tarnyagin (1):
  remoteproc: Bugfix: Deallocate firmware image on shutdown

Sjur Brændeland (8):
  remoteproc: Refactor function rproc_elf_find_rsc_table
  remoteproc: Parse ELF file to find resource table address
  remoteproc: Parse STE-firmware and find resource table address
  remoteproc: Set vring addresses in resource table
  remoteproc: Support virtio config space.
  remoteproc: Code cleanup of resource parsing
  remoteproc: Calculate max_notifyid by counting vrings
  remoteproc: Always perserve resource table data

 drivers/remoteproc/remoteproc_core.c   |  146 
 drivers/remoteproc/remoteproc_elf_loader.c |   96 +--
 drivers/remoteproc/remoteproc_internal.h   |   13 +++
 drivers/remoteproc/remoteproc_virtio.c |   38 +++-
 drivers/remoteproc/ste_modem_rproc.c   |   50 +++---
 include/linux/remoteproc.h |7 +-
 6 files changed, 240 insertions(+), 110 deletions(-)

-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 3/9] remoteproc: Parse ELF file to find resource table address

2013-02-10 Thread sjur . brandeland
From: Sjur Brændeland 

Add function find_rsc_table_va to firmware ops. This function
returns the location of the resource table in shared memory
after loading.

Signed-off-by: Sjur Brændeland 
---
 drivers/remoteproc/remoteproc_elf_loader.c |   17 -
 drivers/remoteproc/remoteproc_internal.h   |   13 +
 2 files changed, 29 insertions(+), 1 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_elf_loader.c 
b/drivers/remoteproc/remoteproc_elf_loader.c
index a958950..3137fba 100644
--- a/drivers/remoteproc/remoteproc_elf_loader.c
+++ b/drivers/remoteproc/remoteproc_elf_loader.c
@@ -312,9 +312,24 @@ rproc_elf_find_rsc_table(struct rproc *rproc, const struct 
firmware *fw,
return table;
 }
 
+struct resource_table *rproc_elf_get_rsctab_addr(struct rproc *rproc,
+const struct firmware *fw)
+{
+   struct elf32_shdr *shdr;
+
+   shdr = find_rsc_shdr(&rproc->dev, (struct elf32_hdr *)fw->data,
+   fw->size);
+   if (!shdr)
+   return NULL;
+
+   /* Find resource table in loaded segments */
+   return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size);
+}
+
 const struct rproc_fw_ops rproc_elf_fw_ops = {
.load = rproc_elf_load_segments,
.find_rsc_table = rproc_elf_find_rsc_table,
.sanity_check = rproc_elf_sanity_check,
-   .get_boot_addr = rproc_elf_get_boot_addr
+   .get_boot_addr = rproc_elf_get_boot_addr,
+   .get_rsctab_addr = rproc_elf_get_rsctab_addr
 };
diff --git a/drivers/remoteproc/remoteproc_internal.h 
b/drivers/remoteproc/remoteproc_internal.h
index 7bb6648..3a5cb7d 100644
--- a/drivers/remoteproc/remoteproc_internal.h
+++ b/drivers/remoteproc/remoteproc_internal.h
@@ -32,6 +32,7 @@ struct rproc;
  * expects to find it
  * @sanity_check:  sanity check the fw image
  * @get_boot_addr: get boot address to entry point specified in firmware
+ * @get_rsctab_addr:   get resouce table address as specified in firmware
  */
 struct rproc_fw_ops {
struct resource_table *(*find_rsc_table) (struct rproc *rproc,
@@ -40,6 +41,8 @@ struct rproc_fw_ops {
int (*load)(struct rproc *rproc, const struct firmware *fw);
int (*sanity_check)(struct rproc *rproc, const struct firmware *fw);
u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
+   struct resource_table *(*get_rsctab_addr)(struct rproc *rproc,
+   const struct firmware *fw);
 };
 
 /* from remoteproc_core.c */
@@ -102,6 +105,16 @@ struct resource_table *rproc_find_rsc_table(struct rproc 
*rproc,
return NULL;
 }
 
+static inline
+struct resource_table *rproc_get_rsctab_addr(struct rproc *rproc,
+   const struct firmware *fw)
+{
+   if (rproc->fw_ops->get_rsctab_addr)
+   return rproc->fw_ops->get_rsctab_addr(rproc, fw);
+
+   return NULL;
+}
+
 extern const struct rproc_fw_ops rproc_elf_fw_ops;
 
 #endif /* REMOTEPROC_INTERNAL_H */
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH vringh 1/2] remoteproc: Add support for vringh (Host vrings)

2013-02-10 Thread sjur . brandeland
From: Sjur Brændeland 

Add functions for creating, deleting and kicking host-side virtio rings.

The host ring is not integrated with virtiqueues and cannot be managed
through virtio-config. Remoteproc must export functions for handling the
host-side virtio rings.

The functions rproc_virtio_get_vringh(), rproc_virtio_del_vringh(),
rproc_virtio_kick_vringh() are added to remoteproc_virtio.c. The
existing functions rproc_vq_interrupt() and rproc_virtio_find_vqs()
are updated to handle the new vhost rings.

Signed-off-by: Sjur Brændeland 
cc: Ohad Ben-Cohen 
cc: Rusty Russell 
cc: Ido Yariv 
cc: Erwan Yvin 

---
Hi Ohad,

I would really appreciate if you could find time to
review this patch. It will go via Rusty's vringh tree.

Feedback and review comments are welcomed.

Thanks,
Sjur


 drivers/remoteproc/Kconfig |3 +
 drivers/remoteproc/remoteproc_virtio.c |  127 ++--
 include/linux/remoteproc.h |   14 
 3 files changed, 137 insertions(+), 7 deletions(-)

diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index 96ce101..c7d1d36 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -7,6 +7,9 @@ config REMOTEPROC
depends on HAS_DMA
select FW_CONFIG
select VIRTIO
+   select VHOST_RING
+
+source drivers/vhost/Kconfig
 
 config OMAP_REMOTEPROC
tristate "OMAP remoteproc support"
diff --git a/drivers/remoteproc/remoteproc_virtio.c 
b/drivers/remoteproc/remoteproc_virtio.c
index 9e198e5..fa7bf7b 100644
--- a/drivers/remoteproc/remoteproc_virtio.c
+++ b/drivers/remoteproc/remoteproc_virtio.c
@@ -23,6 +23,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -60,10 +61,15 @@ irqreturn_t rproc_vq_interrupt(struct rproc *rproc, int 
notifyid)
dev_dbg(&rproc->dev, "vq index %d is interrupted\n", notifyid);
 
rvring = idr_find(&rproc->notifyids, notifyid);
-   if (!rvring || !rvring->vq)
+   if (!rvring)
return IRQ_NONE;
 
-   return vring_interrupt(0, rvring->vq);
+   if (rvring->vringh && rvring->vringh_cb)
+   return rvring->vringh_cb(&rvring->rvdev->vdev, rvring->vringh);
+   else if (rvring->vq)
+   return vring_interrupt(0, rvring->vq);
+   else
+   return IRQ_NONE;
 }
 EXPORT_SYMBOL(rproc_vq_interrupt);
 
@@ -149,14 +155,21 @@ static int rproc_virtio_find_vqs(struct virtio_device 
*vdev, unsigned nvqs,
   const char *names[])
 {
struct rproc *rproc = vdev_to_rproc(vdev);
-   int i, ret;
+   struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
+   int rng, id, ret, nrings = ARRAY_SIZE(rvdev->vring);
+
+   for (id = 0, rng = 0; rng < nrings; ++rng) {
+   struct rproc_vring *rvring = &rvdev->vring[rng];
+   /* Skip the host side rings */
+   if (rvring->vringh)
+   continue;
 
-   for (i = 0; i < nvqs; ++i) {
-   vqs[i] = rp_find_vq(vdev, i, callbacks[i], names[i]);
-   if (IS_ERR(vqs[i])) {
-   ret = PTR_ERR(vqs[i]);
+   vqs[id] = rp_find_vq(vdev, rng, callbacks[id], names[id]);
+   if (IS_ERR(vqs[id])) {
+   ret = PTR_ERR(vqs[id]);
goto error;
}
+   ++id;
}
 
/* now that the vqs are all set, boot the remote processor */
@@ -173,6 +186,106 @@ error:
return ret;
 }
 
+/**
+ * rproc_virtio_new_vringh() - create a reversed virtio ring.
+ * @vdev: the virtio device
+ * @index: the virtio ring index
+ * @cb: callback for the reversed virtio ring
+ *
+ * This function should be called by the virtio-driver
+ * before calling find_vqs(). It returns a struct vringh for
+ * accessing the virtio ring.
+ *
+ * Return: struct vhost, or NULL upon error.
+ */
+struct vringh *
+rproc_virtio_new_vringh(struct virtio_device *vdev, unsigned index,
+   irqreturn_t (*cb)(struct virtio_device *vdev,
+ struct vringh *vring))
+{
+   struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
+   struct rproc_vring *rvring;
+   struct vringh *vrh;
+   int err;
+
+   if (index > ARRAY_SIZE(rvdev->vring)) {
+   dev_err(&rvdev->vdev.dev, "bad vring index: %d\n", index);
+   return NULL;
+   }
+
+   vrh = kzalloc(sizeof(*vrh), GFP_KERNEL);
+   if (!vrh)
+   return NULL;
+
+   err = rproc_alloc_vring(rvdev, index);
+   if (err)
+   goto free_vring;
+
+
+   rvring = &rvdev->vring[index];
+   /* zero vring */
+   memset(rvring->va, 0, vring_size(rvring->len, rvring->align));
+   vring_init(&vrh->vring, rvring->len, rvring->va, rvring->align);
+
+   rvring->vringh_cb = cb;
+   rvring->vringh = vrh;
+
+   err = vringh_init_kern(vrh,
+  rvdev->dfeat

[PATCH vringh 2/2] caif_virtio: Introduce caif over virtio

2013-02-10 Thread sjur . brandeland
From: Vikram ARV 

Add the the Virtio shared memory driver for STE Modems.
caif_virtio is implemented utilizing the virtio framework
for data transport and is managed with the remoteproc frameworks.

The Virtio queue is used for transmitting data to the modem, and
the new vringh implementation is receiving data over the vring.

Signed-off-by: Vikram ARV 
Signed-off-by: Sjur Brændeland 

to: David S. Miller 
cc: Rusty Russell 
cc: Ohad Ben-Cohen 
cc: Ido Yariv 
cc: Erwan Yvin 
---
Hi Dave,

Rusty has accepted to take this patch via his tree.
Feedback and review comments are appreciated.

Thanks,
Sjur

 drivers/net/caif/Kconfig|8 +
 drivers/net/caif/Makefile   |3 +
 drivers/net/caif/caif_virtio.c  |  568 +++
 include/linux/virtio_caif.h |   24 ++
 include/uapi/linux/virtio_ids.h |1 +
 5 files changed, 604 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/caif/caif_virtio.c
 create mode 100644 include/linux/virtio_caif.h

diff --git a/drivers/net/caif/Kconfig b/drivers/net/caif/Kconfig
index abf4d7a..a8b67e9 100644
--- a/drivers/net/caif/Kconfig
+++ b/drivers/net/caif/Kconfig
@@ -47,3 +47,11 @@ config CAIF_HSI
The caif low level driver for CAIF over HSI.
Be aware that if you enable this then you also need to
enable a low-level HSI driver.
+
+config CAIF_VIRTIO
+   tristate "CAIF virtio transport driver"
+   depends on CAIF
+   depends on REMOTEPROC
+   default n
+   ---help---
+   The caif driver for CAIF over Virtio.
diff --git a/drivers/net/caif/Makefile b/drivers/net/caif/Makefile
index 91dff86..d9ee26a 100644
--- a/drivers/net/caif/Makefile
+++ b/drivers/net/caif/Makefile
@@ -13,3 +13,6 @@ obj-$(CONFIG_CAIF_SHM) += caif_shm.o
 
 # HSI interface
 obj-$(CONFIG_CAIF_HSI) += caif_hsi.o
+
+# Virtio interface
+obj-$(CONFIG_CAIF_VIRTIO) += caif_virtio.o
diff --git a/drivers/net/caif/caif_virtio.c b/drivers/net/caif/caif_virtio.c
new file mode 100644
index 000..e8ea114
--- /dev/null
+++ b/drivers/net/caif/caif_virtio.c
@@ -0,0 +1,568 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2012
+ * Contact: Sjur Brendeland / sjur.brandel...@stericsson.com
+ * Authors: Vicram Arv / vikram@stericsson.com,
+ * Dmitry Tarnyagin / dmitry.tarnya...@stericsson.com
+ * Sjur Brendeland / sjur.brandel...@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Vicram Arv ");
+MODULE_AUTHOR("Sjur Brendeland riov.allocated) {
+   kfree(ctx->riov.iov);
+   ctx->riov.iov = NULL;
+   ctx->riov.allocated = false;
+   }
+   ctx->riov.iov = NULL;
+   ctx->riov.i = 0;
+   ctx->riov.max = 0;
+}
+
+static void cfv_release_cb(struct virtqueue *vq_tx)
+{
+   struct cfv_info *cfv = vq_tx->vdev->priv;
+   tasklet_schedule(&cfv->tx_release_tasklet);
+}
+
+/* This is invoked whenever the remote processor completed processing
+ * a TX msg we just sent it, and the buffer is put back to the used ring.
+ */
+static void cfv_release_used_buf(struct virtqueue *vq_tx)
+{
+   struct cfv_info *cfv = vq_tx->vdev->priv;
+   unsigned long flags;
+
+   BUG_ON(vq_tx != cfv->vq_tx);
+   WARN_ON_ONCE(irqs_disabled());
+
+   for (;;) {
+   unsigned int len;
+   struct token_info *buf_info;
+
+   /* Get used buffer from used ring to recycle used descriptors */
+   spin_lock_irqsave(&cfv->tx_lock, flags);
+   buf_info = virtqueue_get_buf(vq_tx, &len);
+
+   if (!buf_info)
+   goto out;
+
+   BUG_ON(!cfv->queued_tx);
+   if (--cfv->queued_tx <= cfv->watermark_tx) {
+   cfv->watermark_tx = 0;
+   netif_tx_wake_all_queues(cfv->ndev);
+   }
+   spin_unlock_irqrestore(&cfv->tx_lock, flags);
+
+   dma_free_coherent(vq_tx->vdev->dev.parent->parent,
+ buf_info->size, buf_info->vaddr,
+ buf_info->dma_handle);
+   kfree(buf_info);
+   }
+   return;
+out:
+   spin_unlock_irqrestore(&cfv->tx_lock, flags);
+}
+
+static struct sk_buff *cfv_alloc_and_copy_skb(int *err,
+ struct cfv_info *cfv,
+ u8 *frm, u32 frm_len)
+{
+   struct sk_buff *skb;
+   u32 cfpkt_len, pad_len;
+
+   *err = 0;
+   /* Verify that packet size with down-link header and mtu size */
+   if (frm_len > cfv->mru || frm_len <= cfv->rx_hr + cfv->rx_tr) {
+   netdev_err(cfv->ndev,
+  "Invalid frmlen:%u  mtu:%u hr:%d tr:%d\n",
+  frm_len, cfv->mru,  c

[PATCH vringh 0/2] Introduce CAIF Virtio driver

2013-02-10 Thread sjur . brandeland
From: Sjur Brændeland 

This patch-set introduces the CAIF Virtio Link layer driver.

This driver depends on Rusty's new host virtio ring implementation,
so this patch-set is based on the vringh branch in Rusty's git.

Regards,
Sjur

cc: Rusty Russell 
cc: Ohad Ben-Cohen 
cc: David S. Miller 
cc: Ido Yariv 
cc: Erwan Yvin 

Sjur Brændeland (1):
  remoteproc: Add support for vringh (Host vrings)

Vikram ARV (1):
  caif_virtio: Introduce caif over virtio

 drivers/net/caif/Kconfig   |8 +
 drivers/net/caif/Makefile  |3 +
 drivers/net/caif/caif_virtio.c |  568 
 drivers/remoteproc/Kconfig |3 +
 drivers/remoteproc/remoteproc_virtio.c |  127 +++-
 include/linux/remoteproc.h |   14 +
 include/linux/virtio_caif.h|   24 ++
 include/uapi/linux/virtio_ids.h|1 +
 8 files changed, 741 insertions(+), 7 deletions(-)
 create mode 100644 drivers/net/caif/caif_virtio.c
 create mode 100644 include/linux/virtio_caif.h

-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[RFC] remoteproc: Add support for host-side (reversed) vrings

2013-01-18 Thread sjur . brandeland
From: Sjur Brændeland 

Hi Ohad, Ido and Rusty.

Rusty has implemented host-side virtio ring. I will be using vringh
for the caif_virtio driver. But we need to figure out how to
integrate the vringh into remoteproc. Below is my initial stab on this.

This code is completely untested, but I'd love to get some initial
feedback on this.

Ohad/Ido are you happy with this approach?

More code will follow after some test and debugging...

Regards,
Sjur

--
remoteproc: Add support for host-side (reversed) vrings

Add functions for creating, deleting and kicking host-side virtio rings.

The host ring is not integrated with virtiqueues and cannot be managed
through virtio-config. So the virtio drivers must call functions exported
from remoteproc for handling the host-side virtio rings.

The functions rproc_virtio_get_vringh(), rproc_virtio_del_vringh(),
rproc_virtio_kick_vringh() are added to remoteproc_virtio.c. The
existing functions rproc_vq_interrupt() and rproc_virtio_find_vqs()
are updated to handle the new vhost rings.

Signed-off-by: Sjur Brændeland 
---
 drivers/remoteproc/remoteproc_virtio.c |  116 ++--
 include/linux/remoteproc.h |   14 
 2 files changed, 124 insertions(+), 6 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_virtio.c 
b/drivers/remoteproc/remoteproc_virtio.c
index 9e198e5..1928433 100644
--- a/drivers/remoteproc/remoteproc_virtio.c
+++ b/drivers/remoteproc/remoteproc_virtio.c
@@ -23,6 +23,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -63,7 +64,10 @@ irqreturn_t rproc_vq_interrupt(struct rproc *rproc, int 
notifyid)
if (!rvring || !rvring->vq)
return IRQ_NONE;
 
-   return vring_interrupt(0, rvring->vq);
+   if (rvring->vringh && rvring->vringh_cb)
+   return rvring->vringh_cb(&rvring->rvdev->vdev, rvring->vringh);
+   else
+   return vring_interrupt(0, rvring->vq);
 }
 EXPORT_SYMBOL(rproc_vq_interrupt);
 
@@ -149,14 +153,21 @@ static int rproc_virtio_find_vqs(struct virtio_device 
*vdev, unsigned nvqs,
   const char *names[])
 {
struct rproc *rproc = vdev_to_rproc(vdev);
-   int i, ret;
+   struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
+   int rng, id, ret, nrings = ARRAY_SIZE(rvdev->vring);
+
+   for (id = 0, rng = 0; rng < nrings; ++rng) {
+   struct rproc_vring *rvring = &rvdev->vring[rng];
+   /* Skip the host side rings */
+   if (rvring->vringh)
+   continue;
 
-   for (i = 0; i < nvqs; ++i) {
-   vqs[i] = rp_find_vq(vdev, i, callbacks[i], names[i]);
-   if (IS_ERR(vqs[i])) {
-   ret = PTR_ERR(vqs[i]);
+   vqs[id] = rp_find_vq(vdev, rng, callbacks[id], names[id]);
+   if (IS_ERR(vqs[id])) {
+   ret = PTR_ERR(vqs[id]);
goto error;
}
+   ++id;
}
 
/* now that the vqs are all set, boot the remote processor */
@@ -173,6 +184,99 @@ error:
return ret;
 }
 
+/**
+ * rproc_virtio_new_vringh() - create a reversed virtio ring.
+ * @vdev: the virtio device
+ * @index: the virtio ring index
+ * @cb: callback for the reversed virtio ring
+ *
+ * This function should be called by the virtio-driver
+ * before calling find_vqs(). It returns a struct vringh for
+ * accessing the virtio ring.
+ *
+ * Return: struct vhost, or NULL upon error.
+ */
+struct vringh *
+rproc_virtio_new_vringh(struct virtio_device *vdev, unsigned index,
+   irqreturn_t (*cb)(struct virtio_device *vdev,
+ struct vringh *vring))
+{
+   struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
+   struct rproc_vring *rvring;
+   struct vringh *vrh;
+   int err;
+
+   if (index > ARRAY_SIZE(rvdev->vring)) {
+   dev_err(&rvdev->vdev.dev, "bad vring index: %d\n", index);
+   return NULL;
+   }
+
+   vrh = kzalloc(sizeof(*vrh), GFP_KERNEL);
+   if (!vrh)
+   return NULL;
+
+
+   rvring = &rvdev->vring[index];
+   vring_init(&vrh->vring, rvring->len, rvring->va, rvring->align);
+   /* zero vring */
+   memset(&vrh->vring, 0, vring_size(rvring->len, rvring->align));
+   rvring->vringh_cb = cb;
+   rvring->vringh = vrh;
+
+   err = vringh_init_kern(vrh,
+  rvdev->dfeatures,
+  rvring->len,
+  false,
+  vrh->vring.desc,
+  vrh->vring.avail,
+  vrh->vring.used);
+   if (err) {
+   dev_err(&vdev->dev, "failed to create vhost: %d\n", err);
+   kfree(vrh);
+   vrh = NULL;
+   }
+
+   return vrh;
+}
+EXPORT_SYMBOL(rproc_virtio_get_vringh);
+
+/**
+ * rproc_virtio_del_vri

[PATCH] remoteproc: Deallocate firmware image on shutdown

2013-01-17 Thread sjur . brandeland
From: Dmitry Tarnyagin 

Fixes coherent memory leakage, caused by non-deallocated
firmware image chunk.

Signed-off-by: Dmitry Tarnyagin 
---

This fix is intended for v3.8.

Thanks,
Sjur

 drivers/remoteproc/ste_modem_rproc.c |7 ++-
 1 files changed, 6 insertions(+), 1 deletions(-)

diff --git a/drivers/remoteproc/ste_modem_rproc.c 
b/drivers/remoteproc/ste_modem_rproc.c
index a7743c0..fb95c42 100644
--- a/drivers/remoteproc/ste_modem_rproc.c
+++ b/drivers/remoteproc/ste_modem_rproc.c
@@ -240,6 +240,8 @@ static int sproc_drv_remove(struct platform_device *pdev)
 
/* Unregister as remoteproc device */
rproc_del(sproc->rproc);
+   dma_free_coherent(sproc->rproc->dev.parent, SPROC_FW_SIZE,
+ sproc->fw_addr, sproc->fw_dma_addr);
rproc_put(sproc->rproc);
 
mdev->drv_data = NULL;
@@ -297,10 +299,13 @@ static int sproc_probe(struct platform_device *pdev)
/* Register as a remoteproc device */
err = rproc_add(rproc);
if (err)
-   goto free_rproc;
+   goto free_mem;
 
return 0;
 
+free_mem:
+   dma_free_coherent(rproc->dev.parent, SPROC_FW_SIZE,
+ sproc->fw_addr, sproc->fw_dma_addr);
 free_rproc:
/* Reset device data upon error */
mdev->drv_data = NULL;
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[RFCv3 04/11] remoteproc: Refactor function rproc_elf_find_rsc_table

2013-01-16 Thread sjur . brandeland
From: Sjur Brændeland 

Refactor rproc_elf_find_rsc_table and split out the scanning
for the section header named resource table. This is done to
prepare for loading firmware once.

Signed-off-by: Sjur Brændeland 
---
 drivers/remoteproc/remoteproc_elf_loader.c |   79 ++--
 1 files changed, 52 insertions(+), 27 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_elf_loader.c 
b/drivers/remoteproc/remoteproc_elf_loader.c
index e1f89d6..32a29b8 100644
--- a/drivers/remoteproc/remoteproc_elf_loader.c
+++ b/drivers/remoteproc/remoteproc_elf_loader.c
@@ -208,38 +208,19 @@ rproc_elf_load_segments(struct rproc *rproc, const struct 
firmware *fw)
return ret;
 }
 
-/**
- * rproc_elf_find_rsc_table() - find the resource table
- * @rproc: the rproc handle
- * @fw: the ELF firmware image
- * @tablesz: place holder for providing back the table size
- *
- * This function finds the resource table inside the remote processor's
- * firmware. It is used both upon the registration of @rproc (in order
- * to look for and register the supported virito devices), and when the
- * @rproc is booted.
- *
- * Returns the pointer to the resource table if it is found, and write its
- * size into @tablesz. If a valid table isn't found, NULL is returned
- * (and @tablesz isn't set).
- */
-static struct resource_table *
-rproc_elf_find_rsc_table(struct rproc *rproc, const struct firmware *fw,
-   int *tablesz)
+static struct elf32_shdr *
+find_rsc_shdr(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
 {
-   struct elf32_hdr *ehdr;
struct elf32_shdr *shdr;
+   int i;
const char *name_table;
-   struct device *dev = &rproc->dev;
struct resource_table *table = NULL;
-   int i;
-   const u8 *elf_data = fw->data;
+   const u8 *elf_data = (void *)ehdr;
 
-   ehdr = (struct elf32_hdr *)elf_data;
+   /* look for the resource table and handle it */
shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
name_table = elf_data + shdr[ehdr->e_shstrndx].sh_offset;
 
-   /* look for the resource table and handle it */
for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
int size = shdr->sh_size;
int offset = shdr->sh_offset;
@@ -250,7 +231,7 @@ rproc_elf_find_rsc_table(struct rproc *rproc, const struct 
firmware *fw,
table = (struct resource_table *)(elf_data + offset);
 
/* make sure we have the entire table */
-   if (offset + size > fw->size) {
+   if (offset + size > fw_size) {
dev_err(dev, "resource table truncated\n");
return NULL;
}
@@ -280,10 +261,54 @@ rproc_elf_find_rsc_table(struct rproc *rproc, const 
struct firmware *fw,
return NULL;
}
 
-   *tablesz = shdr->sh_size;
-   break;
+   return shdr;
}
 
+   return NULL;
+}
+
+/**
+ * rproc_elf_find_rsc_table() - find the resource table
+ * @rproc: the rproc handle
+ * @fw: the ELF firmware image
+ * @tablesz: place holder for providing back the table size
+ *
+ * This function finds the resource table inside the remote processor's
+ * firmware. It is used both upon the registration of @rproc (in order
+ * to look for and register the supported virito devices), and when the
+ * @rproc is booted.
+ *
+ * Returns the pointer to the resource table if it is found, and write its
+ * size into @tablesz. If a valid table isn't found, NULL is returned
+ * (and @tablesz isn't set).
+ */
+static struct resource_table *
+rproc_elf_find_rsc_table(struct rproc *rproc, const struct firmware *fw,
+   int *tablesz)
+{
+   struct elf32_hdr *ehdr;
+   struct elf32_shdr *shdr;
+
+   struct device *dev = &rproc->dev;
+   struct resource_table *table = NULL;
+
+   const u8 *elf_data = fw->data;
+
+   ehdr = (struct elf32_hdr *)elf_data;
+
+   shdr = find_rsc_shdr(dev, ehdr, fw->size);
+   if (!shdr)
+   return NULL;
+
+   /* make sure we have the entire table */
+   if (shdr->sh_offset + shdr->sh_size > fw->size) {
+   dev_err(dev, "resource table truncated\n");
+   return NULL;
+   }
+
+   table = (struct resource_table *)(elf_data + shdr->sh_offset);
+   *tablesz = shdr->sh_size;
+
return table;
 }
 
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[RFCv3 06/11] remoteproc: Parse STE-firmware and find resource table address

2013-01-16 Thread sjur . brandeland
From: Sjur Brændeland 

Parse the STE firmware and scan the TOC-table to find the address
of the resource table.

Signed-off-by: Sjur Brændeland 
---
 drivers/remoteproc/ste_modem_rproc.c |   43 +++---
 1 files changed, 29 insertions(+), 14 deletions(-)

diff --git a/drivers/remoteproc/ste_modem_rproc.c 
b/drivers/remoteproc/ste_modem_rproc.c
index a7743c0..59e99f1 100644
--- a/drivers/remoteproc/ste_modem_rproc.c
+++ b/drivers/remoteproc/ste_modem_rproc.c
@@ -64,26 +64,18 @@ static int sproc_load_segments(struct rproc *rproc, const 
struct firmware *fw)
 }
 
 /* Find the entry for resource table in the Table of Content */
-static struct ste_toc_entry *sproc_find_rsc_entry(const struct firmware *fw)
+static const struct ste_toc_entry *sproc_find_rsc_entry(const void *data)
 {
int i;
-   struct ste_toc *toc;
-
-   if (!fw)
-   return NULL;
-
-   toc = (void *)fw->data;
+   const struct ste_toc *toc;
+   toc = data;
 
/* Search the table for the resource table */
for (i = 0; i < SPROC_MAX_TOC_ENTRIES &&
toc->table[i].start != 0x; i++) {
-
if (!strncmp(toc->table[i].name, SPROC_RESOURCE_NAME,
-sizeof(toc->table[i].name))) {
-   if (toc->table[i].start > fw->size)
-   return NULL;
+sizeof(toc->table[i].name)))
return &toc->table[i];
-   }
}
 
return NULL;
@@ -96,9 +88,12 @@ sproc_find_rsc_table(struct rproc *rproc, const struct 
firmware *fw,
 {
struct sproc *sproc = rproc->priv;
struct resource_table *table;
-   struct ste_toc_entry *entry;
+   const struct ste_toc_entry *entry;
 
-   entry = sproc_find_rsc_entry(fw);
+   if (!fw)
+   return NULL;
+
+   entry = sproc_find_rsc_entry(fw->data);
if (!entry) {
sproc_err(sproc, "resource table not found in fw\n");
return NULL;
@@ -149,10 +144,30 @@ sproc_find_rsc_table(struct rproc *rproc, const struct 
firmware *fw,
return table;
 }
 
+/* Find the resource table inside the remote processor's firmware. */
+static struct resource_table *
+sproc_get_rsctab_addr(struct rproc *rproc, const struct firmware *fw)
+{
+   struct sproc *sproc = rproc->priv;
+   const struct ste_toc_entry *entry;
+
+   if (!fw || !sproc->fw_addr)
+   return NULL;
+
+   entry = sproc_find_rsc_entry(sproc->fw_addr);
+   if (!entry) {
+   sproc_err(sproc, "resource table not found in fw\n");
+   return NULL;
+   }
+
+   return sproc->fw_addr + entry->start;
+}
+
 /* STE modem firmware handler operations */
 const struct rproc_fw_ops sproc_fw_ops = {
.load = sproc_load_segments,
.find_rsc_table = sproc_find_rsc_table,
+   .get_rsctab_addr = sproc_get_rsctab_addr,
 };
 
 /* Kick the modem with specified notification id */
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[RFCv3 00/11] remoteproc: Support bi-directional vdev config space

2013-01-16 Thread sjur . brandeland
From: Sjur Brændeland 

Changes since v2:
- Addressed review comments
- Reworked patch "Load firmware once". 

This patch-set is not yet thoroughly tested, but works in my
simulated environment.

This patch-set adds support for shared resource table between
Linux kernel and remote devices. 
- dynamically-allocated address of the vrings can be communicated
- vdev statuses can be communicated
- virtio config space becomes bi-directional
- virtio feature negotiation is two-way 
- Carveout can be allocated from start of device memory.
  dma_alloc_coherent() aligns to size of memory area. So if you e.g. 
  have 8Mb of memory, you cannot have carveout larger than 4Mb
  unless the carveout is allocated from start of the device memory
  area.

NOTE: This change is not backwards compatible with existing
device firmware! The memory allocation order changes. Previously
the Virtio Rings were always allocated at start of the share memory
area, but with this patch-set Virtio Rings are allocated after the
Carveouts. The address of the vrings are set in the resource table.

Cheers,
Sjur

Sjur Brændeland (11):
  remoteproc: Move enable_iommu to rproc_boot
  remoteproc: Code cleanup of resource parsing
  remoteproc: Move check on firmware name to rproc_add
  remoteproc: Refactor function rproc_elf_find_rsc_table
  remoteproc: Parse ELF file to find resource table address
  remoteproc: Parse STE-firmware and find resource table address
  remoteproc: Add state RPROC_LOADED
  remoteproc: Set vring addresses in resource table
  remoteproc: Load firmware once.
  remoteproc: Support virtio config space.
  remoteproc: Calculate max_notifyid by counting vrings

 drivers/remoteproc/remoteproc_core.c   |  264 +---
 drivers/remoteproc/remoteproc_debugfs.c|1 +
 drivers/remoteproc/remoteproc_elf_loader.c |   96 +++---
 drivers/remoteproc/remoteproc_internal.h   |   16 ++
 drivers/remoteproc/remoteproc_virtio.c |   38 -
 drivers/remoteproc/ste_modem_rproc.c   |   43 +++--
 include/linux/remoteproc.h |7 +-
 7 files changed, 273 insertions(+), 192 deletions(-)

-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[RFCv3 02/11] remoteproc: Code cleanup of resource parsing

2013-01-16 Thread sjur . brandeland
From: Sjur Brændeland 

Combine the almost identical functions rproc_handle_virtio_rsc
and rproc_handle_boot_rsc.

Signed-off-by: Sjur Brændeland 
---
 drivers/remoteproc/remoteproc_core.c |   51 --
 1 files changed, 12 insertions(+), 39 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_core.c 
b/drivers/remoteproc/remoteproc_core.c
index ceca76c..d21f8797 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -678,16 +678,22 @@ free_carv:
  * A lookup table for resource handlers. The indices are defined in
  * enum fw_resource_type.
  */
-static rproc_handle_resource_t rproc_handle_rsc[] = {
+static rproc_handle_resource_t rproc_handle_rsc[RSC_LAST] = {
[RSC_CARVEOUT] = (rproc_handle_resource_t)rproc_handle_carveout,
[RSC_DEVMEM] = (rproc_handle_resource_t)rproc_handle_devmem,
[RSC_TRACE] = (rproc_handle_resource_t)rproc_handle_trace,
[RSC_VDEV] = NULL, /* VDEVs were handled upon registrarion */
 };
 
+static rproc_handle_resource_t rproc_handle_vdev_rsc[RSC_LAST] = {
+   [RSC_VDEV] = (rproc_handle_resource_t)rproc_handle_vdev,
+};
+
 /* handle firmware resource entries before booting the remote processor */
 static int
-rproc_handle_boot_rsc(struct rproc *rproc, struct resource_table *table, int 
len)
+rproc_handle_resource(struct rproc *rproc, struct resource_table *table,
+   int len,
+   rproc_handle_resource_t handlers[RSC_LAST])
 {
struct device *dev = &rproc->dev;
rproc_handle_resource_t handler;
@@ -712,7 +718,7 @@ rproc_handle_boot_rsc(struct rproc *rproc, struct 
resource_table *table, int len
continue;
}
 
-   handler = rproc_handle_rsc[hdr->type];
+   handler = handlers[hdr->type];
if (!handler)
continue;
 
@@ -724,40 +730,6 @@ rproc_handle_boot_rsc(struct rproc *rproc, struct 
resource_table *table, int len
return ret;
 }
 
-/* handle firmware resource entries while registering the remote processor */
-static int
-rproc_handle_virtio_rsc(struct rproc *rproc, struct resource_table *table, int 
len)
-{
-   struct device *dev = &rproc->dev;
-   int ret = 0, i;
-
-   for (i = 0; i < table->num; i++) {
-   int offset = table->offset[i];
-   struct fw_rsc_hdr *hdr = (void *)table + offset;
-   int avail = len - offset - sizeof(*hdr);
-   struct fw_rsc_vdev *vrsc;
-
-   /* make sure table isn't truncated */
-   if (avail < 0) {
-   dev_err(dev, "rsc table is truncated\n");
-   return -EINVAL;
-   }
-
-   dev_dbg(dev, "%s: rsc type %d\n", __func__, hdr->type);
-
-   if (hdr->type != RSC_VDEV)
-   continue;
-
-   vrsc = (struct fw_rsc_vdev *)hdr->data;
-
-   ret = rproc_handle_vdev(rproc, vrsc, avail);
-   if (ret)
-   break;
-   }
-
-   return ret;
-}
-
 /**
  * rproc_resource_cleanup() - clean up and free all acquired resources
  * @rproc: rproc handle
@@ -827,7 +799,7 @@ static int rproc_fw_boot(struct rproc *rproc, const struct 
firmware *fw)
}
 
/* handle fw resources which are required to boot rproc */
-   ret = rproc_handle_boot_rsc(rproc, table, tablesz);
+   ret = rproc_handle_resource(rproc, table, tablesz, rproc_handle_rsc);
if (ret) {
dev_err(dev, "Failed to process resources: %d\n", ret);
goto clean_up;
@@ -882,7 +854,8 @@ static void rproc_fw_config_virtio(const struct firmware 
*fw, void *context)
goto out;
 
/* look for virtio devices and register them */
-   ret = rproc_handle_virtio_rsc(rproc, table, tablesz);
+   ret = rproc_handle_resource(rproc, table, tablesz,
+   rproc_handle_vdev_rsc);
if (ret)
goto out;
 
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[RFCv3 07/11] remoteproc: Add state RPROC_LOADED

2013-01-16 Thread sjur . brandeland
From: Sjur Brændeland 

Add state RPROC_LOADED as firmware loading and startup will be
different states.

Signed-off-by: Sjur Brændeland 
---
 drivers/remoteproc/remoteproc_debugfs.c |1 +
 include/linux/remoteproc.h  |3 ++-
 2 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_debugfs.c 
b/drivers/remoteproc/remoteproc_debugfs.c
index 157a573..a026359 100644
--- a/drivers/remoteproc/remoteproc_debugfs.c
+++ b/drivers/remoteproc/remoteproc_debugfs.c
@@ -68,6 +68,7 @@ static const char * const rproc_state_string[] = {
"suspended",
"running",
"crashed",
+   "loaded",
"invalid",
 };
 
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index faf3332..17b8120 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -357,7 +357,8 @@ enum rproc_state {
RPROC_SUSPENDED = 1,
RPROC_RUNNING   = 2,
RPROC_CRASHED   = 3,
-   RPROC_LAST  = 4,
+   RPROC_LOADED= 4,
+   RPROC_LAST  = 5,
 };
 
 /**
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[RFCv3 08/11] remoteproc: Set vring addresses in resource table

2013-01-16 Thread sjur . brandeland
From: Sjur Brændeland 

Set the vring addresses in the resource table so that
the remote device can read the actual addresses used.

Signed-off-by: Sjur Brændeland 
---
 drivers/remoteproc/remoteproc_core.c |   13 +++--
 include/linux/remoteproc.h   |2 ++
 2 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_core.c 
b/drivers/remoteproc/remoteproc_core.c
index 9caf533..8604b60 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -208,7 +208,6 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i)
/*
 * Allocate non-cacheable memory for the vring. In the future
 * this call will also configure the IOMMU for us
-* TODO: let the rproc know the da of this vring
 */
va = dma_alloc_coherent(dev->parent, size, &dma, GFP_KERNEL);
if (!va) {
@@ -219,7 +218,6 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i)
/*
 * Assign an rproc-wide unique index for this vring
 * TODO: assign a notifyid for rvdev updates as well
-* TODO: let the rproc know the notifyid of this vring
 * TODO: support predefined notifyids (via resource table)
 */
ret = idr_get_new(&rproc->notifyids, rvring, ¬ifyid);
@@ -239,6 +237,14 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i)
rvring->dma = dma;
rvring->notifyid = notifyid;
 
+   /*
+* Let the rproc know the notifyid and da of this vring.
+* Not all platforms use dma_alloc_coherent to automatically
+* set up the iommu. In this case the device address (da) will
+* hold the physical address and not the device address.
+*/
+   rvdev->rsc->vring[i].da = dma;
+   rvdev->rsc->vring[i].notifyid = notifyid;
return 0;
 }
 
@@ -366,6 +372,9 @@ static int rproc_handle_vdev(struct rproc *rproc, struct 
fw_rsc_vdev *rsc,
/* remember the device features */
rvdev->dfeatures = rsc->dfeatures;
 
+   /* remember the resource entry */
+   rvdev->rsc = rsc;
+
list_add_tail(&rvdev->node, &rproc->rvdevs);
 
/* it is now safe to add the virtio device */
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index 17b8120..932edc7 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -465,6 +465,7 @@ struct rproc_vring {
  * @vring: the vrings for this vdev
  * @dfeatures: virtio device features
  * @gfeatures: virtio guest features
+ * @rsc: vdev resource entry
  */
 struct rproc_vdev {
struct list_head node;
@@ -473,6 +474,7 @@ struct rproc_vdev {
struct rproc_vring vring[RVDEV_NUM_VRINGS];
unsigned long dfeatures;
unsigned long gfeatures;
+   struct fw_rsc_vdev *rsc;
 };
 
 struct rproc *rproc_alloc(struct device *dev, const char *name,
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[RFCv3 03/11] remoteproc: Move check on firmware name to rproc_add

2013-01-16 Thread sjur . brandeland
From: Sjur Brændeland 

Verify that firmware name is defined in rproc_add.

Signed-off-by: Sjur Brændeland 
---
 drivers/remoteproc/remoteproc_core.c |   13 ++---
 1 files changed, 6 insertions(+), 7 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_core.c 
b/drivers/remoteproc/remoteproc_core.c
index d21f8797..9caf533 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -980,13 +980,6 @@ int rproc_boot(struct rproc *rproc)
return ret;
}
 
-   /* loading a firmware is required */
-   if (!rproc->firmware) {
-   dev_err(dev, "%s: no firmware to load\n", __func__);
-   ret = -EINVAL;
-   goto unlock_mutex;
-   }
-
/* prevent underlying implementation from being removed */
if (!try_module_get(dev->parent->driver->owner)) {
dev_err(dev, "%s: can't get owner\n", __func__);
@@ -1122,6 +1115,12 @@ int rproc_add(struct rproc *rproc)
struct device *dev = &rproc->dev;
int ret;
 
+   /* loading a firmware is required */
+   if (!rproc->firmware) {
+   dev_err(dev, "%s: no firmware to load\n", __func__);
+   return -EINVAL;
+   }
+
ret = device_add(dev);
if (ret < 0)
return ret;
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[RFCv3 09/11] remoteproc: Load firmware once.

2013-01-16 Thread sjur . brandeland
From: Sjur Brændeland 

Add support for two-way virtio configuration space and status.
Ring-addresses and negotiated feature-bits are readable from device.
Allocation of larger Carveouts are also supported. And when
adding a new rproc device, the firmware is now loaded once not
twice. But there is a catch:

   This patch requires device firmware change!

The device memory layout changes.The virtio rings are no longer
located at start of the device memory. But the device must read the
vring address from the resource table.

This patch also re-organizes the resource handling.
rproc_fw_load() will allocate all resource table resources:
carveouts, trace buffers and vrings. To undo rproc_fw_load(),
vdevs must be unregistered and rproc_resource_cleanup() must
be called.

rproc_boot() will increment power ref-count and module ref-count,
enable iommu, and start the device. rproc_shutdown() reverses all this.

Cycles of rproc_shutdown(), rproc_boot() is handeled by reloading
the firmware (rproc_boot() will reload if state != RPROC_LOADED).

Signed-off-by: Sjur Brændeland 
---
 drivers/remoteproc/remoteproc_core.c |  158 +++--
 drivers/remoteproc/remoteproc_internal.h |3 +
 2 files changed, 85 insertions(+), 76 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_core.c 
b/drivers/remoteproc/remoteproc_core.c
index 8604b60..da1ff4f 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -698,7 +698,7 @@ static rproc_handle_resource_t 
rproc_handle_vdev_rsc[RSC_LAST] = {
[RSC_VDEV] = (rproc_handle_resource_t)rproc_handle_vdev,
 };
 
-/* handle firmware resource entries before booting the remote processor */
+/* handle firmware resource entries */
 static int
 rproc_handle_resource(struct rproc *rproc, struct resource_table *table,
int len,
@@ -782,11 +782,34 @@ static void rproc_resource_cleanup(struct rproc *rproc)
}
 }
 
+static int rproc_fw_reload(struct rproc *rproc)
+{
+   const struct firmware *fw;
+   int err;
+
+   err = request_firmware(&fw, rproc->firmware, &rproc->dev);
+   if (err < 0)
+   return err;
+
+   /* TODO: Compare FW checksum between old and new image */
+
+   /* load the ELF segments to memory */
+   err = rproc_load_segments(rproc, fw);
+   release_firmware(fw);
+   return err;
+}
+
 /*
- * take a firmware and boot a remote processor with it.
+ * take a firmware, parse the resouce table and load it
+ *
+ * Note: this function is called asynchronously upon registration of the
+ * remote processor (so we must wait until it completes before we try
+ * to unregister the device. one other option is just to use kref here,
+ * that might be cleaner).
  */
-static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
+static void rproc_fw_load(const struct firmware *fw, void *context)
 {
+   struct rproc *rproc = context;
struct device *dev = &rproc->dev;
const char *name = rproc->firmware;
struct resource_table *table;
@@ -794,7 +817,7 @@ static int rproc_fw_boot(struct rproc *rproc, const struct 
firmware *fw)
 
ret = rproc_fw_sanity_check(rproc, fw);
if (ret)
-   return ret;
+   goto release_fw;
 
dev_info(dev, "Booting fw image %s, size %zd\n", name, fw->size);
 
@@ -807,7 +830,7 @@ static int rproc_fw_boot(struct rproc *rproc, const struct 
firmware *fw)
goto clean_up;
}
 
-   /* handle fw resources which are required to boot rproc */
+   /* handle fw resources which are required to load rproc */
ret = rproc_handle_resource(rproc, table, tablesz, rproc_handle_rsc);
if (ret) {
dev_err(dev, "Failed to process resources: %d\n", ret);
@@ -821,60 +844,37 @@ static int rproc_fw_boot(struct rproc *rproc, const 
struct firmware *fw)
goto clean_up;
}
 
-   /* power up the remote processor */
-   ret = rproc->ops->start(rproc);
-   if (ret) {
-   dev_err(dev, "can't start rproc %s: %d\n", rproc->name, ret);
+   /* look for the resource table in device memory */
+   table = rproc_get_rsctab_addr(rproc, fw);
+   if (!table) {
+   ret = -EINVAL;
goto clean_up;
}
 
-   rproc->state = RPROC_RUNNING;
+   rproc->state = RPROC_LOADED;
 
-   dev_info(dev, "remote processor %s is now up\n", rproc->name);
+   /* handle vdev resources, this will normally start the device */
+   ret = rproc_handle_resource(rproc, table, tablesz,
+   rproc_handle_vdev_rsc);
+   if (ret) {
+   dev_err(dev, "Failed to process resources: %d\n", ret);
+   goto clean_up;
+   }
 
-   return 0;
+   dev_info(dev, "remote processor %s is loaded to memory\n", rproc->name);
 
 clean_up:
-   rproc_resource_cleanup(rproc);
-   rproc_di

[RFCv3 10/11] remoteproc: Support virtio config space.

2013-01-16 Thread sjur . brandeland
From: Sjur Brændeland 

Support virtio configuration space and device status and
feature negotiation with remote device. This virtio device
can now access the resource table in shared memory.

Signed-off-by: Sjur Brændeland 
---
 drivers/remoteproc/remoteproc_core.c   |3 --
 drivers/remoteproc/remoteproc_virtio.c |   38 +--
 include/linux/remoteproc.h |2 -
 3 files changed, 35 insertions(+), 8 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_core.c 
b/drivers/remoteproc/remoteproc_core.c
index da1ff4f..4f342e0 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -369,9 +369,6 @@ static int rproc_handle_vdev(struct rproc *rproc, struct 
fw_rsc_vdev *rsc,
goto free_rvdev;
}
 
-   /* remember the device features */
-   rvdev->dfeatures = rsc->dfeatures;
-
/* remember the resource entry */
rvdev->rsc = rsc;
 
diff --git a/drivers/remoteproc/remoteproc_virtio.c 
b/drivers/remoteproc/remoteproc_virtio.c
index e7a4780..eb2089a 100644
--- a/drivers/remoteproc/remoteproc_virtio.c
+++ b/drivers/remoteproc/remoteproc_virtio.c
@@ -176,16 +176,21 @@ error:
  */
 static u8 rproc_virtio_get_status(struct virtio_device *vdev)
 {
-   return 0;
+   struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
+   return rvdev->rsc->status;
 }
 
 static void rproc_virtio_set_status(struct virtio_device *vdev, u8 status)
 {
+   struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
+   rvdev->rsc->status = status;
dev_dbg(&vdev->dev, "status: %d\n", status);
 }
 
 static void rproc_virtio_reset(struct virtio_device *vdev)
 {
+   struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
+   rvdev->rsc->status = 0;
dev_dbg(&vdev->dev, "reset !\n");
 }
 
@@ -194,7 +199,7 @@ static u32 rproc_virtio_get_features(struct virtio_device 
*vdev)
 {
struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
 
-   return rvdev->dfeatures;
+   return rvdev->rsc->dfeatures;
 }
 
 static void rproc_virtio_finalize_features(struct virtio_device *vdev)
@@ -213,7 +218,31 @@ static void rproc_virtio_finalize_features(struct 
virtio_device *vdev)
 * fixed as part of a small resource table overhaul and then an
 * extension of the virtio resource entries.
 */
-   rvdev->gfeatures = vdev->features[0];
+   rvdev->rsc->gfeatures = vdev->features[0];
+}
+
+void rproc_virtio_get(struct virtio_device *vdev, unsigned offset,
+   void *buf, unsigned len)
+{
+   struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
+   void *cfg = &rvdev->rsc->vring[rvdev->rsc->num_of_vrings];
+   if (offset + len > rvdev->rsc->config_len)
+   dev_err(&vdev->dev,
+   "rproc_virtio_get: access out of bounds\n");
+   else
+   memcpy(buf, cfg + offset, len);
+}
+
+void rproc_virtio_set(struct virtio_device *vdev, unsigned offset,
+ const void *buf, unsigned len)
+{
+   struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
+   void *cfg = &rvdev->rsc->vring[rvdev->rsc->num_of_vrings];
+   if (offset + len > rvdev->rsc->config_len)
+   dev_err(&vdev->dev,
+   "rproc_virtio_set: access out of bounds\n");
+   else
+   memcpy(cfg + offset, buf, len);
 }
 
 static struct virtio_config_ops rproc_virtio_config_ops = {
@@ -224,6 +253,9 @@ static struct virtio_config_ops rproc_virtio_config_ops = {
.reset  = rproc_virtio_reset,
.set_status = rproc_virtio_set_status,
.get_status = rproc_virtio_get_status,
+   .get= rproc_virtio_get,
+   .set= rproc_virtio_set,
+
 };
 
 /*
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index 932edc7..d41d66f 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -472,8 +472,6 @@ struct rproc_vdev {
struct rproc *rproc;
struct virtio_device vdev;
struct rproc_vring vring[RVDEV_NUM_VRINGS];
-   unsigned long dfeatures;
-   unsigned long gfeatures;
struct fw_rsc_vdev *rsc;
 };
 
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[RFCv3 11/11] remoteproc: Calculate max_notifyid by counting vrings

2013-01-16 Thread sjur . brandeland
From: Sjur Brændeland 

Simplify hanling of max_notifyid by simply counting the
number of vrings.

Signed-off-by: Sjur Brændeland 
---
 drivers/remoteproc/remoteproc_core.c |   20 +---
 1 files changed, 5 insertions(+), 15 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_core.c 
b/drivers/remoteproc/remoteproc_core.c
index 4f342e0..31ecb30 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -227,9 +227,6 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i)
return ret;
}
 
-   /* Store largest notifyid */
-   rproc->max_notifyid = max(rproc->max_notifyid, notifyid);
-
dev_dbg(dev, "vring%d: va %p dma %llx size %x idr %d\n", i, va,
(unsigned long long)dma, size, notifyid);
 
@@ -279,25 +276,13 @@ rproc_parse_vring(struct rproc_vdev *rvdev, struct 
fw_rsc_vdev *rsc, int i)
return 0;
 }
 
-static int rproc_max_notifyid(int id, void *p, void *data)
-{
-   int *maxid = data;
-   *maxid = max(*maxid, id);
-   return 0;
-}
-
 void rproc_free_vring(struct rproc_vring *rvring)
 {
int size = PAGE_ALIGN(vring_size(rvring->len, rvring->align));
struct rproc *rproc = rvring->rvdev->rproc;
-   int maxid = 0;
 
dma_free_coherent(rproc->dev.parent, size, rvring->va, rvring->dma);
idr_remove(&rproc->notifyids, rvring->notifyid);
-
-   /* Find the largest remaining notifyid */
-   idr_for_each(&rproc->notifyids, rproc_max_notifyid, &maxid);
-   rproc->max_notifyid = maxid;
 }
 
 /**
@@ -372,6 +357,9 @@ static int rproc_handle_vdev(struct rproc *rproc, struct 
fw_rsc_vdev *rsc,
/* remember the resource entry */
rvdev->rsc = rsc;
 
+   /* Summerize the number of notification IDs */
+   rproc->max_notifyid += rsc->num_of_vrings;
+
list_add_tail(&rvdev->node, &rproc->rvdevs);
 
/* it is now safe to add the virtio device */
@@ -827,6 +815,8 @@ static void rproc_fw_load(const struct firmware *fw, void 
*context)
goto clean_up;
}
 
+   rproc->max_notifyid = 0;
+
/* handle fw resources which are required to load rproc */
ret = rproc_handle_resource(rproc, table, tablesz, rproc_handle_rsc);
if (ret) {
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[RFCv3 01/11] remoteproc: Move enable_iommu to rproc_boot

2013-01-16 Thread sjur . brandeland
From: Sjur Brændeland 

Call enable_iommu from rproc_boot and disable_iommu from rproc_shutdown.
This make it simpler to keep enable/disable in balance.

Signed-off-by: Sjur Brændeland 
---
 drivers/remoteproc/remoteproc_core.c |   22 --
 1 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_core.c 
b/drivers/remoteproc/remoteproc_core.c
index dd3bfaf..ceca76c 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -141,6 +141,7 @@ static void rproc_disable_iommu(struct rproc *rproc)
 
iommu_detach_device(domain, dev);
iommu_domain_free(domain);
+   rproc->domain = NULL;
 
return;
 }
@@ -816,16 +817,6 @@ static int rproc_fw_boot(struct rproc *rproc, const struct 
firmware *fw)
 
dev_info(dev, "Booting fw image %s, size %zd\n", name, fw->size);
 
-   /*
-* if enabling an IOMMU isn't relevant for this rproc, this is
-* just a nop
-*/
-   ret = rproc_enable_iommu(rproc);
-   if (ret) {
-   dev_err(dev, "can't enable iommu: %d\n", ret);
-   return ret;
-   }
-
rproc->bootaddr = rproc_get_boot_addr(rproc, fw);
 
/* look for the resource table */
@@ -1045,12 +1036,23 @@ int rproc_boot(struct rproc *rproc)
goto downref_rproc;
}
 
+   /*
+* if enabling an IOMMU isn't relevant for this rproc, this is
+* just a nop
+*/
+   ret = rproc_enable_iommu(rproc);
+   if (ret) {
+   dev_err(dev, "can't enable iommu: %d\n", ret);
+   goto downref_rproc;
+   }
+
ret = rproc_fw_boot(rproc, firmware_p);
 
release_firmware(firmware_p);
 
 downref_rproc:
if (ret) {
+   rproc_disable_iommu(rproc);
module_put(dev->parent->driver->owner);
atomic_dec(&rproc->power);
}
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[RFCv3 05/11] remoteproc: Parse ELF file to find resource table address

2013-01-16 Thread sjur . brandeland
From: Sjur Brændeland 

Add function find_rsc_table_va to firmware ops. This function
returns the location of the resource table in shared memory
after loading.

Signed-off-by: Sjur Brændeland 
---
 drivers/remoteproc/remoteproc_elf_loader.c |   17 -
 drivers/remoteproc/remoteproc_internal.h   |   13 +
 2 files changed, 29 insertions(+), 1 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_elf_loader.c 
b/drivers/remoteproc/remoteproc_elf_loader.c
index 32a29b8..2ded994 100644
--- a/drivers/remoteproc/remoteproc_elf_loader.c
+++ b/drivers/remoteproc/remoteproc_elf_loader.c
@@ -312,9 +312,24 @@ rproc_elf_find_rsc_table(struct rproc *rproc, const struct 
firmware *fw,
return table;
 }
 
+struct resource_table *rproc_elf_get_rsctab_addr(struct rproc *rproc,
+const struct firmware *fw)
+{
+   struct elf32_shdr *shdr;
+
+   shdr = find_rsc_shdr(&rproc->dev, (struct elf32_hdr *)fw->data,
+   fw->size);
+   if (!shdr)
+   return NULL;
+
+   /* Find resource table in loaded segments */
+   return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size);
+}
+
 const struct rproc_fw_ops rproc_elf_fw_ops = {
.load = rproc_elf_load_segments,
.find_rsc_table = rproc_elf_find_rsc_table,
.sanity_check = rproc_elf_sanity_check,
-   .get_boot_addr = rproc_elf_get_boot_addr
+   .get_boot_addr = rproc_elf_get_boot_addr,
+   .get_rsctab_addr = rproc_elf_get_rsctab_addr
 };
diff --git a/drivers/remoteproc/remoteproc_internal.h 
b/drivers/remoteproc/remoteproc_internal.h
index 7bb6648..3a5cb7d 100644
--- a/drivers/remoteproc/remoteproc_internal.h
+++ b/drivers/remoteproc/remoteproc_internal.h
@@ -32,6 +32,7 @@ struct rproc;
  * expects to find it
  * @sanity_check:  sanity check the fw image
  * @get_boot_addr: get boot address to entry point specified in firmware
+ * @get_rsctab_addr:   get resouce table address as specified in firmware
  */
 struct rproc_fw_ops {
struct resource_table *(*find_rsc_table) (struct rproc *rproc,
@@ -40,6 +41,8 @@ struct rproc_fw_ops {
int (*load)(struct rproc *rproc, const struct firmware *fw);
int (*sanity_check)(struct rproc *rproc, const struct firmware *fw);
u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
+   struct resource_table *(*get_rsctab_addr)(struct rproc *rproc,
+   const struct firmware *fw);
 };
 
 /* from remoteproc_core.c */
@@ -102,6 +105,16 @@ struct resource_table *rproc_find_rsc_table(struct rproc 
*rproc,
return NULL;
 }
 
+static inline
+struct resource_table *rproc_get_rsctab_addr(struct rproc *rproc,
+   const struct firmware *fw)
+{
+   if (rproc->fw_ops->get_rsctab_addr)
+   return rproc->fw_ops->get_rsctab_addr(rproc, fw);
+
+   return NULL;
+}
+
 extern const struct rproc_fw_ops rproc_elf_fw_ops;
 
 #endif /* REMOTEPROC_INTERNAL_H */
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH resend] virtio_console: Free buffers from out-queue upon close

2012-11-07 Thread sjur . brandeland
From: Sjur Brændeland 

Free pending output buffers from the virtio out-queue when
host has acknowledged port_close. Also removed WARN_ON()
in remove_port_data().

Signed-off-by: Sjur Brændeland 
---

Resending, this time including a proper "Subject"...
--

Hi Amit,

Note: This patch is compile tested only. I have done the removal
of buffers from out-queue in handle_control_message()
when host has acked the close request. This seems less
racy than doing it in the release function.

I you want to change this further, feel free to take over from
here and refine this.

Thanks,
Sjur

 drivers/char/virtio_console.c |   14 ++
 1 files changed, 6 insertions(+), 8 deletions(-)

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 3fa036a..3a5831d 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -1522,15 +1522,9 @@ static void remove_port_data(struct port *port)
while ((buf = virtqueue_detach_unused_buf(port->in_vq)))
free_buf(buf, true);
 
-   /*
-* Check the out-queue for buffers. For VIRTIO_CONSOLE it is a
-* bug if this happens. But for RPROC_SERIAL the remote processor
-* may have crashed, leaving buffers hanging in the out-queue.
-*/
-   while ((buf = virtqueue_detach_unused_buf(port->out_vq))) {
-   WARN_ON_ONCE(!is_rproc_serial(port->portdev->vdev));
+   /* Free pending buffers from the out-queue. */
+   while ((buf = virtqueue_detach_unused_buf(port->out_vq)))
free_buf(buf, true);
-   }
 }
 
 /*
@@ -1655,6 +1649,10 @@ static void handle_control_message(struct ports_device 
*portdev,
 */
spin_lock_irq(&port->outvq_lock);
reclaim_consumed_buffers(port);
+
+   /* Free pending buffers from the out-queue. */
+   while ((buf = virtqueue_detach_unused_buf(port->out_vq)))
+   free_buf(buf, true);
spin_unlock_irq(&port->outvq_lock);
 
/*
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[no subject]

2012-11-07 Thread sjur . brandeland
>From 0ce16d6a0270daebd9972e94a834034a093228b0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Sjur=20Br=C3=A6ndeland?= 
Date: Wed, 7 Nov 2012 12:20:07 +0100
Subject: [PATCH] virtio_console:Free buffers from out-queue upon close
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Free pending output buffers from the virtio out-queue when
host has acknowledged port_close. Also removed WARN_ON()
in remove_port_data().

Signed-off-by: Sjur Brændeland 
---
Hi Amit,

Note: This patch is compile tested only. I have done the removal
of buffers from out-queue in handle_control_message()
when host has acked the close request. This seems less
racy than doing it in the release function.

I you want to change this further, feel free to take over from
here and refine this.

Thanks,
Sjur

 drivers/char/virtio_console.c |   14 ++
 1 files changed, 6 insertions(+), 8 deletions(-)

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 3fa036a..3a5831d 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -1522,15 +1522,9 @@ static void remove_port_data(struct port *port)
while ((buf = virtqueue_detach_unused_buf(port->in_vq)))
free_buf(buf, true);
 
-   /*
-* Check the out-queue for buffers. For VIRTIO_CONSOLE it is a
-* bug if this happens. But for RPROC_SERIAL the remote processor
-* may have crashed, leaving buffers hanging in the out-queue.
-*/
-   while ((buf = virtqueue_detach_unused_buf(port->out_vq))) {
-   WARN_ON_ONCE(!is_rproc_serial(port->portdev->vdev));
+   /* Free pending buffers from the out-queue. */
+   while ((buf = virtqueue_detach_unused_buf(port->out_vq)))
free_buf(buf, true);
-   }
 }
 
 /*
@@ -1655,6 +1649,10 @@ static void handle_control_message(struct ports_device 
*portdev,
 */
spin_lock_irq(&port->outvq_lock);
reclaim_consumed_buffers(port);
+
+   /* Free pending buffers from the out-queue. */
+   while ((buf = virtqueue_detach_unused_buf(port->out_vq)))
+   free_buf(buf, true);
spin_unlock_irq(&port->outvq_lock);
 
/*
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCHv7 1/4] virtio_console: Free buffer if splice fails

2012-10-15 Thread sjur . brandeland
From: Sjur Brændeland 

Free the allocated scatter list if send_pages fails in function
port_splice_write.

Signed-off-by: Sjur Brændeland 
---
 drivers/char/virtio_console.c |2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 8ab9c3d..c36b2f6 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -879,6 +879,8 @@ static ssize_t port_fops_splice_write(struct 
pipe_inode_info *pipe,
if (likely(ret > 0))
ret = send_pages(port, sgl.sg, sgl.n, sgl.len, true);
 
+   if (unlikely(ret <= 0))
+   kfree(sgl.sg);
return ret;
 }
 
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCHv7 4/4] virtio_console: Add support for remoteproc serial

2012-10-15 Thread sjur . brandeland
From: Sjur Brændeland 

Add a simple serial connection driver called
VIRTIO_ID_RPROC_SERIAL (11) for communicating with a
remote processor in an asymmetric multi-processing
configuration.

This implementation reuses the existing virtio_console
implementation, and adds support for DMA allocation
of data buffers and disables use of tty console and
the virtio control queue.

Signed-off-by: Sjur Brændeland 
---
 drivers/char/virtio_console.c |  201 -
 include/linux/virtio_ids.h|1 +
 2 files changed, 180 insertions(+), 22 deletions(-)

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 917cc830..eeb9b35 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -37,8 +37,12 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 #include "../tty/hvc/hvc_console.h"
 
+#define is_rproc_enabled IS_ENABLED(CONFIG_REMOTEPROC)
+
 /*
  * This is a global struct for storing common data for all the devices
  * this driver handles.
@@ -112,6 +116,15 @@ struct port_buffer {
/* offset in the buf from which to consume data */
size_t offset;
 
+   /* DMA address of buffer */
+   dma_addr_t dma;
+
+   /* Device we got DMA memory from */
+   struct device *dev;
+
+   /* List of pending dma buffers to free */
+   struct list_head list;
+
/* If sgpages == 0 then buf is used */
unsigned int sgpages;
 
@@ -331,6 +344,11 @@ static bool is_console_port(struct port *port)
return false;
 }
 
+static bool is_rproc_serial(const struct virtio_device *vdev)
+{
+   return is_rproc_enabled && vdev->id.device == VIRTIO_ID_RPROC_SERIAL;
+}
+
 static inline bool use_multiport(struct ports_device *portdev)
 {
/*
@@ -342,11 +360,13 @@ static inline bool use_multiport(struct ports_device 
*portdev)
return portdev->vdev->features[0] & (1 << VIRTIO_CONSOLE_F_MULTIPORT);
 }
 
-static void free_buf(struct port_buffer *buf)
+static DEFINE_SPINLOCK(dma_bufs_lock);
+static LIST_HEAD(pending_free_dma_bufs);
+
+static void free_buf(struct port_buffer *buf, bool can_sleep)
 {
unsigned int i;
 
-   kfree(buf->buf);
for (i = 0; i < buf->sgpages; i++) {
struct page *page = sg_page(&buf->sg[i]);
if (!page)
@@ -354,14 +374,58 @@ static void free_buf(struct port_buffer *buf)
put_page(page);
}
 
+   if (!buf->dev) {
+   kfree(buf->buf);
+   } else if (is_rproc_enabled) {
+   unsigned long flags;
+
+   /* dma_free_coherent requires interrupts to be enabled. */
+   if (!can_sleep) {
+   /* queue up dma-buffers to be freed later */
+   spin_lock_irqsave(&dma_bufs_lock, flags);
+   list_add_tail(&buf->list, &pending_free_dma_bufs);
+   spin_unlock_irqrestore(&dma_bufs_lock, flags);
+   return;
+   }
+   dma_free_coherent(buf->dev, buf->size, buf->buf, buf->dma);
+
+   /* Release device refcnt and allow it to be freed */
+   put_device(buf->dev);
+   }
+
kfree(buf);
 }
 
+static void reclaim_dma_bufs(void)
+{
+   unsigned long flags;
+   struct port_buffer *buf, *tmp;
+   LIST_HEAD(tmp_list);
+
+   if (list_empty(&pending_free_dma_bufs))
+   return;
+
+   /* Create a copy of the pending_free_dma_bufs while holding the lock */
+   spin_lock_irqsave(&dma_bufs_lock, flags);
+   list_cut_position(&tmp_list, &pending_free_dma_bufs,
+ pending_free_dma_bufs.prev);
+   spin_unlock_irqrestore(&dma_bufs_lock, flags);
+
+   /* Release the dma buffers, without irqs enabled */
+   list_for_each_entry_safe(buf, tmp, &tmp_list, list) {
+   list_del(&buf->list);
+   free_buf(buf, true);
+   }
+}
+
 static struct port_buffer *alloc_buf(struct virtqueue *vq, size_t buf_size,
 int pages)
 {
struct port_buffer *buf;
 
+   if (is_rproc_serial(vq->vdev))
+   reclaim_dma_bufs();
+
/*
 * Allocate buffer and the sg list. The sg list array is allocated
 * directly after the port_buffer struct.
@@ -373,11 +437,34 @@ static struct port_buffer *alloc_buf(struct virtqueue 
*vq, size_t buf_size,
 
buf->sgpages = pages;
if (pages > 0) {
+   buf->dev = NULL;
buf->buf = NULL;
return buf;
}
 
-   buf->buf = kmalloc(buf_size, GFP_KERNEL);
+   if (is_rproc_serial(vq->vdev)) {
+   /*
+* Allocate DMA memory from ancestor. When a virtio
+* device is created by remoteproc, the DMA memory is
+* associated with the grandparent device:
+* vdev => rproc => platform-dev.
+* The code here would

[PATCHv7 3/4] virtio_console: Merge struct buffer_token into struct port_buffer

2012-10-15 Thread sjur . brandeland
From: Sjur Brændeland 

Refactoring the splice functionality by unifying the approach for
sending scatter-lists and regular buffers. This simplifies
buffer handling and reduces code size. Splice will now allocate
a port_buffer and send_buf() and free_buf() can always be used
for any buffer.

Signed-off-by: Sjur Brændeland 
---
 drivers/char/virtio_console.c |  131 +
 1 files changed, 55 insertions(+), 76 deletions(-)

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 301d17e..917cc830 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -111,6 +111,12 @@ struct port_buffer {
size_t len;
/* offset in the buf from which to consume data */
size_t offset;
+
+   /* If sgpages == 0 then buf is used */
+   unsigned int sgpages;
+
+   /* sg is used if spages > 0. sg must be the last in is struct */
+   struct scatterlist sg[0];
 };
 
 /*
@@ -338,17 +344,39 @@ static inline bool use_multiport(struct ports_device 
*portdev)
 
 static void free_buf(struct port_buffer *buf)
 {
+   unsigned int i;
+
kfree(buf->buf);
+   for (i = 0; i < buf->sgpages; i++) {
+   struct page *page = sg_page(&buf->sg[i]);
+   if (!page)
+   break;
+   put_page(page);
+   }
+
kfree(buf);
 }
 
-static struct port_buffer *alloc_buf(size_t buf_size)
+static struct port_buffer *alloc_buf(struct virtqueue *vq, size_t buf_size,
+int pages)
 {
struct port_buffer *buf;
 
-   buf = kmalloc(sizeof(*buf), GFP_KERNEL);
+   /*
+* Allocate buffer and the sg list. The sg list array is allocated
+* directly after the port_buffer struct.
+*/
+   buf = kmalloc(sizeof(*buf) + sizeof(struct scatterlist) * pages,
+ GFP_KERNEL);
if (!buf)
goto fail;
+
+   buf->sgpages = pages;
+   if (pages > 0) {
+   buf->buf = NULL;
+   return buf;
+   }
+
buf->buf = kmalloc(buf_size, GFP_KERNEL);
if (!buf->buf)
goto free_buf;
@@ -476,52 +504,26 @@ static ssize_t send_control_msg(struct port *port, 
unsigned int event,
return 0;
 }
 
-struct buffer_token {
-   union {
-   void *buf;
-   struct scatterlist *sg;
-   } u;
-   /* If sgpages == 0 then buf is used, else sg is used */
-   unsigned int sgpages;
-};
-
-static void reclaim_sg_pages(struct scatterlist *sg, unsigned int nrpages)
-{
-   int i;
-   struct page *page;
-
-   for (i = 0; i < nrpages; i++) {
-   page = sg_page(&sg[i]);
-   if (!page)
-   break;
-   put_page(page);
-   }
-   kfree(sg);
-}
 
 /* Callers must take the port->outvq_lock */
 static void reclaim_consumed_buffers(struct port *port)
 {
-   struct buffer_token *tok;
+   struct port_buffer *buf;
unsigned int len;
 
if (!port->portdev) {
/* Device has been unplugged.  vqs are already gone. */
return;
}
-   while ((tok = virtqueue_get_buf(port->out_vq, &len))) {
-   if (tok->sgpages)
-   reclaim_sg_pages(tok->u.sg, tok->sgpages);
-   else
-   kfree(tok->u.buf);
-   kfree(tok);
+   while ((buf = virtqueue_get_buf(port->out_vq, &len))) {
+   free_buf(buf);
port->outvq_full = false;
}
 }
 
 static ssize_t __send_to_port(struct port *port, struct scatterlist *sg,
  int nents, size_t in_count,
- struct buffer_token *tok, bool nonblock)
+ void *data, bool nonblock)
 {
struct virtqueue *out_vq;
ssize_t ret;
@@ -534,7 +536,7 @@ static ssize_t __send_to_port(struct port *port, struct 
scatterlist *sg,
 
reclaim_consumed_buffers(port);
 
-   ret = virtqueue_add_buf(out_vq, sg, nents, 0, tok, GFP_ATOMIC);
+   ret = virtqueue_add_buf(out_vq, sg, nents, 0, data, GFP_ATOMIC);
 
/* Tell Host to go! */
virtqueue_kick(out_vq);
@@ -572,37 +574,6 @@ done:
return in_count;
 }
 
-static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count,
-   bool nonblock)
-{
-   struct scatterlist sg[1];
-   struct buffer_token *tok;
-
-   tok = kmalloc(sizeof(*tok), GFP_ATOMIC);
-   if (!tok)
-   return -ENOMEM;
-   tok->sgpages = 0;
-   tok->u.buf = in_buf;
-
-   sg_init_one(sg, in_buf, in_count);
-
-   return __send_to_port(port, sg, 1, in_count, tok, nonblock);
-}
-
-static ssize_t send_pages(struct port *port, struct scatterlist *sg, int nents,
- size_t in_count, bool nonblock)
-{
-   struct buffer_token *tok;
-
-   tok = kmalloc(si

[PATCHv7 2/4] virtio_console: Use kmalloc instead of kzalloc

2012-10-15 Thread sjur . brandeland
From: Sjur Brændeland 

Avoid the more cpu expensive kzalloc when allocating buffers.
Originally kzalloc was intended for isolating the guest from
the host by not sending random guest data to the host. But device
isolation is not yet in place so kzalloc is not really needed.

Signed-off-by: Sjur Brændeland 
---
 drivers/char/virtio_console.c |2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index c36b2f6..301d17e 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -349,7 +349,7 @@ static struct port_buffer *alloc_buf(size_t buf_size)
buf = kmalloc(sizeof(*buf), GFP_KERNEL);
if (!buf)
goto fail;
-   buf->buf = kzalloc(buf_size, GFP_KERNEL);
+   buf->buf = kmalloc(buf_size, GFP_KERNEL);
if (!buf->buf)
goto free_buf;
buf->len = 0;
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCHv7 0/4] virtio_console: Add rproc_serial driver

2012-10-15 Thread sjur . brandeland
From: Sjur Brændeland 

This patch-set introduces a new virtio type "rproc_serial" for communicating
with remote processors over shared memory. The driver depends on the
the remoteproc framework. As preparation for introducing "rproc_serial"
I've done a refactoring of the transmit buffer handling.

This patch-set is a rework of the patch-set from Sept 25th, hopefully all
review comments has been addressed.

The fist patch is a bugfix and migth be applicable for 3.7.

Thanks,
Sjur

Sjur Brændeland (4):
  virtio_console: Free buffer if splice fails
  virtio_console: Use kmalloc instead of kzalloc
  virtio_console: Merge struct buffer_token into struct port_buffer
  virtio_console: Add support for remoteproc serial

 drivers/char/virtio_console.c |  328 +
 include/linux/virtio_ids.h|1 +
 2 files changed, 234 insertions(+), 95 deletions(-)

-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 3/3] virtio_console: Don't initialize buffers to zero

2012-09-25 Thread sjur . brandeland
From: Sjur Brændeland 

Skip initializing the receive buffers.

Signed-off-by: Sjur Brændeland 
---
 drivers/char/virtio_console.c |1 -
 1 files changed, 0 insertions(+), 1 deletions(-)

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index faedd2c..e7d8787 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -1344,7 +1344,6 @@ static unsigned int fill_queue(struct virtqueue *vq, 
spinlock_t *lock)
if (!buf)
break;
 
-   memset(buf->buf, 0, PAGE_SIZE);
spin_lock_irq(lock);
ret = add_inbuf(vq, buf);
if (ret < 0) {
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCHv5 2/3] virtio_console: Add support for remoteproc serial

2012-09-25 Thread sjur . brandeland
From: Sjur Brændeland 

Add a simple serial connection driver called
VIRTIO_ID_RPROC_SERIAL (11) for communicating with a
remote processor in an asymmetric multi-processing
configuration.

This implementation reuses the existing virtio_console
implementation, and adds support for DMA allocation
of data buffers and disables use of tty console and
the virtio control queue.

Signed-off-by: Sjur Brændeland 
cc: Rusty Russell 
cc: Michael S. Tsirkin 
cc: Amit Shah 
cc: Ohad Ben-Cohen 
cc: Linus Walleij 
cc: Arnd Bergmann 
---
Changes since v4:
- New baseline
- Use name is_rproc_enabled
- Renamed list and spin-lock used for pending deletion of dma buffers
- Minor style fixes: indentation, removed brace


 drivers/char/virtio_console.c |  184 +
 include/linux/virtio_ids.h|1 +
 2 files changed, 170 insertions(+), 15 deletions(-)

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index f4f7b04..faedd2c 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -37,8 +37,12 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 #include "../tty/hvc/hvc_console.h"
 
+#define is_rproc_enabled IS_ENABLED(CONFIG_REMOTEPROC)
+
 /*
  * This is a global struct for storing common data for all the devices
  * this driver handles.
@@ -112,6 +116,15 @@ struct port_buffer {
/* offset in the buf from which to consume data */
size_t offset;
 
+   /* DMA address of buffer */
+   dma_addr_t dma;
+
+   /* Device we got DMA memory from */
+   struct device *dev;
+
+   /* List of pending dma buffers to free */
+   struct list_head list;
+
/* If sgpages == 0 then buf is used, else sg is used */
unsigned int sgpages;
 
@@ -330,6 +343,11 @@ static bool is_console_port(struct port *port)
return false;
 }
 
+static bool is_rproc_serial(const struct virtio_device *vdev)
+{
+   return is_rproc_enabled && vdev->id.device == VIRTIO_ID_RPROC_SERIAL;
+}
+
 static inline bool use_multiport(struct ports_device *portdev)
 {
/*
@@ -341,32 +359,84 @@ static inline bool use_multiport(struct ports_device 
*portdev)
return portdev->vdev->features[0] & (1 << VIRTIO_CONSOLE_F_MULTIPORT);
 }
 
+static DEFINE_SPINLOCK(dma_bufs_lock);
+static LIST_HEAD(pending_free_dma_bufs);
+
 static void free_buf(struct port_buffer *buf)
 {
int i;
+   unsigned long flags;
 
-   kfree(buf->buf);
+   if (!buf->dev)
+   kfree(buf->buf);
 
-   if (buf->sgpages)
+   if (buf->sgpages) {
for (i = 0; i < buf->sgpages; i++) {
struct page *page = sg_page(&buf->sg[i]);
if (!page)
break;
put_page(page);
}
+   return;
+   }
+
+   if (buf->dev && is_rproc_enabled) {
+
+   /* dma_free_coherent requires interrupts to be enabled. */
+   if (irqs_disabled()) {
+   /* queue up dma-buffers to be freed later */
+   spin_lock_irqsave(&dma_bufs_lock, flags);
+   list_add_tail(&buf->list, &pending_free_dma_bufs);
+   spin_unlock_irqrestore(&dma_bufs_lock, flags);
+   return;
+   }
+   dma_free_coherent(buf->dev, buf->size, buf->buf, buf->dma);
+
+   /* Release device refcnt and allow it to be freed */
+   might_sleep();
+   put_device(buf->dev);
+   }
 
kfree(buf);
 }
 
+static void reclaim_dma_bufs(void)
+{
+   unsigned long flags;
+   struct port_buffer *buf, *tmp;
+   LIST_HEAD(tmp_list);
+
+   WARN_ON(irqs_disabled());
+   if (list_empty(&pending_free_dma_bufs))
+   return;
+
+   BUG_ON(!is_rproc_enabled);
+
+   /* Create a copy of the pending_free_dma_bufs while holding the lock*/
+   spin_lock_irqsave(&dma_bufs_lock, flags);
+   list_cut_position(&tmp_list, &pending_free_dma_bufs,
+ pending_free_dma_bufs.prev);
+   spin_unlock_irqrestore(&dma_bufs_lock, flags);
+
+   /* Release the dma buffers, without irqs enabled */
+   list_for_each_entry_safe(buf, tmp, &tmp_list, list) {
+   list_del(&buf->list);
+   free_buf(buf);
+   }
+}
+
 static struct port_buffer *alloc_buf(struct virtqueue *vq, size_t buf_size,
 int nrbufs)
 {
struct port_buffer *buf;
size_t alloc_size;
 
+   if (is_rproc_serial(vq->vdev) && !irqs_disabled())
+   reclaim_dma_bufs();
+
/* Allocate buffer and the scatter list */
alloc_size = sizeof(*buf) + sizeof(struct scatterlist) * nrbufs;
-   buf = kmalloc(alloc_size, GFP_ATOMIC);
+   buf = kzalloc(alloc_size, GFP_ATOMIC);
if (!buf)
goto fail;
 
@@ -374,11 +444,30 @@ static struct port_bu

[PATCH 1/3] virtio_console:Merge struct buffer_token into struct port_buffer

2012-09-25 Thread sjur . brandeland
From: Sjur Brændeland 

This merge reduces code size by unifying the approach for
sending scatter-lists and regular buffers. Any type of
write operation (splice, write, put_chars) will now allocate
a port_buffer and send_buf() and free_buf() can always be used.

Signed-off-by: Sjur Brændeland 
cc: Rusty Russell 
cc: Michael S. Tsirkin 
cc: Amit Shah 
cc: Linus Walleij 
cc: Masami Hiramatsu 
---
 drivers/char/virtio_console.c |  141 ++---
 1 files changed, 62 insertions(+), 79 deletions(-)

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 8ab9c3d..f4f7b04 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -111,6 +111,11 @@ struct port_buffer {
size_t len;
/* offset in the buf from which to consume data */
size_t offset;
+
+   /* If sgpages == 0 then buf is used, else sg is used */
+   unsigned int sgpages;
+
+   struct scatterlist sg[1];
 };
 
 /*
@@ -338,23 +343,46 @@ static inline bool use_multiport(struct ports_device 
*portdev)
 
 static void free_buf(struct port_buffer *buf)
 {
+   int i;
+
kfree(buf->buf);
+
+   if (buf->sgpages)
+   for (i = 0; i < buf->sgpages; i++) {
+   struct page *page = sg_page(&buf->sg[i]);
+   if (!page)
+   break;
+   put_page(page);
+   }
+
kfree(buf);
 }
 
-static struct port_buffer *alloc_buf(size_t buf_size)
+static struct port_buffer *alloc_buf(struct virtqueue *vq, size_t buf_size,
+int nrbufs)
 {
struct port_buffer *buf;
+   size_t alloc_size;
 
-   buf = kmalloc(sizeof(*buf), GFP_KERNEL);
+   /* Allocate buffer and the scatter list */
+   alloc_size = sizeof(*buf) + sizeof(struct scatterlist) * nrbufs;
+   buf = kmalloc(alloc_size, GFP_ATOMIC);
if (!buf)
goto fail;
-   buf->buf = kzalloc(buf_size, GFP_KERNEL);
+
+   buf->sgpages = nrbufs;
+   if (nrbufs > 0)
+   return buf;
+
+   buf->buf = kmalloc(buf_size, GFP_ATOMIC);
if (!buf->buf)
goto free_buf;
buf->len = 0;
buf->offset = 0;
buf->size = buf_size;
+
+   /* Prepare scatter buffer for sending */
+   sg_init_one(buf->sg, buf->buf, buf_size);
return buf;
 
 free_buf:
@@ -476,52 +504,25 @@ static ssize_t send_control_msg(struct port *port, 
unsigned int event,
return 0;
 }
 
-struct buffer_token {
-   union {
-   void *buf;
-   struct scatterlist *sg;
-   } u;
-   /* If sgpages == 0 then buf is used, else sg is used */
-   unsigned int sgpages;
-};
-
-static void reclaim_sg_pages(struct scatterlist *sg, unsigned int nrpages)
-{
-   int i;
-   struct page *page;
-
-   for (i = 0; i < nrpages; i++) {
-   page = sg_page(&sg[i]);
-   if (!page)
-   break;
-   put_page(page);
-   }
-   kfree(sg);
-}
 
 /* Callers must take the port->outvq_lock */
 static void reclaim_consumed_buffers(struct port *port)
 {
-   struct buffer_token *tok;
+   struct port_buffer *buf;
unsigned int len;
 
if (!port->portdev) {
/* Device has been unplugged.  vqs are already gone. */
return;
}
-   while ((tok = virtqueue_get_buf(port->out_vq, &len))) {
-   if (tok->sgpages)
-   reclaim_sg_pages(tok->u.sg, tok->sgpages);
-   else
-   kfree(tok->u.buf);
-   kfree(tok);
+   while ((buf = virtqueue_get_buf(port->out_vq, &len))) {
+   free_buf(buf);
port->outvq_full = false;
}
 }
 
-static ssize_t __send_to_port(struct port *port, struct scatterlist *sg,
- int nents, size_t in_count,
- struct buffer_token *tok, bool nonblock)
+static ssize_t send_buf(struct port *port, struct port_buffer *buf, int nents,
+ size_t in_count, bool nonblock)
 {
struct virtqueue *out_vq;
ssize_t ret;
@@ -534,7 +535,7 @@ static ssize_t __send_to_port(struct port *port, struct 
scatterlist *sg,
 
reclaim_consumed_buffers(port);
 
-   ret = virtqueue_add_buf(out_vq, sg, nents, 0, tok, GFP_ATOMIC);
+   ret = virtqueue_add_buf(out_vq, buf->sg, nents, 0, buf, GFP_ATOMIC);
 
/* Tell Host to go! */
virtqueue_kick(out_vq);
@@ -559,8 +560,11 @@ static ssize_t __send_to_port(struct port *port, struct 
scatterlist *sg,
 * we need to kmalloc a GFP_ATOMIC buffer each time the
 * console driver writes something out.
 */
-   while (!virtqueue_get_buf(out_vq, &len))
+   for (buf = virtqueue_get_buf(out_vq, &len); !buf;
+buf = virtqueue_get_buf(out_vq, &len))
  

[PATCHv6 0/3] virtio_console: Add rproc_serial device

2012-09-25 Thread sjur . brandeland
From: Sjur Brændeland 

I thought rebasing rproc_serial to linux-next was going to be trivial.
But when starting the merge I realized that I had to refactor the
the patches from  Masami Hiramatsu. The splice support has the same issue
as I faced, with different type of buffers in the out_vq.
So I ended up refactoring the splice functionality. The code
size got smaller so hopefully this a step in the right direction.

This refactoring also make introduction of rproc_serial cleaner.

As requested I also added a patch for not initializing buffers.

I have tested the VIRTIO_CONSOLE device by looping large amount of data
through character device and tty, with lockdep and slub-debug on.
This looks stable for me. I've also done a simple test of splice.

Thanks,
Sjur

cc: Rusty Russell 
cc: Michael S. Tsirkin 
cc: Amit Shah 
cc: Linus Walleij 
cc: Masami Hiramatsu 


Sjur Brændeland (3):
  virtio_console:Merge struct buffer_token into struct port_buffer
  virtio_console: Add support for remoteproc serial
  virtio_console: Don't initialize buffers to zero

 drivers/char/virtio_console.c |  318 +
 include/linux/virtio_ids.h|1 +
 2 files changed, 228 insertions(+), 91 deletions(-)

-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCHv4] virtio_console: Add support for remoteproc serial

2012-09-24 Thread sjur . brandeland
From: Sjur Brændeland 

Add a simple serial connection driver called
VIRTIO_ID_RPROC_SERIAL (11) for communicating with a
remote processor in an asymmetric multi-processing
configuration.

This implementation reuses the existing virtio_console
implementation, and adds support for DMA allocation
of data buffers and disables use of tty console and
the virtio control queue.

Signed-off-by: Sjur Brændeland 
cc: Rusty Russell 
cc: Michael S. Tsirkin 
cc: Amit Shah 
cc: Ohad Ben-Cohen 
cc: Linus Walleij 
cc: Arnd Bergmann 
---

Changes since v3 are mostly related to freeing of dma-buffers:
- Change port_fops_write() to use struct port_buffer when allocating
  memory. This is done in order to store the dma-address of the
  allocated buffers, so the correct dma-address can be passed to
  dma_free_coherent().
- Added pending_free_list for port_buf. dma_free_coherent() requires
  the irqs to be enabled, so if irqs are disabled we queue the buffer
  on the pending_free_list and free it later when irqs are enabled.
- Remove #if around is_rproc_serial

Thanks,
Sjur

 drivers/char/virtio_console.c |  222 -
 include/linux/virtio_ids.h|1 +
 2 files changed, 199 insertions(+), 24 deletions(-)

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index cdf2f54..3af9a5d 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -35,8 +35,12 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 #include "../tty/hvc/hvc_console.h"
 
+#define rproc_enabled IS_ENABLED(CONFIG_REMOTEPROC)
+
 /*
  * This is a global struct for storing common data for all the devices
  * this driver handles.
@@ -109,6 +113,15 @@ struct port_buffer {
size_t len;
/* offset in the buf from which to consume data */
size_t offset;
+
+   /* DMA address of buffer */
+   dma_addr_t dma;
+
+   /* Device we got DMA memory from */
+   struct device *dev;
+
+   /* List of pending dma buffers to free */
+   struct list_head list;
 };
 
 /*
@@ -323,6 +336,11 @@ static bool is_console_port(struct port *port)
return false;
 }
 
+static bool is_rproc_serial(const struct virtio_device *vdev)
+{
+   return rproc_enabled && vdev->id.device == VIRTIO_ID_RPROC_SERIAL;
+}
+
 static inline bool use_multiport(struct ports_device *portdev)
 {
/*
@@ -334,20 +352,99 @@ static inline bool use_multiport(struct ports_device 
*portdev)
return portdev->vdev->features[0] & (1 << VIRTIO_CONSOLE_F_MULTIPORT);
 }
 
+static DEFINE_SPINLOCK(list_lock);
+static LIST_HEAD(pending_free_list);
+
 static void free_buf(struct port_buffer *buf)
 {
-   kfree(buf->buf);
+   unsigned long flags;
+
+   if (!buf->dev) {
+   kfree(buf->buf);
+   goto freebuf;
+   }
+
+   BUG_ON(!rproc_enabled);
+
+   /* dma_free_coherent requires interrupts to be enabled */
+   if (rproc_enabled && !irqs_disabled()) {
+   dma_free_coherent(buf->dev, buf->size, buf->buf, buf->dma);
+
+   /* Release device refcnt and allow it to be freed */
+   might_sleep();
+   put_device(buf->dev);
+   goto freebuf;
+   }
+
+   /* queue up dma-buffers to be freed later */
+   spin_lock_irqsave(&list_lock, flags);
+   list_add_tail(&buf->list, &pending_free_list);
+   spin_unlock_irqrestore(&list_lock, flags);
+   return;
+
+freebuf:
kfree(buf);
 }
 
-static struct port_buffer *alloc_buf(size_t buf_size)
+static void reclaim_dma_bufs(void)
+{
+   unsigned long flags;
+   struct port_buffer *buf, *tmp;
+   LIST_HEAD(tmp_list);
+
+   WARN_ON(irqs_disabled());
+   if (list_empty(&pending_free_list))
+   return;
+
+   BUG_ON(!rproc_enabled);
+
+   /* Create a copy of the pending_free_list while holding the lock*/
+   spin_lock_irqsave(&list_lock, flags);
+   list_cut_position(&tmp_list, &pending_free_list,
+ pending_free_list.prev);
+   spin_unlock_irqrestore(&list_lock, flags);
+
+   /* Release the dma buffers, without irqs enabled */
+   list_for_each_entry_safe(buf, tmp, &tmp_list, list) {
+   list_del(&buf->list);
+   free_buf(buf);
+   }
+}
+
+static struct port_buffer *alloc_buf(struct virtqueue *vq, size_t buf_size)
 {
struct port_buffer *buf;
 
+   if (is_rproc_serial(vq->vdev) && !irqs_disabled())
+   reclaim_dma_bufs();
+
buf = kmalloc(sizeof(*buf), GFP_KERNEL);
if (!buf)
goto fail;
-   buf->buf = kzalloc(buf_size, GFP_KERNEL);
+
+   if (is_rproc_serial(vq->vdev)) {
+   /*
+* Allocate DMA memory from ancestor. When a virtio
+* device is created by remoteproc, the DMA memory is
+* associated with the grandparent device:
+* vdev => rproc => platform-dev.
+   

[PATCHv3] virtio_console: Add support for remoteproc serial

2012-09-20 Thread sjur . brandeland
From: Sjur Brændeland 

Add a simple serial connection driver called
VIRTIO_ID_RPROC_SERIAL (11) for communicating with a
remote processor in an asymmetric multi-processing
configuration.

This implementation reuses the existing virtio_console
implementation, and adds support for DMA allocation
of data buffers and disables use of tty console and
the virtio control queue.

This enables use of the exising virtio_console code in
the remoteproc framework.

Signed-off-by: Sjur Brændeland 
cc: Rusty Russell 
cc: Michael S. Tsirkin 
cc: Amit Shah 
cc: Ohad Ben-Cohen 
cc: Linus Walleij 
cc: virtualizat...@lists.linux-foundation.org
---
Hi Amit,

Changes since v2: Fixes for Rustys review comments. The only
"unresolved" issue (unless I missed something) is the quirky
handling of finding device grandparent when doing dma_alloc.

[Rusty wrote:]
>OK, I'll let Amit comment on the console changes, but some minor style
>comments below.

Amit, any chance that you might find time to review this?

Note: This patch is based on v3.6 so this patch is will conflict
with "virtio: console: fix error handling in init() function".
Get back to me if you want me to rebase to another baseline.

Thanks,
Sjur

 drivers/char/virtio_console.c |  185 ++--
 include/linux/virtio_ids.h|1 +
 2 files changed, 158 insertions(+), 28 deletions(-)

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index cdf2f54..4f2f74e 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -35,6 +35,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 #include "../tty/hvc/hvc_console.h"
 
 /*
@@ -323,6 +325,55 @@ static bool is_console_port(struct port *port)
return false;
 }
 
+#if IS_ENABLED(CONFIG_REMOTEPROC)
+static bool is_rproc_serial(const struct virtio_device *vdev)
+{
+   return vdev->id.device == VIRTIO_ID_RPROC_SERIAL;
+}
+#else
+static bool is_rproc_serial(const struct virtio_device *vdev)
+{
+   return false;
+}
+#endif
+
+/* Allocate data buffer from DMA memory if requested */
+static void *alloc_databuf(struct virtio_device *vdev, size_t size, gfp_t flag)
+{
+   if (is_rproc_serial(vdev)) {
+   dma_addr_t dma_addr;
+   struct device *dev = &vdev->dev;
+   /*
+* Allocate DMA memory from ancestor. When a virtio
+* device is created by remoteproc, the DMA memory is
+* associated with the grandparent device:
+* vdev => rproc => platform-dev.
+* The code here would have been less quirky if
+* DMA_MEMORY_INCLUDES_CHILDREN had been supported
+* in dma-coherent.c
+*/
+   dev = dev->parent ? dev->parent : dev;
+   dev = dev->parent ? dev->parent : dev;
+   return dma_alloc_coherent(dev, size, &dma_addr, flag);
+   }
+   return kmalloc(size, flag);
+}
+
+static void free_databuf(struct virtio_device *vdev, size_t size, void *vaddr)
+{
+   if (is_rproc_serial(vdev)) {
+   struct device *dev = &vdev->dev;
+   dma_addr_t dma_addr;
+
+   dev = dev->parent ? dev->parent : dev;
+   dev = dev->parent ? dev->parent : dev;
+   dma_addr = virt_to_bus(vaddr);
+   dma_free_coherent(dev, size, vaddr, dma_addr);
+   return;
+   }
+   kfree(vaddr);
+}
+
 static inline bool use_multiport(struct ports_device *portdev)
 {
/*
@@ -334,22 +385,24 @@ static inline bool use_multiport(struct ports_device 
*portdev)
return portdev->vdev->features[0] & (1 << VIRTIO_CONSOLE_F_MULTIPORT);
 }
 
-static void free_buf(struct port_buffer *buf)
+static void free_buf(struct virtqueue *vq, struct port_buffer *buf,
+size_t buf_size)
 {
-   kfree(buf->buf);
+   free_databuf(vq->vdev, buf_size, buf->buf);
kfree(buf);
 }
 
-static struct port_buffer *alloc_buf(size_t buf_size)
+static struct port_buffer *alloc_buf(struct virtqueue *vq, size_t buf_size)
 {
struct port_buffer *buf;
 
buf = kmalloc(sizeof(*buf), GFP_KERNEL);
if (!buf)
goto fail;
-   buf->buf = kzalloc(buf_size, GFP_KERNEL);
+   buf->buf = alloc_databuf(vq->vdev, buf_size, GFP_KERNEL);
if (!buf->buf)
goto free_buf;
+   memset(buf->buf, 0, buf_size);
buf->len = 0;
buf->offset = 0;
buf->size = buf_size;
@@ -414,7 +467,7 @@ static void discard_port_data(struct port *port)
port->stats.bytes_discarded += buf->len - buf->offset;
if (add_inbuf(port->in_vq, buf) < 0) {
err++;
-   free_buf(buf);
+   free_buf(port->in_vq, buf, PAGE_SIZE);
}
port->inbuf = NULL;
buf = get_inbuf(port);
@@ -485,7 +538,7 @@ static void reclaim_consumed_buff

[PATCHv4] remoteproc: Add STE modem driver for remoteproc

2012-09-20 Thread sjur . brandeland
From: Sjur Brændeland 

Add support for the STE modem shared memory driver.
This driver hooks into the remoteproc framework
in order to manage configuration and the virtio
devices.

This driver adds custom firmware handlers, because
STE modem uses a custom firmware layout.

Signed-off-by: Sjur Brændeland 
cc: Linus Walleij 
cc: Alan Cox 
---
Changes from v3:
Added function setup to struct ste_modem_dev_ops.

 drivers/remoteproc/Kconfig   |   11 ++
 drivers/remoteproc/Makefile  |1 +
 drivers/remoteproc/ste_modem_rproc.c |  317 ++
 include/linux/ste_modem_shm.h|   56 ++
 4 files changed, 385 insertions(+), 0 deletions(-)
 create mode 100644 drivers/remoteproc/ste_modem_rproc.c
 create mode 100644 include/linux/ste_modem_shm.h

diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index f8d818a..a552566 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -27,4 +27,15 @@ config OMAP_REMOTEPROC
  It's safe to say n here if you're not interested in multimedia
  offloading or just want a bare minimum kernel.
 
+config STE_MODEM_RPROC
+   tristate "STE-Modem remoteproc support"
+   depends on EXPERIMENTAL
+   depends on HAS_DMA
+   select REMOTEPROC
+   default n
+   help
+ Say y or m here to support STE-Modem shared memory driver.
+ This can be either built-in or a loadable module.
+ If unsure say N.
+
 endmenu
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index 934ce6e..391b651 100644
--- a/drivers/remoteproc/Makefile
+++ b/drivers/remoteproc/Makefile
@@ -8,3 +8,4 @@ remoteproc-y+= remoteproc_debugfs.o
 remoteproc-y   += remoteproc_virtio.o
 remoteproc-y   += remoteproc_elf_loader.o
 obj-$(CONFIG_OMAP_REMOTEPROC)  += omap_remoteproc.o
+obj-$(CONFIG_STE_MODEM_RPROC)  += ste_modem_rproc.o
diff --git a/drivers/remoteproc/ste_modem_rproc.c 
b/drivers/remoteproc/ste_modem_rproc.c
new file mode 100644
index 000..176362f
--- /dev/null
+++ b/drivers/remoteproc/ste_modem_rproc.c
@@ -0,0 +1,317 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2012
+ * Author: Sjur Brændeland 
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include "remoteproc_internal.h"
+
+#define SPROC_FW_SIZE (50 * 4096)
+#define SPROC_MAX_TOC_ENTRIES 32
+#define SPROC_MAX_NOTIFY_ID 14
+#define SPROC_RESOURCE_NAME "rsc-table"
+#define SPROC_MODEM_NAME "ste-modem"
+#define SPROC_MODEM_FIRMWARE SPROC_MODEM_NAME "-fw.bin"
+
+#define sproc_dbg(sproc, fmt, ...) \
+   dev_dbg(&sproc->mdev->pdev.dev, fmt, ##__VA_ARGS__)
+#define sproc_err(sproc, fmt, ...) \
+   dev_err(&sproc->mdev->pdev.dev, fmt, ##__VA_ARGS__)
+
+/* STE-modem control structure */
+struct sproc {
+   struct rproc *rproc;
+   struct ste_modem_device *mdev;
+   int error;
+   void *fw_addr;
+   size_t fw_size;
+   dma_addr_t fw_dma_addr;
+};
+
+/* STE-Modem firmware entry */
+struct ste_toc_entry {
+   __le32 start;
+   __le32 size;
+   __le32 flags;
+   __le32 entry_point;
+   __le32 load_addr;
+   char name[12];
+};
+
+/*
+ * The Table Of Content is located at the start of the firmware image and
+ * at offset zero in the shared memory region. The resource table typically
+ * contains the initial boot image (boot strap) and other information elements
+ * such as remoteproc resource table. Each entry is identified by a unique
+ * name.
+ */
+struct ste_toc {
+   struct ste_toc_entry table[SPROC_MAX_TOC_ENTRIES];
+};
+
+/* Loads the firmware to shared memory. */
+static int sproc_load_segments(struct rproc *rproc, const struct firmware *fw)
+{
+   struct sproc *sproc = rproc->priv;
+
+   memcpy(sproc->fw_addr, fw->data, fw->size);
+   return 0;
+}
+
+/* Find the entry for resource table in the Table of Content */
+static struct ste_toc_entry *sproc_find_rsc_entry(const struct firmware *fw)
+{
+   int i;
+   struct ste_toc *toc;
+
+   if (!fw)
+   return NULL;
+   toc = (void *)fw->data;
+
+   /* Search the table for the resource table */
+   for (i = 0; i < SPROC_MAX_TOC_ENTRIES &&
+toc->table[i].start != 0x; i++) {
+
+   if (!strncmp(toc->table[i].name, SPROC_RESOURCE_NAME,
+sizeof(toc->table[i].name))) {
+   if (toc->table[i].start > fw->size)
+   return NULL;
+   return &toc->table[i];
+   }
+   }
+   return NULL;
+}
+
+/*
+ * Find the resource table inside the remote processor's firmware.
+ * This function will allocate area used for firmware image in the memory
+ * region shared with the modem.
+ */
+static struct resource_table *
+sproc_find_rsc_table(struct rproc *rproc, const struct fir

[PATCHv2] virtio_console: Add support for remoteproc serial

2012-09-19 Thread sjur . brandeland
From: Sjur Brændeland 

Add a simple serial connection driver called
VIRTIO_ID_RPROC_SERIAL (0xB) for communicating with a
remote processor in an asymmetric multi-processing
configuration.

This implementation reuses the existing virtio_console
implementation, and adds support for DMA allocation
of data buffers and disables use of tty console and
the virtio control queue.

This enables use of the exising virtio_console code in
the remoteproc framework.

Signed-off-by: Sjur Brændeland 
cc: Michael S. Tsirkin 
cc: Amit Shah 
cc: Ohad Ben-Cohen 
cc: Linus Walleij 
---

Hi Rusty,

Changes since v1:
o Use proper macros IS_ENABLED(CONFIG_REMOTEPROC)
o Fix bug at registration of rproc_serial driver
o Always allocate PAGE_SIZE buffers for rproc_serial,
  and limit write to port_fops_write to use PAGE_SIZE.

Regards,
Sjur

 drivers/char/virtio_console.c |  160 ++---
 include/linux/virtio_ids.h|1 +
 2 files changed, 134 insertions(+), 27 deletions(-)

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index cdf2f54..395522a 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -35,6 +35,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 #include "../tty/hvc/hvc_console.h"
 
 /*
@@ -323,6 +325,52 @@ static bool is_console_port(struct port *port)
return false;
 }
 
+#if IS_ENABLED(CONFIG_REMOTEPROC)
+static inline bool is_rproc_serial(struct virtio_device *vdev)
+{
+   return vdev->id.device == VIRTIO_ID_RPROC_SERIAL;
+}
+#else
+static inline bool is_rproc_serial(struct virtio_device *vdev)
+{
+   return false;
+}
+#endif
+
+/* Allocate data buffer from DMA memory if requested */
+static inline void *
+alloc_databuf(struct virtio_device *vdev, size_t size, gfp_t flag)
+{
+   if (is_rproc_serial(vdev)) {
+   dma_addr_t dma;
+   struct device *dev = &vdev->dev;
+   /*
+* Allocate DMA memory from ancestors. Finding the ancestor
+* is a bit quirky when DMA_MEMORY_INCLUDES_CHILDREN is not
+* implemented.
+*/
+   dev = dev->parent ? dev->parent : dev;
+   dev = dev->parent ? dev->parent : dev;
+   return dma_alloc_coherent(dev, size, &dma, flag);
+   }
+   return kmalloc(size, flag);
+}
+
+static inline void
+free_databuf(struct virtio_device *vdev, size_t size, void *cpu_addr)
+{
+
+   if (is_rproc_serial(vdev)) {
+   struct device *dev = &vdev->dev;
+   dma_addr_t dma_handle = virt_to_bus(cpu_addr);
+   dev = dev->parent ? dev->parent : dev;
+   dev = dev->parent ? dev->parent : dev;
+   dma_free_coherent(dev, size, cpu_addr, dma_handle);
+   return;
+   }
+   kfree(cpu_addr);
+}
+
 static inline bool use_multiport(struct ports_device *portdev)
 {
/*
@@ -334,20 +382,22 @@ static inline bool use_multiport(struct ports_device 
*portdev)
return portdev->vdev->features[0] & (1 << VIRTIO_CONSOLE_F_MULTIPORT);
 }
 
-static void free_buf(struct port_buffer *buf)
+static void
+free_buf(struct virtqueue *vq, struct port_buffer *buf, size_t buf_size)
 {
-   kfree(buf->buf);
+   free_databuf(vq->vdev, buf_size, buf->buf);
kfree(buf);
 }
 
-static struct port_buffer *alloc_buf(size_t buf_size)
+static struct port_buffer *alloc_buf(struct virtqueue *vq, size_t buf_size)
 {
struct port_buffer *buf;
 
buf = kmalloc(sizeof(*buf), GFP_KERNEL);
if (!buf)
goto fail;
-   buf->buf = kzalloc(buf_size, GFP_KERNEL);
+   buf->buf = alloc_databuf(vq->vdev, buf_size, GFP_KERNEL);
+   memset(buf->buf, 0, buf_size);
if (!buf->buf)
goto free_buf;
buf->len = 0;
@@ -414,7 +464,7 @@ static void discard_port_data(struct port *port)
port->stats.bytes_discarded += buf->len - buf->offset;
if (add_inbuf(port->in_vq, buf) < 0) {
err++;
-   free_buf(buf);
+   free_buf(port->in_vq, buf, PAGE_SIZE);
}
port->inbuf = NULL;
buf = get_inbuf(port);
@@ -485,7 +535,7 @@ static void reclaim_consumed_buffers(struct port *port)
return;
}
while ((buf = virtqueue_get_buf(port->out_vq, &len))) {
-   kfree(buf);
+   free_databuf(port->portdev->vdev, PAGE_SIZE, buf);
port->outvq_full = false;
}
 }
@@ -672,6 +722,8 @@ static ssize_t port_fops_write(struct file *filp, const 
char __user *ubuf,
char *buf;
ssize_t ret;
bool nonblock;
+   struct virtio_device *vdev;
+   size_t buf_size;
 
/* Userspace could be out to fool us */
if (!count)
@@ -694,9 +746,16 @@ static ssize_t port_fops_write(struct file *filp, const 
char __user *ubuf,
if (!port->g

[PATCHv3] remoteproc: Add STE modem driver for remoteproc

2012-09-19 Thread sjur . brandeland
From: Sjur Brændeland 

Add support for the STE modem shared memory driver.
This driver hooks into the remoteproc framework
in order to manage configuration and the virtio
devices.

This driver adds custom firmware handlers, because
STE modem uses a custom firmware layout.

Signed-off-by: Sjur Brændeland 
cc: Linus Walleij 
cc: Alan Cox 
---
Changes since v3:
o Make fw sanity checks more robust against maths overflow.
o Move and rename header file
o Remove Kconfig select statements
o Cleaned up include files.
o Allocate memory used for firmware image at driver probe.
o Use macro for table size in for-loop.
o Move declaration of dma memory out of this driver.
o Register as a standard platform_driver.

 drivers/remoteproc/Kconfig   |   11 ++
 drivers/remoteproc/Makefile  |1 +
 drivers/remoteproc/ste_modem_rproc.c |  316 ++
 include/linux/ste_modem_shm.h|   55 ++
 4 files changed, 383 insertions(+)
 create mode 100644 drivers/remoteproc/ste_modem_rproc.c
 create mode 100644 include/linux/ste_modem_shm.h

diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index f8d818a..a552566 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -27,4 +27,15 @@ config OMAP_REMOTEPROC
  It's safe to say n here if you're not interested in multimedia
  offloading or just want a bare minimum kernel.
 
+config STE_MODEM_RPROC
+   tristate "STE-Modem remoteproc support"
+   depends on EXPERIMENTAL
+   depends on HAS_DMA
+   select REMOTEPROC
+   default n
+   help
+ Say y or m here to support STE-Modem shared memory driver.
+ This can be either built-in or a loadable module.
+ If unsure say N.
+
 endmenu
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index 934ce6e..391b651 100644
--- a/drivers/remoteproc/Makefile
+++ b/drivers/remoteproc/Makefile
@@ -8,3 +8,4 @@ remoteproc-y+= remoteproc_debugfs.o
 remoteproc-y   += remoteproc_virtio.o
 remoteproc-y   += remoteproc_elf_loader.o
 obj-$(CONFIG_OMAP_REMOTEPROC)  += omap_remoteproc.o
+obj-$(CONFIG_STE_MODEM_RPROC)  += ste_modem_rproc.o
diff --git a/drivers/remoteproc/ste_modem_rproc.c 
b/drivers/remoteproc/ste_modem_rproc.c
new file mode 100644
index 000..0f5b6a8
--- /dev/null
+++ b/drivers/remoteproc/ste_modem_rproc.c
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2012
+ * Author: Sjur Brændeland 
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include "remoteproc_internal.h"
+
+#define SPROC_FW_SIZE (50 * 4096)
+#define SPROC_MAX_TOC_ENTRIES 32
+#define SPROC_MAX_NOTIFY_ID 14
+#define SPROC_RESOURCE_NAME "rsc-table"
+#define SPROC_MODEM_NAME "ste-modem"
+#define SPROC_MODEM_FIRMWARE SPROC_MODEM_NAME "-fw.bin"
+
+#define sproc_dbg(sproc, fmt, ...) \
+   dev_dbg(&sproc->mdev->pdev.dev, fmt, ##__VA_ARGS__)
+#define sproc_err(sproc, fmt, ...) \
+   dev_err(&sproc->mdev->pdev.dev, fmt, ##__VA_ARGS__)
+
+/* STE-modem control structure */
+struct sproc {
+   struct rproc *rproc;
+   struct ste_modem_device *mdev;
+   int error;
+   void *fw_addr;
+   size_t fw_size;
+   dma_addr_t fw_dma_addr;
+};
+
+/* STE-Modem firmware entry */
+struct ste_toc_entry {
+   __le32 start;
+   __le32 size;
+   __le32 flags;
+   __le32 entry_point;
+   __le32 load_addr;
+   char name[12];
+};
+
+/*
+ * The Table Of Content is located at the start of the firmware image and
+ * at offset zero in the shared memory region. The resource table typically
+ * contains the initial boot image (boot strap) and other information elements
+ * such as remoteproc resource table. Each entry is identified by a unique
+ * name.
+ */
+struct ste_toc {
+   struct ste_toc_entry table[SPROC_MAX_TOC_ENTRIES];
+};
+
+/* Loads the firmware to shared memory. */
+static int sproc_load_segments(struct rproc *rproc, const struct firmware *fw)
+{
+   struct sproc *sproc = rproc->priv;
+
+   memcpy(sproc->fw_addr, fw->data, fw->size);
+   return 0;
+}
+
+/* Find the entry for resource table in the Table of Content */
+static struct ste_toc_entry *sproc_find_rsc_entry(const struct firmware *fw)
+{
+   int i;
+   struct ste_toc *toc;
+
+   if (!fw)
+   return NULL;
+   toc = (void *)fw->data;
+
+   /* Search the table for the resource table */
+   for (i = 0; i < SPROC_MAX_TOC_ENTRIES &&
+toc->table[i].start != 0x; i++) {
+
+   if (!strncmp(toc->table[i].name, SPROC_RESOURCE_NAME,
+sizeof(toc->table[i].name))) {
+   if (toc->table[i].start > fw->size)
+   return NULL;
+   return &toc->table[i];
+   }
+   }
+   return NULL;

[PATCHv3] remtoteproc: Export notification id range

2012-09-18 Thread sjur . brandeland
From: Sjur Brændeland 

Some of the rproc drivers needs to know the range
of the notification IDs used for notifying the device.
Export a variable in struct rproc holding the
largest allocated notification id.

Signed-off-by: Sjur Brændeland 
---

Changes since v2:
Use idr_for_each() instead of nested loops.

 drivers/remoteproc/remoteproc_core.c |   15 +++
 include/linux/remoteproc.h   |2 ++
 2 files changed, 17 insertions(+), 0 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_core.c 
b/drivers/remoteproc/remoteproc_core.c
index d5c2dbf..b368797 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -215,6 +215,9 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i)
return ret;
}
 
+   /* Store largest notifyid */
+   rproc->max_notifyid = max(rproc->max_notifyid, notifyid);
+
dev_dbg(dev, "vring%d: va %p dma %x size %x idr %d\n", i, va,
dma, size, notifyid);
 
@@ -256,13 +259,25 @@ rproc_parse_vring(struct rproc_vdev *rvdev, struct 
fw_rsc_vdev *rsc, int i)
return 0;
 }
 
+static int rproc_max_notifyid(int id, void *p, void *data)
+{
+   int *maxid = data;
+   *maxid = max(*maxid, id);
+   return 0;
+}
+
 void rproc_free_vring(struct rproc_vring *rvring)
 {
+   int maxid = 0;
int size = PAGE_ALIGN(vring_size(rvring->len, rvring->align));
struct rproc *rproc = rvring->rvdev->rproc;
 
dma_free_coherent(rproc->dev.parent, size, rvring->va, rvring->dma);
idr_remove(&rproc->notifyids, rvring->notifyid);
+
+   /* Find the largest remaining ID*/
+   idr_for_each(&rproc->notifyids, rproc_max_notifyid, &maxid);
+   rproc->max_notifyid = maxid;
 }
 
 /**
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index 131b539..c37e359 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -382,6 +382,7 @@ enum rproc_state {
  * @bootaddr: address of first instruction to boot rproc with (optional)
  * @rvdevs: list of remote virtio devices
  * @notifyids: idr for dynamically assigning rproc-wide unique notify ids
+ * @max_notifyid: Largest allocated notify id.
  * @index: index of this rproc device
  */
 struct rproc {
@@ -406,6 +407,7 @@ struct rproc {
struct list_head rvdevs;
struct idr notifyids;
int index;
+   int max_notifyid;
 };
 
 /* we currently support only two vrings per rvdev */
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[RFCv2] remoteproc: Add STE modem driver for remoteproc

2012-09-18 Thread sjur . brandeland
From: Sjur Brændeland 

Add support for the STE modem shared memory driver.
This driver hooks into the remoteproc framework
in order to manage configuration and the virtio
devices.

This driver adds custom firmware handlers, because
STE modem uses a custom firmware layout.

Signed-off-by: Sjur Brændeland 
---

Changes since v1:
o Implement a driver for struct ste_modem_device. This driver is using
  the platform-device bus. New include file is added in 
  include/linux/modem_shm/.

o Changed from a stand-alone API for "kick" and control to a device.
  Now we use a device and driver with ops structure. Hopefully this
  cleans up the interface.

o Removed the character device for user-space control of remoteproc.
  I will have to come back to this later.

 drivers/remoteproc/Kconfig   |   12 +
 drivers/remoteproc/Makefile  |1 +
 drivers/remoteproc/ste_modem_rproc.c |  408 ++
 include/linux/modem_shm/ste_modem.h  |   71 ++
 4 files changed, 492 insertions(+)
 create mode 100644 drivers/remoteproc/ste_modem_rproc.c
 create mode 100644 include/linux/modem_shm/ste_modem.h

diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index e7d440c..14b70fd 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -28,4 +28,16 @@ config OMAP_REMOTEPROC
  It's safe to say n here if you're not interested in multimedia
  offloading or just want a bare minimum kernel.
 
+config STE_MODEM_RPROC
+   tristate "STE-Modem remoteproc support"
+   select REMOTEPROC
+   select VIRTIO_CONSOLE
+   depends on EXPERIMENTAL
+   depends on HAS_DMA
+   default n
+   help
+ Say y or m here to support STE-Modem shared memory driver.
+ This can be either built-in or a loadable module.
+ If unsure say N.
+
 endmenu
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index 934ce6e..391b651 100644
--- a/drivers/remoteproc/Makefile
+++ b/drivers/remoteproc/Makefile
@@ -8,3 +8,4 @@ remoteproc-y+= remoteproc_debugfs.o
 remoteproc-y   += remoteproc_virtio.o
 remoteproc-y   += remoteproc_elf_loader.o
 obj-$(CONFIG_OMAP_REMOTEPROC)  += omap_remoteproc.o
+obj-$(CONFIG_STE_MODEM_RPROC)  += ste_modem_rproc.o
diff --git a/drivers/remoteproc/ste_modem_rproc.c 
b/drivers/remoteproc/ste_modem_rproc.c
new file mode 100644
index 000..9290bf3
--- /dev/null
+++ b/drivers/remoteproc/ste_modem_rproc.c
@@ -0,0 +1,408 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2012
+ * Author: Sjur Brændeland 
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "remoteproc_internal.h"
+
+#define SPROC_MAX_NOTIFY_ID 14
+#define SPROC_RESOURCE_NAME "rsc-table"
+#define SPROC_MODEM_NAME "ste-modem"
+#define SPROC_MODEM_FIRMWARE SPROC_MODEM_NAME "-fw.bin"
+
+#define sproc_dbg(sproc, fmt, ...) \
+   dev_dbg(&sproc->mdev->pdev.dev, fmt, ##__VA_ARGS__)
+#define sproc_err(sproc, fmt, ...) \
+   dev_err(&sproc->mdev->pdev.dev, fmt, ##__VA_ARGS__)
+
+/* STE-modem control structure */
+struct sproc {
+   struct rproc *rproc;
+   struct ste_modem_device *mdev;
+   int error;
+   void *fw_addr;
+   size_t fw_size;
+   dma_addr_t fw_dma_addr;
+};
+
+/* STE-Modem firmware entry */
+struct ste_toc_entry {
+   __le32 start;
+   __le32 size;
+   __le32 flags;
+   __le32 entry_point;
+   __le32 load_addr;
+   char name[12];
+};
+
+/*
+ * The Table Of Content is located at the start of the firmware image and
+ * at offset zero in the shared memory region. The resource table typically
+ * contains the initial boot image (boot strap) and other information elements
+ * such as remoteproc resource table. Each entry is identified by a unique
+ * name.
+ */
+struct ste_toc {
+   struct ste_toc_entry table[32];
+};
+
+/*
+ * Loads the firmware to shared memory.
+ * The memory area to load fw into must be pre-allocated before
+ * this function is called (because remoteproc has already allocated
+ * device memory when this function is called)
+ */
+static int sproc_load_segments(struct rproc *rproc, const struct firmware *fw)
+{
+   struct sproc *sproc = rproc->priv;
+
+   /* Convert to pages before checking if we have enough space for fw*/
+   if (sproc->fw_addr == NULL ||
+   PFN_DOWN(sproc->fw_size) < PFN_DOWN(fw->size)) {
+   sproc_err(sproc, "Not sufficient space for firmware\n");
+   return -EINVAL;
+   }
+
+   memcpy(sproc->fw_addr, fw->data, fw->size);
+   return 0;
+}
+
+/* Find the entry for resource table in the Table of Content */
+static struct ste_toc_entry *sproc_find_rsc_entry(const struct firmware *fw)
+{
+   int i;
+   struct ste_toc *toc;
+   int entries = ARRAY_SIZE(toc->table);
+
+   if (!fw)
+   return

[PATCHv2] remoteproc: Export notification id range

2012-09-13 Thread sjur . brandeland
From: Sjur Brændeland 

Some of the rproc drivers needs to know the range
of the notification IDs used for notifying the device.
Export a variable in struct rproc holding the
largest allocated notification id.

Signed-off-by: Sjur Brændeland 
---
cc: Linus Walleij 
cc: linux-kernel@vger.kernel.org

>For completeness, I think we probably also want to update max_notifyid
>when a notifyid is removed (i.e. on rproc_free_vring).

I've added a scan through the vrings to find the new max_notifyid after
removing a notifyid.

Thanks,
Sjur

 drivers/remoteproc/remoteproc_core.c |   13 +
 include/linux/remoteproc.h   |2 ++
 2 files changed, 15 insertions(+)

diff --git a/drivers/remoteproc/remoteproc_core.c 
b/drivers/remoteproc/remoteproc_core.c
index d5c2dbf..741242d 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -215,6 +215,9 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i)
return ret;
}
 
+   /* Store largest notifyid */
+   rproc->max_notifyid = max(rproc->max_notifyid, notifyid);
+
dev_dbg(dev, "vring%d: va %p dma %x size %x idr %d\n", i, va,
dma, size, notifyid);
 
@@ -258,11 +261,21 @@ rproc_parse_vring(struct rproc_vdev *rvdev, struct 
fw_rsc_vdev *rsc, int i)
 
 void rproc_free_vring(struct rproc_vring *rvring)
 {
+   int i, maxid = 0;
+   struct rproc_vdev *rvdev, *tmp;
int size = PAGE_ALIGN(vring_size(rvring->len, rvring->align));
struct rproc *rproc = rvring->rvdev->rproc;
 
dma_free_coherent(rproc->dev.parent, size, rvring->va, rvring->dma);
idr_remove(&rproc->notifyids, rvring->notifyid);
+
+   /* Iterate over the new set of rings to find the largest id */
+   rvring->notifyid = 0;
+   list_for_each_entry_safe(rvdev, tmp, &rproc->rvdevs, node)
+   for (i = 0; i < RVDEV_NUM_VRINGS; i++)
+   maxid = max(maxid, rvdev->vring[i].notifyid);
+
+   rproc->max_notifyid = maxid;
 }
 
 /**
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index 131b539..c37e359 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -382,6 +382,7 @@ enum rproc_state {
  * @bootaddr: address of first instruction to boot rproc with (optional)
  * @rvdevs: list of remote virtio devices
  * @notifyids: idr for dynamically assigning rproc-wide unique notify ids
+ * @max_notifyid: Largest allocated notify id.
  * @index: index of this rproc device
  */
 struct rproc {
@@ -406,6 +407,7 @@ struct rproc {
struct list_head rvdevs;
struct idr notifyids;
int index;
+   int max_notifyid;
 };
 
 /* we currently support only two vrings per rvdev */
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH] virtio_console: Add support for remoteproc serial

2012-09-13 Thread sjur . brandeland
From: Sjur Brændeland 

Add a virtio remoteproc serial driver: VIRTIO_ID_RPROC_SERIAL (0xB)
for communicating with a remote processor in an asymmetric
multi-processing configuration.

The virtio remoteproc serial driver reuses the existing virtio_console
implementation, and adds support for DMA allocation of data buffers
but disables support for tty console, mutiple ports, and the control queue.

Signed-off-by: Sjur Brændeland 
---
cc: Rusty Russell 
cc: Michael S. Tsirkin 
cc: Amit Shah 
cc: Ohad Ben-Cohen 
cc: Linus Walleij 
cc: virtualizat...@lists.linux-foundation.org
cc: linux-kernel@vger.kernel.org

>Just one thing, should it depend on CONFIG_REMOTEPROC?  And have
>OMAP_REMOTEPROC depend on CONFIG_HAS_DMA (if it doesn't already).

I have changed to use CONFIG_REMOTEPROC_MODULE now. I'll send a patch
to Ohad adding an explicit dependency to HAS_DMA for remoteproc.

>PS.  I've reserved 11 for you in the latest virtio spec draft.
Ok, I'll look into updating the spec.

Thanks,
Sjur


 drivers/char/virtio_console.c |  137 +
 include/linux/virtio_ids.h|1 +
 2 files changed, 112 insertions(+), 26 deletions(-)

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index cdf2f54..7c697ca 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -35,6 +35,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 #include "../tty/hvc/hvc_console.h"
 
 /*
@@ -323,6 +325,52 @@ static bool is_console_port(struct port *port)
return false;
 }
 
+#ifdef CONFIG_REMOTEPROC_MODULE
+static inline bool is_rproc_serial(struct virtio_device *vdev)
+{
+   return vdev->id.device == VIRTIO_ID_RPROC_SERIAL;
+}
+#else
+static inline bool is_rproc_serial(struct virtio_device *vdev)
+{
+   return false;
+}
+#endif
+
+/* Allocate data buffer from DMA memory if requested */
+static inline void *
+alloc_databuf(struct virtio_device *vdev, size_t size, gfp_t flag)
+{
+   if (is_rproc_serial(vdev)) {
+   dma_addr_t dma;
+   struct device *dev = &vdev->dev;
+   /*
+* Allocate DMA memory from ancestors. Finding the ancestor
+* is a bit quirky when DMA_MEMORY_INCLUDES_CHILDREN is not
+* implemented.
+*/
+   dev = dev->parent ? dev->parent : dev;
+   dev = dev->parent ? dev->parent : dev;
+   return dma_alloc_coherent(dev, size, &dma, flag);
+   }
+   return kmalloc(size, flag);
+}
+
+static inline void
+free_databuf(struct virtio_device *vdev, size_t size, void *cpu_addr)
+{
+
+   if (is_rproc_serial(vdev)) {
+   struct device *dev = &vdev->dev;
+   dma_addr_t dma_handle = virt_to_bus(cpu_addr);
+   dev = dev->parent ? dev->parent : dev;
+   dev = dev->parent ? dev->parent : dev;
+   dma_free_coherent(dev, size, cpu_addr, dma_handle);
+   return;
+   }
+   kfree(cpu_addr);
+}
+
 static inline bool use_multiport(struct ports_device *portdev)
 {
/*
@@ -334,20 +382,22 @@ static inline bool use_multiport(struct ports_device 
*portdev)
return portdev->vdev->features[0] & (1 << VIRTIO_CONSOLE_F_MULTIPORT);
 }
 
-static void free_buf(struct port_buffer *buf)
+static void
+free_buf(struct virtqueue *vq, struct port_buffer *buf, size_t buf_size)
 {
-   kfree(buf->buf);
+   free_databuf(vq->vdev, buf_size, buf->buf);
kfree(buf);
 }
 
-static struct port_buffer *alloc_buf(size_t buf_size)
+static struct port_buffer *alloc_buf(struct virtqueue *vq, size_t buf_size)
 {
struct port_buffer *buf;
 
buf = kmalloc(sizeof(*buf), GFP_KERNEL);
if (!buf)
goto fail;
-   buf->buf = kzalloc(buf_size, GFP_KERNEL);
+   buf->buf = alloc_databuf(vq->vdev, buf_size, GFP_KERNEL);
+   memset(buf->buf, 0, buf_size);
if (!buf->buf)
goto free_buf;
buf->len = 0;
@@ -414,7 +464,7 @@ static void discard_port_data(struct port *port)
port->stats.bytes_discarded += buf->len - buf->offset;
if (add_inbuf(port->in_vq, buf) < 0) {
err++;
-   free_buf(buf);
+   free_buf(port->in_vq, buf, PAGE_SIZE);
}
port->inbuf = NULL;
buf = get_inbuf(port);
@@ -485,7 +535,7 @@ static void reclaim_consumed_buffers(struct port *port)
return;
}
while ((buf = virtqueue_get_buf(port->out_vq, &len))) {
-   kfree(buf);
+   free_databuf(port->portdev->vdev, len, buf);
port->outvq_full = false;
}
 }
@@ -672,6 +722,7 @@ static ssize_t port_fops_write(struct file *filp, const 
char __user *ubuf,
char *buf;
ssize_t ret;
bool nonblock;
+   struct virtio_device *vdev;
 
/* Userspace could be out to fool u

[PATCH] remoteproc: Add dependency to HAS_DMA

2012-09-13 Thread sjur . brandeland
From: Sjur Brændeland 

Remoteproc relies on HAS_DMA, add this dependency in Kconfig.

Signed-off-by: Sjur Brændeland 
---
cc: linux-kernel@vger.kernel.org
cc: Rusty Russell 

 drivers/remoteproc/Kconfig |1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index f8d818a..e7d440c 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -4,6 +4,7 @@ menu "Remoteproc drivers (EXPERIMENTAL)"
 config REMOTEPROC
tristate
depends on EXPERIMENTAL
+   depends on HAS_DMA
select FW_CONFIG
 
 config OMAP_REMOTEPROC
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[RFCv3] virtio_console: Add support for virtio remoteproc serial

2012-09-10 Thread sjur . brandeland
From: Sjur Brændeland 

Add a virtio remoteproc serial driver: VIRTIO_ID_RPROC_SERIAL (0xB)
for communicating with a remote processor in an asymmetric
multi-processing configuration.

The virtio remoteproc serial driver reuses the existing virtio_console
implementation, and adds support for DMA allocation of data buffers
but disables support for tty console, mutiple ports, and the control queue.

Signed-off-by: Sjur Brændeland 
cc: Rusty Russell 
cc: Michael S. Tsirkin 
cc: Amit Shah 
cc: Ohad Ben-Cohen 
cc: Linus Walleij 
cc: virtualizat...@lists.linux-foundation.org
cc: linux-kernel@vger.kernel.org
---

Hi Rusty,

...

>Sorry for the back and forth, I've been pondering MST's points.
>If we make a new dma-multiport device (eg. ID 11), how ugly is the code?

I don't think it's too bad.
It's a few more code lines - as I have added a new virtio_driver
definition and feature table. The rest is just replacing the check
on feature bits with driver type. I no longer need to check on
feature bits in the probe function, as the match on device type is
done automatically by the driver framework.

I actually like this new approach better.
It solves the issues Michael has pointed out, and we don't have to
think through side effects of weired combination of feature bits.

>It would be a virtio console with DMA buffers and no console, just the
>multiport stuff.  This would have no impact on the current spec for
>virtio console.

Yes, and this way it will also be easier to explain what this new
feature does.

Regards,
Sjur

 drivers/char/virtio_console.c |  133 +
 include/linux/virtio_ids.h|1 +
 2 files changed, 109 insertions(+), 25 deletions(-)

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index cdf2f54..08593aa 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -35,6 +35,7 @@
 #include 
 #include 
 #include 
+#include 
 #include "../tty/hvc/hvc_console.h"
 
 /*
@@ -323,6 +324,52 @@ static bool is_console_port(struct port *port)
return false;
 }
 
+#ifdef CONFIG_HAS_DMA
+static inline bool is_rproc_serial(struct virtio_device *vdev)
+{
+   return vdev->id.device == VIRTIO_ID_RPROC_SERIAL;
+}
+#else
+static inline bool is_rproc_serial(struct virtio_device *vdev)
+{
+   return false;
+}
+#endif
+
+/* Allocate data buffer from DMA memory if requested */
+static inline void *
+alloc_databuf(struct virtio_device *vdev, size_t size, gfp_t flag)
+{
+   if (is_rproc_serial(vdev)) {
+   dma_addr_t dma;
+   struct device *dev = &vdev->dev;
+   /*
+* Allocate DMA memory from ancestors. Finding the ancestor
+* is a bit quirky when DMA_MEMORY_INCLUDES_CHILDREN is not
+* implemented.
+*/
+   dev = dev->parent ? dev->parent : dev;
+   dev = dev->parent ? dev->parent : dev;
+   return dma_alloc_coherent(dev, size, &dma, flag);
+   }
+   return kzalloc(size, flag);
+}
+
+static inline void
+free_databuf(struct virtio_device *vdev, size_t size, void *cpu_addr)
+{
+
+   if (is_rproc_serial(vdev)) {
+   struct device *dev = &vdev->dev;
+   dma_addr_t dma_handle = virt_to_bus(cpu_addr);
+   dev = dev->parent ? dev->parent : dev;
+   dev = dev->parent ? dev->parent : dev;
+   dma_free_coherent(dev, size, cpu_addr, dma_handle);
+   return;
+   }
+   kfree(cpu_addr);
+}
+
 static inline bool use_multiport(struct ports_device *portdev)
 {
/*
@@ -334,20 +381,21 @@ static inline bool use_multiport(struct ports_device 
*portdev)
return portdev->vdev->features[0] & (1 << VIRTIO_CONSOLE_F_MULTIPORT);
 }
 
-static void free_buf(struct port_buffer *buf)
+static void
+free_buf(struct virtqueue *vq, struct port_buffer *buf, size_t buf_size)
 {
-   kfree(buf->buf);
+   free_databuf(vq->vdev, buf_size, buf->buf);
kfree(buf);
 }
 
-static struct port_buffer *alloc_buf(size_t buf_size)
+static struct port_buffer *alloc_buf(struct virtqueue *vq, size_t buf_size)
 {
struct port_buffer *buf;
 
buf = kmalloc(sizeof(*buf), GFP_KERNEL);
if (!buf)
goto fail;
-   buf->buf = kzalloc(buf_size, GFP_KERNEL);
+   buf->buf = alloc_databuf(vq->vdev, buf_size, GFP_KERNEL);
if (!buf->buf)
goto free_buf;
buf->len = 0;
@@ -414,7 +462,7 @@ static void discard_port_data(struct port *port)
port->stats.bytes_discarded += buf->len - buf->offset;
if (add_inbuf(port->in_vq, buf) < 0) {
err++;
-   free_buf(buf);
+   free_buf(port->in_vq, buf, PAGE_SIZE);
}
port->inbuf = NULL;
buf = get_inbuf(port);
@@ -485,7 +533,7 @@ static void reclaim_consumed_buffers(struct port *port)

[RFCv2 2/2] virtio_console: Add feature to disable console port

2012-09-06 Thread sjur . brandeland
From: Sjur Brændeland 

Add the feature VIRTIO_CONSOLE_F_NO_HVC. With this bit set
only port-devices are created. The console port and
port control virtio-queues are not created.

The console port is not suited for communicating
to a remote processor because of it's blocking behavior.
But the port-device supports efficient non-blocking IO
to a remote processor.

Signed-off-by: Sjur Brændeland 
cc: Rusty Russell 
cc: Michael S. Tsirkin 
cc: Amit Shah 
cc: Ohad Ben-Cohen 
cc: Linus Walleij 
cc: virtualizat...@lists.linux-foundation.org
cc: linux-kernel@vger.kernel.org
---
 drivers/char/virtio_console.c  |6 +-
 include/linux/virtio_console.h |1 +
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 469c05f..7408c00 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -1244,10 +1244,13 @@ static int add_port(struct ports_device *portdev, u32 
id)
goto free_device;
}
 
+   /* Don't initialize the port_console if F_NO_HVC is set*/
+   if (virtio_has_feature(port->portdev->vdev, VIRTIO_CONSOLE_F_NO_HVC))
+   port->host_connected = true;
/*
 * If we're not using multiport support, this has to be a console port
 */
-   if (!use_multiport(port->portdev)) {
+   else if (!use_multiport(port->portdev)) {
err = init_port_console(port);
if (err)
goto free_inbufs;
@@ -1896,6 +1899,7 @@ static unsigned int features[] = {
 #if VIRTIO_CONSOLE_HAS_DMA
VIRTIO_CONSOLE_F_DMA_MEM,
 #endif
+   VIRTIO_CONSOLE_F_NO_HVC,
 
 };
 
diff --git a/include/linux/virtio_console.h b/include/linux/virtio_console.h
index b27f7fa..a7c8974 100644
--- a/include/linux/virtio_console.h
+++ b/include/linux/virtio_console.h
@@ -39,6 +39,7 @@
 #define VIRTIO_CONSOLE_F_SIZE  0   /* Does host provide console size? */
 #define VIRTIO_CONSOLE_F_MULTIPORT 1   /* Does host provide multiple ports? */
 #define VIRTIO_CONSOLE_F_DMA_MEM 2 /* Use DMA memory in vrings */
+#define VIRTIO_CONSOLE_F_NO_HVC 3  /* Disable use of HVC */
 
 #define VIRTIO_CONSOLE_BAD_ID  (~(u32)0)
 
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[RFCv2 1/2] virtio_console: Add support for DMA memory allocation

2012-09-06 Thread sjur . brandeland
From: Sjur Brændeland 

Add feature VIRTIO_CONSOLE_F_DMA_MEM. If the architecture has
DMA support and this feature bit is set, the virtio data buffers
will be allocated from DMA memory. If the device requests
the feature VIRTIO_CONSOLE_F_DMA_MEM, but the architecture
don't support DMA the driver's probe function will fail.

This is needed for using virtio_console from the remoteproc
framework.

Signed-off-by: Sjur Brændeland 
cc: Rusty Russell 
cc: Michael S. Tsirkin 
cc: Amit Shah 
cc: Ohad Ben-Cohen 
cc: Linus Walleij 
cc: virtualizat...@lists.linux-foundation.org
cc: linux-kernel@vger.kernel.org
---
 drivers/char/virtio_console.c  |   91 +---
 include/linux/virtio_console.h |1 +
 2 files changed, 77 insertions(+), 15 deletions(-)

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index cdf2f54..469c05f 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -35,8 +35,15 @@
 #include 
 #include 
 #include 
+#include 
 #include "../tty/hvc/hvc_console.h"
 
+#ifdef CONFIG_HAS_DMA
+#define VIRTIO_CONSOLE_HAS_DMA (1)
+#else
+#define VIRTIO_CONSOLE_HAS_DMA (0)
+#endif
+
 /*
  * This is a global struct for storing common data for all the devices
  * this driver handles.
@@ -334,20 +341,56 @@ static inline bool use_multiport(struct ports_device 
*portdev)
return portdev->vdev->features[0] & (1 << VIRTIO_CONSOLE_F_MULTIPORT);
 }
 
-static void free_buf(struct port_buffer *buf)
+/* Allocate data buffer from DMA memory if requested */
+static inline void *
+alloc_databuf(struct virtio_device *vdev, size_t size, gfp_t flag)
+{
+   if (VIRTIO_CONSOLE_HAS_DMA &&
+   virtio_has_feature(vdev, VIRTIO_CONSOLE_F_DMA_MEM)) {
+   struct device *dev = &vdev->dev;
+   dma_addr_t dma;
+   /*
+* Allocate DMA memory from ancestors. Finding the ancestor
+* is a bit quirky when DMA_MEMORY_INCLUDES_CHILDREN is not
+* implemented.
+*/
+   dev = dev->parent ? dev->parent : dev;
+   dev = dev->parent ? dev->parent : dev;
+   return dma_alloc_coherent(dev, size, &dma, flag);
+   }
+   return kzalloc(size, flag);
+}
+
+static inline void
+free_databuf(struct virtio_device *vdev, size_t size, void *cpu_addr)
+{
+   if (VIRTIO_CONSOLE_HAS_DMA &&
+   virtio_has_feature(vdev, VIRTIO_CONSOLE_F_DMA_MEM)) {
+   struct device *dev = &vdev->dev;
+   dma_addr_t dma = virt_to_bus(cpu_addr);
+   dev = dev->parent ? dev->parent : dev;
+   dev = dev->parent ? dev->parent : dev;
+   dma_free_coherent(dev, size, cpu_addr, dma);
+   return;
+   }
+   kfree(cpu_addr);
+}
+
+static void
+free_buf(struct virtqueue *vq, struct port_buffer *buf, size_t buf_size)
 {
-   kfree(buf->buf);
+   free_databuf(vq->vdev, buf_size, buf);
kfree(buf);
 }
 
-static struct port_buffer *alloc_buf(size_t buf_size)
+static struct port_buffer *alloc_buf(struct virtqueue *vq, size_t buf_size)
 {
struct port_buffer *buf;
 
buf = kmalloc(sizeof(*buf), GFP_KERNEL);
if (!buf)
goto fail;
-   buf->buf = kzalloc(buf_size, GFP_KERNEL);
+   buf->buf = alloc_databuf(vq->vdev, buf_size, GFP_KERNEL);
if (!buf->buf)
goto free_buf;
buf->len = 0;
@@ -414,7 +457,7 @@ static void discard_port_data(struct port *port)
port->stats.bytes_discarded += buf->len - buf->offset;
if (add_inbuf(port->in_vq, buf) < 0) {
err++;
-   free_buf(buf);
+   free_buf(port->in_vq, buf, PAGE_SIZE);
}
port->inbuf = NULL;
buf = get_inbuf(port);
@@ -485,7 +528,7 @@ static void reclaim_consumed_buffers(struct port *port)
return;
}
while ((buf = virtqueue_get_buf(port->out_vq, &len))) {
-   kfree(buf);
+   free_databuf(port->portdev->vdev, len, buf);
port->outvq_full = false;
}
 }
@@ -672,6 +715,7 @@ static ssize_t port_fops_write(struct file *filp, const 
char __user *ubuf,
char *buf;
ssize_t ret;
bool nonblock;
+   struct virtio_device *vdev;
 
/* Userspace could be out to fool us */
if (!count)
@@ -694,9 +738,10 @@ static ssize_t port_fops_write(struct file *filp, const 
char __user *ubuf,
if (!port->guest_connected)
return -ENODEV;
 
+   vdev = port->portdev->vdev;
count = min((size_t)(32 * 1024), count);
 
-   buf = kmalloc(count, GFP_KERNEL);
+   buf = alloc_databuf(vdev, count, GFP_KERNEL);
if (!buf)
return -ENOMEM;
 
@@ -720,7 +765,8 @@ static ssize_t port_fops_write(struct file *filp, const 
char __user *ubuf,
goto out;
 
 free_buf:

[PATCHv2] virtio: Don't access device data after unregistration.

2012-09-06 Thread sjur . brandeland
From: Sjur Brændeland 

Fix panic in virtio.c when CONFIG_DEBUG_SLAB is set.
device_unregister() drops reference to device so put_device()
could invoke release callback. In this case the release
callback will free the device. Make sure we don't access
device after unregister by fetching the device index
before calling unregister.

Signed-off-by: Sjur Brændeland 
cc: Guzman Lugo, Fernadndo 
cc: Michael S. Tsirkin 
cc: Rusty Russell 
cc: Ohad Ben-Cohen 
cc: virtualizat...@lists.linux-foundation.org
cc: linux-kernel@vger.kernel.org
---
 drivers/virtio/virtio.c |9 -
 1 files changed, 8 insertions(+), 1 deletions(-)

diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c
index c3b3f7f..faee112 100644
--- a/drivers/virtio/virtio.c
+++ b/drivers/virtio/virtio.c
@@ -225,8 +225,15 @@ EXPORT_SYMBOL_GPL(register_virtio_device);
 
 void unregister_virtio_device(struct virtio_device *dev)
 {
+   /*
+* device_unregister() drops reference to device so put_device could
+* invoke release callback. In case that callback will free the device,
+* make sure we don't access device after this call.
+*/
+
+   int index = dev->index;
device_unregister(&dev->dev);
-   ida_simple_remove(&virtio_index_ida, dev->index);
+   ida_simple_remove(&virtio_index_ida, index);
 }
 EXPORT_SYMBOL_GPL(unregister_virtio_device);
 
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[RFC 2/2] virtio_console: Add feature to disable console port

2012-09-03 Thread sjur . brandeland
From: Sjur Brændeland 

Add the feature VIRTIO_CONSOLE_F_NO_HVC. With this bit set
only port-devices are created. The console port and
port control virtio-queues are not created.

The console port is not suited for communicating
to a remote processor because of it's blocking behavior.
But the port-device supports efficient non-blocking IO
to a remote processor.

Signed-off-by: Sjur Brændeland 
cc: Rusty Russell 
cc: Michael S. Tsirkin 
cc: virtualizat...@lists.linux-foundation.org
cc: Ohad Ben-Cohen 
cc: Linus Walleij 
---
 drivers/char/virtio_console.c  |5 -
 include/linux/virtio_console.h |1 +
 2 files changed, 5 insertions(+), 1 deletions(-)

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 6bfbd09..81546e9 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -1246,7 +1246,9 @@ static int add_port(struct ports_device *portdev, u32 id)
/*
 * If we're not using multiport support, this has to be a console port
 */
-   if (!use_multiport(port->portdev)) {
+   if (virtio_has_feature(port->portdev->vdev, VIRTIO_CONSOLE_F_NO_HVC))
+   port->host_connected = true;
+   else if (!use_multiport(port->portdev)) {
err = init_port_console(port);
if (err)
goto free_inbufs;
@@ -1882,6 +1884,7 @@ static unsigned int features[] = {
VIRTIO_CONSOLE_F_SIZE,
VIRTIO_CONSOLE_F_MULTIPORT,
VIRTIO_CONSOLE_F_DMA_MEM,
+   VIRTIO_CONSOLE_F_NO_HVC,
 };
 
 #ifdef CONFIG_PM
diff --git a/include/linux/virtio_console.h b/include/linux/virtio_console.h
index b27f7fa..a7c8974 100644
--- a/include/linux/virtio_console.h
+++ b/include/linux/virtio_console.h
@@ -39,6 +39,7 @@
 #define VIRTIO_CONSOLE_F_SIZE  0   /* Does host provide console size? */
 #define VIRTIO_CONSOLE_F_MULTIPORT 1   /* Does host provide multiple ports? */
 #define VIRTIO_CONSOLE_F_DMA_MEM 2 /* Use DMA memory in vrings */
+#define VIRTIO_CONSOLE_F_NO_HVC 3  /* Disable use of HVC */
 
 #define VIRTIO_CONSOLE_BAD_ID  (~(u32)0)
 
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[RFC 1/2] virtio_console: Add support for DMA memory allocation

2012-09-03 Thread sjur . brandeland
From: Sjur Brændeland 

Add feature VIRTIO_CONSOLE_F_DMA_MEM. If the architecture has
DMA support and this feature bit is set, the virtio data buffers
will be allocated from DMA memory.

This is needed for using virtio_console from the remoteproc
framework.

Signed-off-by: Sjur Brændeland 
cc: Rusty Russell 
cc: Michael S. Tsirkin 
cc: Ohad Ben-Cohen 
cc: Linus Walleij 
cc: virtualizat...@lists.linux-foundation.org
---
 drivers/char/virtio_console.c  |   76 
 include/linux/virtio_console.h |1 +
 2 files changed, 62 insertions(+), 15 deletions(-)

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index cdf2f54..6bfbd09 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -35,6 +35,7 @@
 #include 
 #include 
 #include 
+#include 
 #include "../tty/hvc/hvc_console.h"
 
 /*
@@ -334,20 +335,60 @@ static inline bool use_multiport(struct ports_device 
*portdev)
return portdev->vdev->features[0] & (1 << VIRTIO_CONSOLE_F_MULTIPORT);
 }
 
-static void free_buf(struct port_buffer *buf)
+/* Allcoate data buffer from DMA memory if requested */
+static inline void *
+alloc_databuf(struct virtio_device *vdev, size_t size, dma_addr_t *dma_handle,
+  gfp_t flag)
 {
-   kfree(buf->buf);
+#ifdef CONFIG_HAS_DMA
+   if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_DMA_MEM)) {
+   struct device *dev = &vdev->dev;
+   /*
+* Allocate DMA memory from ancestors. Finding the ancestor
+* is a bit quirky when DMA_MEMORY_INCLUDES_CHILDREN is not
+* implemented.
+*/
+   dev = dev->parent ? dev->parent : dev;
+   dev = dev->parent ? dev->parent : dev;
+   return dma_alloc_coherent(dev, size, dma_handle, flag);
+   }
+#endif
+   return kzalloc(size, flag);
+}
+
+static inline void
+free_databuf(struct virtio_device *vdev, size_t size, void *cpu_addr)
+{
+#ifdef CONFIG_HAS_DMA
+   dma_addr_t dma_handle = virt_to_bus(cpu_addr);
+   if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_DMA_MEM)) {
+   struct device *dev = &vdev->dev;
+
+   dev = dev->parent ? dev->parent : dev;
+   dev = dev->parent ? dev->parent : dev;
+   dma_free_coherent(dev, size, cpu_addr, dma_handle);
+   return;
+   }
+#endif
+   kfree(cpu_addr);
+}
+
+static void
+free_buf(struct virtqueue *vq, struct port_buffer *buf, size_t buf_size)
+{
+   free_databuf(vq->vdev, buf_size, buf);
kfree(buf);
 }
 
-static struct port_buffer *alloc_buf(size_t buf_size)
+static struct port_buffer *alloc_buf(struct virtqueue *vq, size_t buf_size)
 {
struct port_buffer *buf;
+   dma_addr_t dma;
 
buf = kmalloc(sizeof(*buf), GFP_KERNEL);
if (!buf)
goto fail;
-   buf->buf = kzalloc(buf_size, GFP_KERNEL);
+   buf->buf = alloc_databuf(vq->vdev, buf_size, &dma, GFP_KERNEL);
if (!buf->buf)
goto free_buf;
buf->len = 0;
@@ -414,7 +455,7 @@ static void discard_port_data(struct port *port)
port->stats.bytes_discarded += buf->len - buf->offset;
if (add_inbuf(port->in_vq, buf) < 0) {
err++;
-   free_buf(buf);
+   free_buf(port->in_vq, buf, PAGE_SIZE);
}
port->inbuf = NULL;
buf = get_inbuf(port);
@@ -485,7 +526,7 @@ static void reclaim_consumed_buffers(struct port *port)
return;
}
while ((buf = virtqueue_get_buf(port->out_vq, &len))) {
-   kfree(buf);
+   free_databuf(port->portdev->vdev, len, buf);
port->outvq_full = false;
}
 }
@@ -672,6 +713,8 @@ static ssize_t port_fops_write(struct file *filp, const 
char __user *ubuf,
char *buf;
ssize_t ret;
bool nonblock;
+   struct virtio_device *vdev;
+   dma_addr_t dma;
 
/* Userspace could be out to fool us */
if (!count)
@@ -694,9 +737,10 @@ static ssize_t port_fops_write(struct file *filp, const 
char __user *ubuf,
if (!port->guest_connected)
return -ENODEV;
 
+   vdev = port->portdev->vdev;
count = min((size_t)(32 * 1024), count);
 
-   buf = kmalloc(count, GFP_KERNEL);
+   buf = alloc_databuf(vdev, count, &dma, GFP_KERNEL);
if (!buf)
return -ENOMEM;
 
@@ -720,7 +764,8 @@ static ssize_t port_fops_write(struct file *filp, const 
char __user *ubuf,
goto out;
 
 free_buf:
-   kfree(buf);
+   free_databuf(vdev, count, buf);
+
 out:
return ret;
 }
@@ -1102,7 +1147,7 @@ static unsigned int fill_queue(struct virtqueue *vq, 
spinlock_t *lock)
 
nr_added_bufs = 0;
do {
-   buf = alloc_buf(PAGE_SIZE);
+   buf = alloc_buf(vq, PAGE_SIZE);
  

[PATCH] virtio: Don't access device data after unregistration.

2012-09-03 Thread sjur . brandeland
From: Sjur Brændeland 

Fix panic in virtio.c when CONFIG_DEBUG_SLAB is set.
Use device_del() and put_device() instead of
device_unregister(), and access device data before
calling put_device().


Signed-off-by: Sjur Brændeland 
cc: Guzman Lugo, Fernadndo 
cc: Michael S. Tsirkin 
cc: virtualizat...@lists.linux-foundation.org
cc: Ohad Ben-Cohen 
---
 drivers/virtio/virtio.c |3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c
index c3b3f7f..71eacd1 100644
--- a/drivers/virtio/virtio.c
+++ b/drivers/virtio/virtio.c
@@ -225,8 +225,9 @@ EXPORT_SYMBOL_GPL(register_virtio_device);
 
 void unregister_virtio_device(struct virtio_device *dev)
 {
-   device_unregister(&dev->dev);
+   device_del(&dev->dev);
ida_simple_remove(&virtio_index_ida, dev->index);
+   put_device(&dev->dev);
 }
 EXPORT_SYMBOL_GPL(unregister_virtio_device);
 
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[RFC 3/3] remoteproc: Add STE modem driver for remoteproc

2012-09-03 Thread sjur . brandeland
From: Sjur Brændeland 

Add support for the STE modem shared memory driver.
This driver hooks into the remoteproc framework
in order to manage configuration and the virtio
devices.

When this platform device driver is probed, a
character device is added. This character device
is used to start and stop the modem.
When the character device is opened the driver
adds a rproc device instance. This causes firmware
to be requested and loaded into shared memory
and modem to be started. Closing the device
will stop the modem. Errors are reported to user-
space as POLLERR from the poll() function.

This driver adds custom firmware handlers, because
STE modem uses a custom firmware layout.

The memory region shared with the modem is declared
as a platform device resource.

This driver users modem_ctrl.h and modem_kick.h for
power control and interrupt handling.

Signed-off-by: Sjur Brændeland 
cc: Linus Walleij 
cc: Arun Murthy 
---
 drivers/remoteproc/Kconfig   |   14 +
 drivers/remoteproc/Makefile  |1 +
 drivers/remoteproc/ste_modem_rproc.c |  691 ++
 3 files changed, 706 insertions(+), 0 deletions(-)
 create mode 100644 drivers/remoteproc/ste_modem_rproc.c

diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index f8d818a..05d036e 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -27,4 +27,18 @@ config OMAP_REMOTEPROC
  It's safe to say n here if you're not interested in multimedia
  offloading or just want a bare minimum kernel.
 
+config STE_MODEM_RPROC
+   tristate "STE-Modem remoteproc support"
+   select REMOTEPROC
+   select VIRTIO_CONSOLE
+   select VIRTIO_CAIF
+   depends on EXPERIMENTAL
+   depends on MODEM_KICK
+   depends on MODEM_CTRL
+   default n
+   help
+ Say y or m here to support STE-Modem shared memory driver.
+ This can be either built-in or a loadable module.
+ If unsure say N.
+
 endmenu
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index 934ce6e..391b651 100644
--- a/drivers/remoteproc/Makefile
+++ b/drivers/remoteproc/Makefile
@@ -8,3 +8,4 @@ remoteproc-y+= remoteproc_debugfs.o
 remoteproc-y   += remoteproc_virtio.o
 remoteproc-y   += remoteproc_elf_loader.o
 obj-$(CONFIG_OMAP_REMOTEPROC)  += omap_remoteproc.o
+obj-$(CONFIG_STE_MODEM_RPROC)  += ste_modem_rproc.o
diff --git a/drivers/remoteproc/ste_modem_rproc.c 
b/drivers/remoteproc/ste_modem_rproc.c
new file mode 100644
index 000..53cad9d
--- /dev/null
+++ b/drivers/remoteproc/ste_modem_rproc.c
@@ -0,0 +1,691 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2012
+ * Author: Sjur Brændeland 
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "remoteproc_internal.h"
+#include 
+#include 
+
+#define SPROC_MAX_NOTIFY_ID 14
+#define SPROC_RESOURCE_NAME "rsc-table"
+#define SPROC_NAME "ste-modem"
+#define SPROC_MODEM_FIRMWARE SPROC_NAME "-fw.bin"
+#define SPROC_MEM_AREA "modem_shm"
+
+/* struct sproc - ST-Ericsson modem control structure
+ *
+ * @rproc: Remoteproc handle.
+ * @error: Error reported by underlying "kick" driver.
+ * @fw_addr: Location of firmware in memory shared with modem.
+ * @chardev: Character device used to remoteproc for STE modem.
+ * @kick: Handle to the kick interface.
+ * @ctrl: Handle to the modem control interface.
+ * @wq: Wait queue used by poll to wait for errors reported.
+ */
+struct sproc {
+   struct rproc *rproc;
+   struct platform_device *pdev;
+   int error;
+   void *fw_addr;
+   size_t fw_size;
+   dma_addr_t fw_dma_addr;
+   struct device chardev;
+   struct modem_kick *kick;
+   struct modem_ctrl *ctrl;
+   wait_queue_head_t wq;
+};
+
+/* struct ste_toc_entry - Table of content entry
+ *
+ * @start: Offset to the image data.
+ * @size:  Size of the images in bytes.
+ * @flags: Use 0 if no flags are in use.
+ * @entry_point: Modem internal information.
+ * @load_addr: Modem internal information.
+ * @name: Name of image.
+ */
+struct ste_toc_entry {
+   __le32 start;
+   __le32 size;
+   __le32 flags;
+   __le32 entry_point;
+   __le32 load_addr;
+   char name[12];
+};
+
+/* struct ste_toc - Table of content
+ * @table: Table of toc entries.
+ *
+ * The Table Of Content is located at the start of the firmware image and
+ * at offset zero in the shared memory region. The resource table typically
+ * contains the initial boot image (boot strap) and other information elements
+ * such as remoteproc resource table. Each entry is identified by a unique
+ */
+struct ste_toc {
+   struct ste_toc

[RFC 1/3] include/linux: Add API for kicking modem

2012-09-03 Thread sjur . brandeland
From: Sjur Brændeland 

Add an API for subscribing to and generating kicks
(interrupts) to the modem.

Signed-off-by: Sjur Brændeland 
cc: Linus Walleij 
cc: Arun Murthy 
---
 include/linux/modem_kick.h |  126 
 1 files changed, 126 insertions(+), 0 deletions(-)
 create mode 100644 include/linux/modem_kick.h

diff --git a/include/linux/modem_kick.h b/include/linux/modem_kick.h
new file mode 100644
index 000..e650144
--- /dev/null
+++ b/include/linux/modem_kick.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2012
+ * Author: Sjur Brendeland / sjur.brandel...@stericsson.com
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef __INC_MODEM_KICK_H
+#define __INC_MODEM_KICK_H
+#include 
+
+struct modem_kick;
+
+/**
+ * modem_kick_get- Get the handle for the modem kick API.
+ * @modem_name:Name of the modem.
+ *
+ * Get a handle to the modem kick API. This API provides
+ * functionality to generate "kicks" between modem and host.
+ *
+ * This function may block.
+ * Returns zero on success, and negative upon error.
+ */
+struct modem_kick *modem_kick_get(const char *modem_name);
+
+/**
+ * modem_kick_put - Release the instance of the modem kick API.
+ * @kick:  The API handle return by @modem_get.
+ *
+ * Releases the modem kick API.
+ *
+ * This function may block.
+ * Returns zero on success, and negative upon error.
+ */
+void modem_kick_put(struct modem_kick *kick);
+
+/**
+ * modem_kick_subscribe - Subscribe for notifications from the modem.
+ * @kick:  The API handle return by @modem_get.
+ * @notifyid:  The identification of the notification.
+ * @notify_cb: Callback function to be called when modem kicks.
+ * @data: Client data to be provided in the notification callback function.
+ *
+ * Installs a callback function for a specific notification ID.
+ *
+ * Precondition: modem_kick_alloc_notifyid() must have declared
+ * the @notifyid in the rx_mask.
+ * This function may block.
+ * Returns zero on success, and negative upon error.
+ *
+ * Callback context:
+ * The callback might be called from a IRQ context.
+ * The callback function is not allowed to block
+ * or spend much CPU time in the callback.
+ */
+int modem_kick_subscribe(struct modem_kick *kick, int notifyid,
+ void (*notify_cb)(int notifyid, void *data),
+ void *data);
+
+/**
+ * modem_kick_alloc_notifyid - Allocate the usage of notification IDs.
+ *
+ * @kick:  The API handle return by @modem_get.
+ * @rx_mask:   Bit-mask defining the notification IDs that can be
+ * subscribed to by modem_kick_subscribe().
+ * @tx_mask:   Bit-mask defining the notification IDs that can be
+ * set by modem_kick_set_notifyid()
+ *
+ * This function allocates the Notification IDs to be used for
+ * RX and TX direction towards the modem.
+ *
+ * This function may block.
+ *
+ * Returns zero on success, and negative upon error.
+ *
+ */
+int modem_kick_alloc_notifyid(struct modem_kick *kick,
+ u32 rx_mask, u32 tx_mask);
+
+/**
+ * modem_kick_register_errhandler - Register an error handler.
+ * @kick:  The API handle return by @modem_get.
+ * @userdata:  User data will be used as argument to the errorhandler
+ * @errhandler: Error handler called from driver upon severe errors
+ * that requires reset of the remote device.
+ *
+ * This routine installs an error callback function to be used if
+ * non recoverable errors are detected in the driver implementing
+ * the kick API.
+ * Callback context:
+ * The callback function is not allowed to block
+ * or spend much CPU time in the callback.
+ */
+void modem_kick_register_errhandler(struct modem_kick *kick, void *userdata,
+   void (*errhandler)(void *userdata,
+  int errno));
+
+/**
+ * modem_kick_reset() - Reset the driver
+ * @kick:  The API handle return by @modem_get.
+ *
+ * Reset the Kick Driver. This shall reset state back to
+ * initial state, and should only be used when the modem has
+ * been reset.
+ *
+ * This function may block.
+ * Returns zero on success, and negative upon error.
+ */
+int modem_kick_reset(struct modem_kick *kick);
+
+/**
+ * modem_kick_trigger() - Kick the modem.
+ * @kick:  The API handle return by @modem_get.
+ * @notifyid:  The notification ID for this kick.
+ *
+ * This function is used to trigger a notification to the modem.
+ *
+ * This function is non-blocking, and can be called from a IRQ context.
+ * Returns zero on success, and negative upon error.
+ *
+ * Precondition: modem_kick_alloc_notifyid() must have declared
+ * the @notifyid in the tx_mask.
+ */
+int modem_kick_trigger(struct modem_kick *kick, int notifyid);
+
+#endif /*INC_MODEM_KICK_H*/
-- 
1.7.5.4

--
To unsubscribe from this list:

[RFC 2/3] include/linux: Add header file for modem power control.

2012-09-03 Thread sjur . brandeland
From: Sjur Brændeland 

Add a API for modem power control.

Signed-off-by: Sjur Brændeland 
cc: Linus Walleij 
cc: Arun Murthy 
---
 include/linux/modem_ctrl.h |   61 
 1 files changed, 61 insertions(+), 0 deletions(-)
 create mode 100644 include/linux/modem_ctrl.h

diff --git a/include/linux/modem_ctrl.h b/include/linux/modem_ctrl.h
new file mode 100644
index 000..f6c537d
--- /dev/null
+++ b/include/linux/modem_ctrl.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2012
+ * Author: Sjur Brendeland / sjur.brandel...@stericsson.com
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef __INC_MODEM_CTRL_H
+#define __INC_MODEM_CTRL_H
+#include 
+
+struct modem_ctrl;
+
+/**
+ * modem_ctrl_get- Get the handle for the modem power control API.
+ * @modem_name:Name of the modem.
+ *
+ * Get a handle to the modem power control API providing
+ * functionality to for powering up and down the modem.
+ *
+ * This function may block.
+ * Returns zero on success, and negative upon error.
+ */
+struct modem_ctrl *modem_ctrl_get(const char *modem_name);
+
+/**
+ * modem_ctrl_put - Release the instance of the modem ctrl API.
+ *
+ * ctrl:   The API handle return by modem_ctrl_get().
+ *
+ * Releases the modem_ctrl API instance.
+ * This function may block.
+ * Returns zero on success, and negative upon error.
+ */
+void modem_ctrl_put(struct modem_ctrl *ctrl);
+
+/**
+ * modem_start() - Start the modem.
+ *
+ * @ctrl:  The API handle return by modem_ctrl_get().
+ *
+ * This function is used to start the modem.
+ *
+ * This function may block.
+ * Returns zero on success, and negative upon error.
+ */
+int modem_start(struct modem_ctrl *ctrl);
+
+/**
+ * modem_stop() - Stop the modem.
+ *
+ * @ctrl:  The API handle return by modem_ctrl_get().
+ *
+ * This function is used to stop the modem.
+ *
+ * This function may block.
+ * Returns zero on success, and negative upon error.
+ */
+int modem_stop(struct modem_ctrl *ctrl);
+
+#endif /*INC_MODEM_CTRL_H*/
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH] remtoteproc: Export notification id range

2012-09-03 Thread sjur . brandeland
From: Sjur Brændeland 

Some of the rproc drivers needs to know the range
of the notification IDs used for notifying the device.
Export a variable in struct rproc holding the
largest allocated notification id.

Signed-off-by: Sjur Brændeland 
---
 drivers/remoteproc/remoteproc_core.c |3 +++
 include/linux/remoteproc.h   |2 ++
 2 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_core.c 
b/drivers/remoteproc/remoteproc_core.c
index d5c2dbf..00e1674 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -215,6 +215,9 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i)
return ret;
}
 
+   /* Store largest notifyid */
+   rproc->max_notifyid = max(rproc->max_notifyid, notifyid);
+
dev_dbg(dev, "vring%d: va %p dma %x size %x idr %d\n", i, va,
dma, size, notifyid);
 
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index 131b539..c37e359 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -382,6 +382,7 @@ enum rproc_state {
  * @bootaddr: address of first instruction to boot rproc with (optional)
  * @rvdevs: list of remote virtio devices
  * @notifyids: idr for dynamically assigning rproc-wide unique notify ids
+ * @max_notifyid: Largest allocated notify id.
  * @index: index of this rproc device
  */
 struct rproc {
@@ -406,6 +407,7 @@ struct rproc {
struct list_head rvdevs;
struct idr notifyids;
int index;
+   int max_notifyid;
 };
 
 /* we currently support only two vrings per rvdev */
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/