diff options
author | Kumar Sanghvi <kumar.sanghvi@stericsson.com> | 2011-03-26 13:53:09 +0530 |
---|---|---|
committer | Mathieu J. Poirier <mathieu.poirier@linaro.org> | 2011-11-10 11:12:12 -0700 |
commit | 6203efe5fa3561683c7952ac68cb79ea30ac27db (patch) | |
tree | b189ecda0bd99835d382999312f95ae71e3f23e8 | |
parent | 2f771cc80581be8ba9af8bdbdcd1b2bf2e4f7145 (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.h | 2 | ||||
-rw-r--r-- | drivers/char/shrm_char.c | 3 | ||||
-rw-r--r-- | drivers/misc/shrm/modem_shrm_driver.c | 3 | ||||
-rw-r--r-- | drivers/misc/shrm/shrm_fifo.c | 30 | ||||
-rw-r--r-- | drivers/net/u8500_shrm.c | 62 |
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++; |