summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKumar Sanghvi <kumar.sanghvi@stericsson.com>2011-03-26 13:53:09 +0530
committerMathieu J. Poirier <mathieu.poirier@linaro.org>2011-11-10 11:12:12 -0700
commit6203efe5fa3561683c7952ac68cb79ea30ac27db (patch)
treeb189ecda0bd99835d382999312f95ae71e3f23e8
parent2f771cc80581be8ba9af8bdbdcd1b2bf2e4f7145 (diff)
u8500: shrm: Misc updates and optimisation
This patch does following: 1. Protects reset of char queues to prevent a potential kernel crash if MSR is run in rapid succession continuously without allowing the user-space to settle. 2. Removes un-needed memcpy from tx/rx path in shrm net interface. 3. Eliminates use of ph_recv_buf in rx path. 3. Fixes compiler warning in net interface. 4. Updates the protection of writes to shrm fifo. ST-Ericsson ID: ER326117 Change-Id: I6aac23e20a20efc1f9b8a620db455f53e067f9bd Signed-off-by: Kumar Sanghvi <kumar.sanghvi@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/19226 Reviewed-by: Hemant-vilas RAMDASI <hemant.ramdasi@stericsson.com> Reviewed-by: Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com>
-rw-r--r--arch/arm/mach-ux500/include/mach/shrm_net.h2
-rw-r--r--drivers/char/shrm_char.c3
-rw-r--r--drivers/misc/shrm/modem_shrm_driver.c3
-rw-r--r--drivers/misc/shrm/shrm_fifo.c30
-rw-r--r--drivers/net/u8500_shrm.c62
5 files changed, 44 insertions, 56 deletions
diff --git a/arch/arm/mach-ux500/include/mach/shrm_net.h b/arch/arm/mach-ux500/include/mach/shrm_net.h
index 4e675a98f3d..a97b276ee15 100644
--- a/arch/arm/mach-ux500/include/mach/shrm_net.h
+++ b/arch/arm/mach-ux500/include/mach/shrm_net.h
@@ -33,7 +33,7 @@ struct shrm_net_iface_priv {
};
int shrm_register_netdev(struct shrm_dev *shrm_dev_data);
-int shrm_net_receive(struct net_device *dev, unsigned char *data);
+int shrm_net_receive(struct net_device *dev);
int shrm_suspend_netdev(struct net_device *dev);
int shrm_resume_netdev(struct net_device *dev);
int shrm_stop_netdev(struct net_device *dev);
diff --git a/drivers/char/shrm_char.c b/drivers/char/shrm_char.c
index 2890f152d2d..714d38e42f1 100644
--- a/drivers/char/shrm_char.c
+++ b/drivers/char/shrm_char.c
@@ -112,6 +112,7 @@ void shrm_char_reset_queues(struct shrm_dev *shrm)
isadev = &isa_context->isadev[no_dev];
q = &isadev->dl_queue;
+ spin_lock_bh(&q->update_lock);
/* empty out the msg queue */
list_for_each_safe(cur_msg_ptr, msg_ptr, &q->msg_list) {
cur_msg = list_entry(cur_msg_ptr,
@@ -129,6 +130,8 @@ void shrm_char_reset_queues(struct shrm_dev *shrm)
/* wake up the blocking read/select */
atomic_set(&q->q_rp, 1);
wake_up_interruptible(&q->wq_readable);
+
+ spin_unlock_bh(&q->update_lock);
}
}
diff --git a/drivers/misc/shrm/modem_shrm_driver.c b/drivers/misc/shrm/modem_shrm_driver.c
index d94c007098b..29368950256 100644
--- a/drivers/misc/shrm/modem_shrm_driver.c
+++ b/drivers/misc/shrm/modem_shrm_driver.c
@@ -42,7 +42,6 @@ static struct hrtimer timer;
#define PHONET_TASKLET
#define MAX_RCV_LEN 2048
-static u8 ph_recv_buf[MAX_RCV_LEN];
void do_phonet_rcv_tasklet(unsigned long unused);
struct tasklet_struct phonet_rcv_tasklet;
@@ -308,7 +307,7 @@ void do_phonet_rcv_tasklet(unsigned long unused)
dev_dbg(shrm->dev, "%s IN\n", __func__);
for (;;) {
- ret = shrm_net_receive(shrm->ndev, ph_recv_buf);
+ ret = shrm_net_receive(shrm->ndev);
if (ret == 0) {
dev_dbg(shrm->dev, "len is zero, queue empty\n");
break;
diff --git a/drivers/misc/shrm/shrm_fifo.c b/drivers/misc/shrm/shrm_fifo.c
index ecf4b7e4466..cbe0949a56d 100644
--- a/drivers/misc/shrm/shrm_fifo.c
+++ b/drivers/misc/shrm/shrm_fifo.c
@@ -125,6 +125,7 @@ void write_boot_info_resp(struct shrm_dev *shrm, u32 config,
u8 msg_length;
version = SHRM_VER;
+ spin_lock_bh(&fifo->fifo_update_lock);
/* Read L1 header read content of reader_local_rptr */
msg = (u32 *)
(fifo->writer_local_wptr+fifo->fifo_virtual_addr);
@@ -144,10 +145,9 @@ void write_boot_info_resp(struct shrm_dev *shrm, u32 config,
*msg = ca_csc_inactivity_timer;
msg_length = L1_NORMAL_MSG;
}
- spin_lock(&fifo->fifo_update_lock);
fifo->writer_local_wptr += msg_length;
fifo->availablesize -= msg_length;
- spin_unlock(&fifo->fifo_update_lock);
+ spin_unlock_bh(&fifo->fifo_update_lock);
}
/**
@@ -240,6 +240,7 @@ int shm_write_msg_to_fifo(struct shrm_dev *shrm, u8 channel,
*/
l2_header = ((l2header << L2_HEADER_OFFSET) |
((length) & MASK_0_39_BIT));
+ spin_lock_bh(&fifo->fifo_update_lock);
/* Check Local Rptr is less than or equal to Local WPtr */
if (fifo->writer_local_rptr <= fifo->writer_local_wptr) {
msg = (u32 *)
@@ -257,11 +258,9 @@ int shm_write_msg_to_fifo(struct shrm_dev *shrm, u8 channel,
/* copy the l2 message in 1 memcpy */
memcpy((void *)msg, addr, length);
/* UpdateWptr */
- spin_lock_bh(&fifo->fifo_update_lock);
fifo->writer_local_wptr += requiredsize;
fifo->availablesize -= requiredsize;
fifo->writer_local_wptr %= fifo->end_addr_fifo;
- spin_unlock_bh(&fifo->fifo_update_lock);
} else {
/*
* message is split between and of FIFO and beg of FIFO
@@ -273,7 +272,6 @@ int shm_write_msg_to_fifo(struct shrm_dev *shrm, u8 channel,
/* Add L1 header */
*msg = l1_header;
msg++;
- spin_lock_bh(&fifo->fifo_update_lock);
/* UpdateWptr */
fifo->writer_local_wptr = 0;
fifo->availablesize -= size;
@@ -293,7 +291,6 @@ int shm_write_msg_to_fifo(struct shrm_dev *shrm, u8 channel,
requiredsize-size;
fifo->availablesize -=
(requiredsize-size);
- spin_unlock_bh(&fifo->fifo_update_lock);
} else if (size == 2) {
/* Add L1 header and L2 header */
*msg = l1_header;
@@ -301,7 +298,6 @@ int shm_write_msg_to_fifo(struct shrm_dev *shrm, u8 channel,
*msg = l2_header;
msg++;
- spin_lock_bh(&fifo->fifo_update_lock);
/* UpdateWptr */
fifo->writer_local_wptr = 0;
fifo->availablesize -= size;
@@ -320,7 +316,6 @@ int shm_write_msg_to_fifo(struct shrm_dev *shrm, u8 channel,
requiredsize-size;
fifo->availablesize -=
(requiredsize-size);
- spin_unlock_bh(&fifo->fifo_update_lock);
} else {
/* Add L1 header and L2 header */
*msg = l1_header;
@@ -331,7 +326,6 @@ int shm_write_msg_to_fifo(struct shrm_dev *shrm, u8 channel,
/* copy the l2 message in 1 memcpy */
memcpy((void *)msg, addr, (size-2)*4);
- spin_lock_bh(&fifo->fifo_update_lock);
/* UpdateWptr */
fifo->writer_local_wptr = 0;
@@ -351,7 +345,6 @@ int shm_write_msg_to_fifo(struct shrm_dev *shrm, u8 channel,
requiredsize-size;
fifo->availablesize -=
(requiredsize-size);
- spin_unlock_bh(&fifo->fifo_update_lock);
}
}
@@ -370,13 +363,12 @@ int shm_write_msg_to_fifo(struct shrm_dev *shrm, u8 channel,
*/
memcpy((void *)msg, addr, length);
- spin_lock_bh(&fifo->fifo_update_lock);
/* UpdateWptr */
fifo->writer_local_wptr += requiredsize;
fifo->availablesize -= requiredsize;
- spin_unlock_bh(&fifo->fifo_update_lock);
}
+ spin_unlock_bh(&fifo->fifo_update_lock);
return length;
}
@@ -667,6 +659,7 @@ void update_ac_common_local_rptr(struct shrm_dev *shrm)
fifo = &ape_shm_fifo_0;
+ spin_lock_bh(&fifo->fifo_update_lock);
fifo->shared_rptr =
(*((u32 *)shrm->ac_common_shared_rptr));
@@ -680,10 +673,9 @@ void update_ac_common_local_rptr(struct shrm_dev *shrm)
}
/* Chance of race condition of below variables with write_msg */
- spin_lock(&fifo->fifo_update_lock);
fifo->availablesize += free_space;
fifo->writer_local_rptr = fifo->shared_rptr;
- spin_unlock(&fifo->fifo_update_lock);
+ spin_unlock_bh(&fifo->fifo_update_lock);
}
void update_ac_audio_local_rptr(struct shrm_dev *shrm)
@@ -696,6 +688,7 @@ void update_ac_audio_local_rptr(struct shrm_dev *shrm)
u32 free_space = 0;
fifo = &ape_shm_fifo_1;
+ spin_lock_bh(&fifo->fifo_update_lock);
fifo->shared_rptr =
(*((u32 *)shrm->ac_audio_shared_rptr));
@@ -709,10 +702,9 @@ void update_ac_audio_local_rptr(struct shrm_dev *shrm)
}
/* Chance of race condition of below variables with write_msg */
- spin_lock(&fifo->fifo_update_lock);
fifo->availablesize += free_space;
fifo->writer_local_rptr = fifo->shared_rptr;
- spin_unlock(&fifo->fifo_update_lock);
+ spin_unlock_bh(&fifo->fifo_update_lock);
}
void update_ac_common_shared_wptr(struct shrm_dev *shrm)
@@ -724,11 +716,13 @@ void update_ac_common_shared_wptr(struct shrm_dev *shrm)
struct fifo_write_params *fifo;
fifo = &ape_shm_fifo_0;
+ spin_lock_bh(&fifo->fifo_update_lock);
/* Update shared pointer fifo offset of the IPC zone */
(*((u32 *)shrm->ac_common_shared_wptr)) =
fifo->writer_local_wptr;
fifo->shared_wptr = fifo->writer_local_wptr;
+ spin_unlock_bh(&fifo->fifo_update_lock);
}
void update_ac_audio_shared_wptr(struct shrm_dev *shrm)
@@ -740,10 +734,12 @@ void update_ac_audio_shared_wptr(struct shrm_dev *shrm)
struct fifo_write_params *fifo;
fifo = &ape_shm_fifo_1;
+ spin_lock_bh(&fifo->fifo_update_lock);
/* Update shared pointer fifo offset of the IPC zone */
(*((u32 *)shrm->ac_audio_shared_wptr)) =
fifo->writer_local_wptr;
fifo->shared_wptr = fifo->writer_local_wptr;
+ spin_unlock_bh(&fifo->fifo_update_lock);
}
void update_ca_common_shared_rptr(struct shrm_dev *shrm)
@@ -803,9 +799,11 @@ void get_writer_pointers(u8 channel_type, u32 *writer_local_rptr,
else /* channel_type = AUDIO_CHANNEL */
fifo = &ape_shm_fifo_1;
+ spin_lock_bh(&fifo->fifo_update_lock);
*writer_local_rptr = fifo->writer_local_rptr;
*writer_local_wptr = fifo->writer_local_wptr;
*shared_wptr = fifo->shared_wptr;
+ spin_unlock_bh(&fifo->fifo_update_lock);
}
void set_ca_msg_0_read_notif_send(u8 val)
diff --git a/drivers/net/u8500_shrm.c b/drivers/net/u8500_shrm.c
index aaec346c781..488f96f2c04 100644
--- a/drivers/net/u8500_shrm.c
+++ b/drivers/net/u8500_shrm.c
@@ -22,16 +22,13 @@
#include <mach/shrm_net.h>
#include <mach/shrm.h>
-static u8 wr_isi_msg[10*1024];
-
/**
* shrm_net_receive() - receive data and copy to user space buffer
* @dev: pointer to the network device structure
- * @data: pointer to the receive buffer
*
* Copy data from ISI queue to the user space buffer.
*/
-int shrm_net_receive(struct net_device *dev, u8 *data)
+int shrm_net_receive(struct net_device *dev)
{
struct sk_buff *skb;
struct isadev_context *isadev;
@@ -42,9 +39,6 @@ int shrm_net_receive(struct net_device *dev, u8 *data)
(struct shrm_net_iface_priv *)netdev_priv(dev);
struct shrm_dev *shrm = net_iface_priv->shrm_device;
- if (data == NULL)
- goto out;
-
isadev = &shrm->isa_context->isadev[ISI_MESSAGING];
q = &isadev->dl_queue;
@@ -60,30 +54,10 @@ int shrm_net_receive(struct net_device *dev, u8 *data)
if (msgsize <= 0)
return msgsize;
- if ((q->readptr+msgsize) >= q->size) {
- size = (q->size-q->readptr);
- /*Copy First Part of msg*/
- memcpy(data,
- (u8 *)(q->fifo_base + q->readptr), size);
- /*Copy Second Part of msg at the top of fifo*/
- memcpy(data+size,
- (u8 *)(q->fifo_base), (msgsize - size));
- } else {
- memcpy(data,
- (u8 *)(q->fifo_base+q->readptr), msgsize);
- }
-
- spin_lock_bh(&q->update_lock);
- remove_msg_from_queue(q);
- spin_unlock_bh(&q->update_lock);
-
- dev_dbg(shrm->dev, "Data len at shrm_net_receive: %d\n", msgsize);
-
/*
* The packet has been retrieved from the transmission
* medium. Build an skb around it, so upper layers can handle it
*/
-
skb = dev_alloc_skb(msgsize);
if (!skb) {
if (printk_ratelimit())
@@ -92,8 +66,29 @@ int shrm_net_receive(struct net_device *dev, u8 *data)
dev->stats.rx_dropped++;
goto out;
}
- skb_copy_to_linear_data(skb, data, msgsize);
- skb_put(skb, msgsize);
+
+ if ((q->readptr+msgsize) >= q->size) {
+ size = (q->size-q->readptr);
+ /*Copy First Part of msg*/
+ skb_copy_to_linear_data(skb,
+ (u8 *)(q->fifo_base + q->readptr), size);
+ skb_put(skb, size);
+
+ /*Copy Second Part of msg at the top of fifo*/
+ skb_copy_to_linear_data_offset(skb, size,
+ (u8 *)(q->fifo_base), (msgsize - size));
+ skb_put(skb, msgsize-size);
+
+ } else {
+ skb_copy_to_linear_data(skb,
+ (u8 *)(q->fifo_base+q->readptr), msgsize);
+ skb_put(skb, msgsize);
+ }
+
+ spin_lock_bh(&q->update_lock);
+ remove_msg_from_queue(q);
+ spin_unlock_bh(&q->update_lock);
+
skb_reset_mac_header(skb);
__skb_pull(skb, dev->hard_header_len);
/*Write metadata, and then pass to the receive level*/
@@ -196,15 +191,8 @@ static netdev_tx_t netdev_isa_write(struct sk_buff *skb, struct net_device *dev)
skb->data[SRC_OBJ_INDEX] = skb->data[PIPE_HDL_INDEX];
}
- if ((void *)wr_isi_msg !=
- memcpy((void *)wr_isi_msg, skb->data, skb->len)) {
- dev_err(shrm->dev, "memcpy failed\n");
- dev_kfree_skb(skb);
- return -EFAULT;
- }
-
spin_lock_bh(&shrm->isa_context->common_tx);
- err = shm_write_msg(shrm, ISI_MESSAGING, (void *)wr_isi_msg,
+ err = shm_write_msg(shrm, ISI_MESSAGING, skb->data,
skb->len);
if (!err) {
dev->stats.tx_packets++;