summaryrefslogtreecommitdiff
path: root/drivers/staging/fsl_dpa_offload
diff options
context:
space:
mode:
authorAurelian Zanoschi <Aurelian.Zanoschi@freescale.com>2014-05-08 11:23:57 (GMT)
committerJose Rivera <German.Rivera@freescale.com>2014-05-09 00:51:46 (GMT)
commitcc1d9e72168c9a25ce3fcebed0db7ba556043f3b (patch)
tree19a6547fd729b9a8521d1b1ba4420efed0ede1f3 /drivers/staging/fsl_dpa_offload
parentaebfce967cb36d466d1ba418be7e475a95f951be (diff)
downloadlinux-fsl-qoriq-cc1d9e72168c9a25ce3fcebed0db7ba556043f3b.tar.xz
dpa_offload: Fix DPA Stats async request for 64bit US mode
Because in the case of 64 bit user-space, 64 bit kernel-space CONFIG_COMPAT is enabled, the DPA Stats asynchronous request failed to work. Solving the problem involves analyzing at run time the environment and taking the decision if the compat or normal function for read is used. Also some changes in the internal DPA Stats data structures are needed. Change-Id: I0d7357def19e42901a3c9b90478b07ef53f62301 Signed-off-by: Aurelian Zanoschi <Aurelian.Zanoschi@freescale.com> Reviewed-on: http://git.am.freescale.net:8181/12052 Reviewed-by: Anca Jeanina Floarea <anca.floarea@freescale.com> Reviewed-by: Jose Rivera <German.Rivera@freescale.com> Tested-by: Jose Rivera <German.Rivera@freescale.com>
Diffstat (limited to 'drivers/staging/fsl_dpa_offload')
-rw-r--r--drivers/staging/fsl_dpa_offload/dpa_stats_ioctl.h10
-rw-r--r--drivers/staging/fsl_dpa_offload/wrp_dpa_stats.c148
-rw-r--r--drivers/staging/fsl_dpa_offload/wrp_dpa_stats.h22
3 files changed, 93 insertions, 87 deletions
diff --git a/drivers/staging/fsl_dpa_offload/dpa_stats_ioctl.h b/drivers/staging/fsl_dpa_offload/dpa_stats_ioctl.h
index a1bd323..961373d 100644
--- a/drivers/staging/fsl_dpa_offload/dpa_stats_ioctl.h
+++ b/drivers/staging/fsl_dpa_offload/dpa_stats_ioctl.h
@@ -238,16 +238,6 @@ struct compat_ioc_dpa_stats_cnts_reset_params {
compat_uptr_t cnts_ids;
unsigned int cnts_ids_len;
};
-
-struct compat_dpa_stats_event_params {
- int dpa_stats_id;
- unsigned int storage_area_offset;
- unsigned int cnts_written;
- int bytes_written;
- compat_uptr_t us_cnt_ids;
- unsigned int cnt_ids_len;
- compat_uptr_t request_done;
-};
#endif
#define DPA_STATS_IOC_MAGIC 0xde
diff --git a/drivers/staging/fsl_dpa_offload/wrp_dpa_stats.c b/drivers/staging/fsl_dpa_offload/wrp_dpa_stats.c
index 9a044f3..49545e85 100644
--- a/drivers/staging/fsl_dpa_offload/wrp_dpa_stats.c
+++ b/drivers/staging/fsl_dpa_offload/wrp_dpa_stats.c
@@ -43,6 +43,7 @@
#include <linux/fdtable.h>
#include <linux/atomic.h>
#include <linux/export.h>
+#include <asm/thread_info.h>
#include "lnxwrp_fm.h"
#include "fm_port_ioctls.h"
@@ -99,7 +100,7 @@ static void **copy_class_members(unsigned int size, void **src);
static long store_get_cnts_async_params(
struct ioc_dpa_stats_cnt_request_params *kprm,
- struct dpa_stats_async_req_ev **async_request_event);
+ int *us_cnts);
#ifdef CONFIG_COMPAT
static long wrp_dpa_stats_do_compat_ioctl(struct file *filp,
@@ -251,34 +252,28 @@ long wrp_dpa_stats_ioctl(struct file *filp, unsigned int cmd,
return wrp_dpa_stats_do_ioctl(filp, cmd, args);
}
-#ifdef CONFIG_COMPAT
-ssize_t wrp_dpa_stats_read(struct file *file,
- char *buf, size_t count, loff_t *off)
+ssize_t wrp_normal_read(struct file *file, char *buf, size_t count, loff_t *off)
{
struct dpa_stats_event *event;
- struct compat_dpa_stats_event_params ev_prm;
+ struct dpa_stats_event_params ev_prm;
size_t c = 0;
/*
* Make sure that the size of the buffer requested by the user is
* at least the size of an event
*/
- if (count < sizeof(struct compat_dpa_stats_event_params))
+ if (count < sizeof(struct dpa_stats_event_params))
return -EINVAL;
/* Dequeue first event by using a blocking call */
event = wrp_dpa_stats_dequeue_event(&wrp_dpa_stats.ev_queue, 0);
-
while (event) {
- memset(&ev_prm, 0,
- sizeof(struct compat_dpa_stats_event_params));
-
if (event->params.bytes_written > 0 && wrp_dpa_stats.k_mem) {
if (copy_to_user(wrp_dpa_stats.us_mem +
- event->params.storage_area_offset,
- wrp_dpa_stats.k_mem +
- event->params.storage_area_offset,
- event->params.bytes_written)) {
+ event->params.storage_area_offset,
+ wrp_dpa_stats.k_mem +
+ event->params.storage_area_offset,
+ event->params.bytes_written)) {
log_err("Cannot copy counter values to storage area\n");
return -EFAULT;
}
@@ -288,13 +283,10 @@ ssize_t wrp_dpa_stats_read(struct file *file,
ev_prm.cnts_written = event->params.cnts_written;
ev_prm.dpa_stats_id = event->params.dpa_stats_id;
ev_prm.storage_area_offset = event->params.storage_area_offset;
- ev_prm.request_done = ptr_to_compat(event->params.request_done);
- ev_prm.us_cnt_ids = event->params.us_cnt_ids;
- ev_prm.cnt_ids_len = event->params.cnt_ids_len;
+ ev_prm.request_done = event->params.request_done;
- if (copy_to_user((compat_ptr)(ev_prm.us_cnt_ids),
- event->ks_cnt_ids,
- (event->params.cnt_ids_len * sizeof(int)))) {
+ if (copy_to_user(event->us_cnt_ids, event->ks_cnt_ids,
+ (event->cnt_ids_len * sizeof(int)))) {
kfree(event);
return -EFAULT;
}
@@ -307,10 +299,10 @@ ssize_t wrp_dpa_stats_read(struct file *file,
kfree(event->ks_cnt_ids);
kfree(event);
- count -= sizeof(struct compat_dpa_stats_event_params);
- c += sizeof(struct compat_dpa_stats_event_params);
+ count -= sizeof(struct dpa_stats_event_params);
+ c += sizeof(struct dpa_stats_event_params);
- if (count < sizeof(struct compat_dpa_stats_event_params))
+ if (count < sizeof(struct dpa_stats_event_params))
break;
/* For subsequent events, don't block */
@@ -320,37 +312,51 @@ ssize_t wrp_dpa_stats_read(struct file *file,
return c;
}
-#else
-ssize_t wrp_dpa_stats_read(struct file *file,
- char *buf, size_t count, loff_t *off)
+
+#ifdef CONFIG_COMPAT
+ssize_t wrp_compat_read(struct file *file, char *buf, size_t count, loff_t *off)
{
struct dpa_stats_event *event;
+ struct compat_dpa_stats_event_params ev_prm;
size_t c = 0;
/*
- * Make sure that the size of the buffer requested by the user is
- * at least the size of an event
+ * Make sure that the size of the buffer requested by the user
+ * is at least the size of an event
*/
- if (count < sizeof(struct dpa_stats_event_params))
+ if (count < sizeof(struct compat_dpa_stats_event_params))
return -EINVAL;
/* Dequeue first event by using a blocking call */
event = wrp_dpa_stats_dequeue_event(&wrp_dpa_stats.ev_queue, 0);
while (event) {
+ memset(&ev_prm, 0,
+ sizeof(struct compat_dpa_stats_event_params));
+
if (event->params.bytes_written > 0 && wrp_dpa_stats.k_mem) {
if (copy_to_user(wrp_dpa_stats.us_mem +
- event->params.storage_area_offset,
- wrp_dpa_stats.k_mem +
- event->params.storage_area_offset,
- event->params.bytes_written)) {
+ event->params.storage_area_offset,
+ wrp_dpa_stats.k_mem +
+ event->params.storage_area_offset,
+ event->params.bytes_written)) {
log_err("Cannot copy counter values to storage area\n");
return -EFAULT;
}
}
- if (copy_to_user(buf + c,
- &event->params,
- sizeof(struct dpa_stats_event_params)) != 0) {
+ ev_prm.bytes_written = event->params.bytes_written;
+ ev_prm.cnts_written = event->params.cnts_written;
+ ev_prm.dpa_stats_id = event->params.dpa_stats_id;
+ ev_prm.storage_area_offset = event->params.storage_area_offset;
+ ev_prm.request_done = ptr_to_compat(event->params.request_done);
+
+ if (copy_to_user(event->us_cnt_ids, event->ks_cnt_ids,
+ (event->cnt_ids_len * sizeof(int)))) {
+ kfree(event);
+ return -EFAULT;
+ }
+
+ if (copy_to_user(buf + c, &ev_prm, sizeof(ev_prm)) != 0) {
kfree(event);
return -EFAULT;
}
@@ -358,10 +364,10 @@ ssize_t wrp_dpa_stats_read(struct file *file,
kfree(event->ks_cnt_ids);
kfree(event);
- count -= sizeof(struct dpa_stats_event_params);
- c += sizeof(struct dpa_stats_event_params);
+ count -= sizeof(struct compat_dpa_stats_event_params);
+ c += sizeof(struct compat_dpa_stats_event_params);
- if (count < sizeof(struct dpa_stats_event_params))
+ if (count < sizeof(struct compat_dpa_stats_event_params))
break;
/* For subsequent events, don't block */
@@ -371,7 +377,25 @@ ssize_t wrp_dpa_stats_read(struct file *file,
return c;
}
-#endif
+#endif /* CONFIG_COMPAT */
+
+ssize_t wrp_dpa_stats_read(struct file *file,
+ char *buf, size_t count, loff_t *off)
+{
+#ifdef CONFIG_COMPAT
+ /* compat mode is when KS is compiled for 64 bits */
+ if (is_32bit_task()) {
+ /* case US is compiled for 32 bit */
+ return wrp_compat_read(file, buf, count, off);
+ } else {
+ /* case US is compiled for 64 bit */
+ return wrp_normal_read(file, buf, count, off);
+ }
+#else
+ /* KS compiled for 32 bit and US compiled for 32 bit too */
+ return wrp_normal_read(file, buf, count, off);
+#endif /* CONFIG_COMPAT */
+}
static void wrp_dpa_stats_event_queue_init(
struct dpa_stats_event_queue *event_queue)
@@ -508,15 +532,9 @@ void do_ioctl_req_done_cb(int dpa_stats_id,
event->params.cnts_written = cnts_written;
event->params.bytes_written = bytes_written;
event->params.request_done = async_req_ev->request_done;
-#ifdef CONFIG_COMPAT
event->ks_cnt_ids = async_req_ev->ks_cnt_ids;
- event->params.us_cnt_ids = async_req_ev->us_cnt_ids;
- event->params.cnt_ids_len = async_req_ev->cnt_ids_len;
-#else
- event->ks_cnt_ids = NULL;
- event->params.us_cnt_ids = NULL;
- event->params.cnt_ids_len = 0;
-#endif /* CONFIG_COMPAT */
+ event->us_cnt_ids = async_req_ev->us_cnt_ids;
+ event->cnt_ids_len = async_req_ev->cnt_ids_len;
mutex_unlock(&wrp_dpa_stats.async_req_lock);
@@ -1433,28 +1451,28 @@ static int do_ioctl_stats_get_counters(void *args)
return -EINVAL;
}
+ /* Save the user-space array of counter ids */
+ cnts_ids = prm.req_params.cnts_ids;
+
/* Allocate kernel-space memory area to copy the counters ids */
- cnts_ids = kzalloc(prm.req_params.cnts_ids_len *
- sizeof(int), GFP_KERNEL);
- if (!cnts_ids) {
+ prm.req_params.cnts_ids = kzalloc(prm.req_params.cnts_ids_len *
+ sizeof(int), GFP_KERNEL);
+ if (!prm.req_params.cnts_ids) {
log_err("Cannot allocate memory for requested counter ids array\n");
return -ENOMEM;
}
/* Copy the user provided counter ids */
- if (copy_from_user(cnts_ids,
- prm.req_params.cnts_ids,
- (prm.req_params.cnts_ids_len * sizeof(int)))) {
+ if (copy_from_user(prm.req_params.cnts_ids, cnts_ids,
+ (prm.req_params.cnts_ids_len * sizeof(int)))) {
log_err("Cannot copy from user array of requested counter ids\n");
kfree(prm.req_params.cnts_ids);
return -EINVAL;
}
- prm.req_params.cnts_ids = cnts_ids;
-
/* If counters request is asynchronous */
if (prm.request_done) {
- ret = store_get_cnts_async_params(&prm, NULL);
+ ret = store_get_cnts_async_params(&prm, cnts_ids);
if (ret < 0)
return ret;
}
@@ -1530,14 +1548,10 @@ static int do_ioctl_stats_compat_get_counters(void *args)
/* If counters request is asynchronous */
if (kprm.request_done) {
- struct dpa_stats_async_req_ev *async_request_ev = NULL;
-
- ret = store_get_cnts_async_params(&kprm, &async_request_ev);
+ ret = store_get_cnts_async_params(&kprm,
+ (compat_ptr)(uprm.req_params.cnts_ids));
if (ret < 0)
return ret;
- /* Store user-space pointer to array of ids */
- async_request_ev->us_cnt_ids = uprm.req_params.cnts_ids;
- async_request_ev->cnt_ids_len = uprm.req_params.cnts_ids_len;
}
ret = dpa_stats_get_counters(kprm.req_params,
@@ -1840,8 +1854,7 @@ static long wrp_dpa_stats_do_compat_ioctl(struct file *filp,
#endif
static long store_get_cnts_async_params(
- struct ioc_dpa_stats_cnt_request_params *kprm,
- struct dpa_stats_async_req_ev **async_request_event)
+ struct ioc_dpa_stats_cnt_request_params *kprm, int *us_cnts)
{
struct dpa_stats_async_req_ev *async_req_ev;
struct list_head *async_req_grp;
@@ -1870,15 +1883,14 @@ static long store_get_cnts_async_params(
kprm->req_params.storage_area_offset;
async_req_ev->ks_cnt_ids = kprm->req_params.cnts_ids;
+ async_req_ev->us_cnt_ids = us_cnts;
+ async_req_ev->cnt_ids_len = kprm->req_params.cnts_ids_len;
list_add_tail(&async_req_ev->node, async_req_grp);
mutex_unlock(&wrp_dpa_stats.async_req_lock);
/* Replace the application callback with wrapper function */
kprm->request_done = do_ioctl_req_done_cb;
- /* If calling function requested, return the pointer to async_req_ev */
- if (async_request_event)
- *async_request_event = async_req_ev;
return 0;
}
diff --git a/drivers/staging/fsl_dpa_offload/wrp_dpa_stats.h b/drivers/staging/fsl_dpa_offload/wrp_dpa_stats.h
index 506b02c..f9719a2 100644
--- a/drivers/staging/fsl_dpa_offload/wrp_dpa_stats.h
+++ b/drivers/staging/fsl_dpa_offload/wrp_dpa_stats.h
@@ -66,15 +66,19 @@ struct dpa_stats_event_params {
unsigned int storage_area_offset;
unsigned int cnts_written;
int bytes_written;
-#ifdef CONFIG_COMPAT
- compat_uptr_t us_cnt_ids;
-#else
- int *us_cnt_ids;
-#endif /* CONFIG_COMPAT */
- unsigned int cnt_ids_len;
dpa_stats_request_cb request_done;
};
+#ifdef CONFIG_COMPAT
+struct compat_dpa_stats_event_params {
+ int dpa_stats_id;
+ unsigned int storage_area_offset;
+ unsigned int cnts_written;
+ int bytes_written;
+ compat_uptr_t request_done;
+};
+#endif
+
struct dpa_stats_event_queue {
struct list_head lh; /* Double linked list of events */
wait_queue_head_t wq; /* Waitqueue for reader processes */
@@ -84,7 +88,9 @@ struct dpa_stats_event_queue {
struct dpa_stats_event {
struct dpa_stats_event_params params; /* Event data */
struct list_head lh; /* Event queue list head */
+ int *us_cnt_ids; /* Request array of counter ids from user-space */
int *ks_cnt_ids; /* Request array of counter ids from kernel-space */
+ unsigned int cnt_ids_len; /* Number of counter ids in array */
};
struct dpa_stats_async_req_ev {
@@ -92,9 +98,7 @@ struct dpa_stats_async_req_ev {
unsigned int storage_area_offset; /* Storage offset for this request */
/* Pointers to other async requests in the current set */
struct list_head node;
-#ifdef CONFIG_COMPAT
- compat_uptr_t us_cnt_ids; /* Request array of counter ids from US */
-#endif /* CONFIG COMPAT */
+ int *us_cnt_ids; /* Request array of counter ids from US */
int *ks_cnt_ids; /* Request array of counter ids from KS */
unsigned int cnt_ids_len; /* Number of counter ids in array */
};