aboutsummaryrefslogtreecommitdiff
path: root/drivers/staging/ozwpan/ozproto.c
diff options
context:
space:
mode:
authorRupesh Gujare <rupesh.gujare@atmel.com>2013-07-30 13:31:50 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-07-31 17:48:21 -0700
commit8fd070077410b26847ef6f5856850df417e7b83e (patch)
tree2a164a166018dcc02e06a8d66a465006b88b948b /drivers/staging/ozwpan/ozproto.c
parent70bcbc06b7c0c7ecb900a81250862440e80205f7 (diff)
staging: ozwpan: High resolution timers
Current implementation assumes HZ = 1000 for calculating all internal timer intervals, which creates problem on platforms where HZ != 1000. As well we need resolution of less than 10 mSec for heartbeat calculation, this creates problem on some platforms where HZ is configured as HZ = 100, or around, which restricts us to timer interval of 10 mSec. This is particularly found on embedded devices. This patch moves on to use high resolution timers to calculate all timer intervals as it allows us to have very small resolution of timer interval, removing dependency on HZ. Signed-off-by: Rupesh Gujare <rupesh.gujare@atmel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/staging/ozwpan/ozproto.c')
-rw-r--r--drivers/staging/ozwpan/ozproto.c329
1 files changed, 89 insertions, 240 deletions
diff --git a/drivers/staging/ozwpan/ozproto.c b/drivers/staging/ozwpan/ozproto.c
index 760761df384..ed22729ea90 100644
--- a/drivers/staging/ozwpan/ozproto.c
+++ b/drivers/staging/ozwpan/ozproto.c
@@ -30,12 +30,6 @@
#define OZ_DO_STOP 1
#define OZ_DO_SLEEP 2
-/* States of the timer.
- */
-#define OZ_TIMER_IDLE 0
-#define OZ_TIMER_SET 1
-#define OZ_TIMER_IN_HANDLER 2
-
#define OZ_MAX_TIMER_POOL_SIZE 16
/*------------------------------------------------------------------------------
@@ -46,12 +40,6 @@ struct oz_binding {
struct oz_binding *next;
};
-struct oz_timer {
- struct list_head link;
- struct oz_pd *pd;
- unsigned long due_time;
- int type;
-};
/*------------------------------------------------------------------------------
* Static external variables.
*/
@@ -63,15 +51,6 @@ static struct sk_buff_head g_rx_queue;
static u8 g_session_id;
static u16 g_apps = 0x1;
static int g_processing_rx;
-static struct timer_list g_timer;
-static struct oz_timer *g_cur_timer;
-static struct list_head *g_timer_pool;
-static int g_timer_pool_count;
-static int g_timer_state = OZ_TIMER_IDLE;
-static LIST_HEAD(g_timer_list);
-/*------------------------------------------------------------------------------
- */
-static void oz_protocol_timer_start(void);
/*------------------------------------------------------------------------------
* Context: softirq-serialized
*/
@@ -138,33 +117,37 @@ static void pd_set_keepalive(struct oz_pd *pd, u8 kalive)
switch (kalive & OZ_KALIVE_TYPE_MASK) {
case OZ_KALIVE_SPECIAL:
- pd->keep_alive_j =
- oz_ms_to_jiffies(keep_alive * 1000*60*60*24*20);
+ pd->keep_alive = keep_alive * 1000*60*60*24*20;
break;
case OZ_KALIVE_SECS:
- pd->keep_alive_j = oz_ms_to_jiffies(keep_alive*1000);
+ pd->keep_alive = keep_alive*1000;
break;
case OZ_KALIVE_MINS:
- pd->keep_alive_j = oz_ms_to_jiffies(keep_alive*1000*60);
+ pd->keep_alive = keep_alive*1000*60;
break;
case OZ_KALIVE_HOURS:
- pd->keep_alive_j = oz_ms_to_jiffies(keep_alive*1000*60*60);
+ pd->keep_alive = keep_alive*1000*60*60;
break;
default:
- pd->keep_alive_j = 0;
+ pd->keep_alive = 0;
}
- oz_dbg(ON, "Keepalive = %lu jiffies\n", pd->keep_alive_j);
+ oz_dbg(ON, "Keepalive = %lu mSec\n", pd->keep_alive);
}
/*------------------------------------------------------------------------------
* Context: softirq-serialized
*/
-static void pd_set_presleep(struct oz_pd *pd, u8 presleep)
+static void pd_set_presleep(struct oz_pd *pd, u8 presleep, u8 start_timer)
{
if (presleep)
- pd->presleep_j = oz_ms_to_jiffies(presleep*100);
+ pd->presleep = presleep*100;
else
- pd->presleep_j = OZ_PRESLEEP_TOUT_J;
- oz_dbg(ON, "Presleep time = %lu jiffies\n", pd->presleep_j);
+ pd->presleep = OZ_PRESLEEP_TOUT;
+ if (start_timer) {
+ spin_unlock(&g_polling_lock);
+ oz_timer_add(pd, OZ_TIMER_TOUT, pd->presleep);
+ spin_lock(&g_polling_lock);
+ }
+ oz_dbg(ON, "Presleep time = %lu mSec\n", pd->presleep);
}
/*------------------------------------------------------------------------------
* Context: softirq-serialized
@@ -189,7 +172,7 @@ static struct oz_pd *oz_connect_req(struct oz_pd *cur_pd, struct oz_elt *elt,
pd = oz_pd_alloc(pd_addr);
if (pd == NULL)
return NULL;
- pd->last_rx_time_j = jiffies;
+ getnstimeofday(&pd->last_rx_timestamp);
spin_lock_bh(&g_polling_lock);
list_for_each(e, &g_pd_list) {
pd2 = container_of(e, struct oz_pd, link);
@@ -238,9 +221,8 @@ static struct oz_pd *oz_connect_req(struct oz_pd *cur_pd, struct oz_elt *elt,
oz_dbg(ON, "Max frame:%u Ms per isoc:%u\n",
pd->max_tx_size, pd->ms_per_isoc);
pd->max_stream_buffering = 3*1024;
- pd->timeout_time_j = jiffies + OZ_CONNECTION_TOUT_J;
- pd->pulse_period_j = OZ_QUANTUM_J;
- pd_set_presleep(pd, body->presleep);
+ pd->pulse_period = OZ_QUANTUM;
+ pd_set_presleep(pd, body->presleep, 0);
pd_set_keepalive(pd, body->keep_alive);
new_apps &= le16_to_cpu(get_unaligned(&body->apps));
@@ -272,7 +254,6 @@ done:
u16 resume_apps = new_apps & pd->paused_apps & ~0x1;
spin_unlock_bh(&g_polling_lock);
oz_pd_set_state(pd, OZ_PD_S_CONNECTED);
- oz_timer_delete(pd, OZ_TIMER_STOP);
oz_dbg(ON, "new_apps=0x%x total_apps=0x%x paused_apps=0x%x\n",
new_apps, pd->total_apps, pd->paused_apps);
if (start_apps) {
@@ -341,6 +322,7 @@ static void oz_rx_frame(struct sk_buff *skb)
int length;
struct oz_pd *pd = NULL;
struct oz_hdr *oz_hdr = (struct oz_hdr *)skb_network_header(skb);
+ struct timespec current_time;
int dup = 0;
u32 pkt_num;
@@ -361,9 +343,14 @@ static void oz_rx_frame(struct sk_buff *skb)
pd = oz_pd_find(src_addr);
if (pd) {
- pd->last_rx_time_j = jiffies;
- oz_timer_add(pd, OZ_TIMER_TOUT,
- pd->last_rx_time_j + pd->presleep_j, 1);
+ if (!(pd->state & OZ_PD_S_CONNECTED))
+ oz_pd_set_state(pd, OZ_PD_S_CONNECTED);
+ getnstimeofday(&current_time);
+ if ((current_time.tv_sec != pd->last_rx_timestamp.tv_sec) ||
+ (pd->presleep < MSEC_PER_SEC)) {
+ oz_timer_add(pd, OZ_TIMER_TOUT, pd->presleep);
+ pd->last_rx_timestamp = current_time;
+ }
if (pkt_num != pd->last_rx_pkt_num) {
pd->last_rx_pkt_num = pkt_num;
} else {
@@ -412,7 +399,7 @@ static void oz_rx_frame(struct sk_buff *skb)
if (pd && (pd->state & OZ_PD_S_CONNECTED)) {
spin_lock(&g_polling_lock);
pd_set_keepalive(pd, body->keepalive);
- pd_set_presleep(pd, body->presleep);
+ pd_set_presleep(pd, body->presleep, 1);
spin_unlock(&g_polling_lock);
}
}
@@ -450,8 +437,6 @@ done:
*/
void oz_protocol_term(void)
{
- struct list_head *chain;
- del_timer_sync(&g_timer);
/* Walk the list of bindings and remove each one.
*/
spin_lock_bh(&g_binding_lock);
@@ -480,21 +465,35 @@ void oz_protocol_term(void)
oz_pd_put(pd);
spin_lock_bh(&g_polling_lock);
}
- chain = g_timer_pool;
- g_timer_pool = NULL;
spin_unlock_bh(&g_polling_lock);
- while (chain) {
- struct oz_timer *t = container_of(chain, struct oz_timer, link);
- chain = chain->next;
- kfree(t);
- }
oz_dbg(ON, "Protocol stopped\n");
}
/*------------------------------------------------------------------------------
* Context: softirq
*/
-static void oz_pd_handle_timer(struct oz_pd *pd, int type)
+void oz_pd_heartbeat_handler(unsigned long data)
{
+ struct oz_pd *pd = (struct oz_pd *)data;
+ u16 apps = 0;
+ spin_lock_bh(&g_polling_lock);
+ if (pd->state & OZ_PD_S_CONNECTED)
+ apps = pd->total_apps;
+ spin_unlock_bh(&g_polling_lock);
+ if (apps)
+ oz_pd_heartbeat(pd, apps);
+
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq
+ */
+void oz_pd_timeout_handler(unsigned long data)
+{
+ int type;
+ struct oz_pd *pd = (struct oz_pd *)data;
+
+ spin_lock_bh(&g_polling_lock);
+ type = pd->timeout_type;
+ spin_unlock_bh(&g_polling_lock);
switch (type) {
case OZ_TIMER_TOUT:
oz_pd_sleep(pd);
@@ -502,218 +501,69 @@ static void oz_pd_handle_timer(struct oz_pd *pd, int type)
case OZ_TIMER_STOP:
oz_pd_stop(pd);
break;
- case OZ_TIMER_HEARTBEAT: {
- u16 apps = 0;
- spin_lock_bh(&g_polling_lock);
- pd->heartbeat_requested = 0;
- if (pd->state & OZ_PD_S_CONNECTED)
- apps = pd->total_apps;
- spin_unlock_bh(&g_polling_lock);
- if (apps)
- oz_pd_heartbeat(pd, apps);
- }
- break;
}
}
/*------------------------------------------------------------------------------
- * Context: softirq
+ * Context: Interrupt
*/
-static void oz_protocol_timer(unsigned long arg)
+enum hrtimer_restart oz_pd_heartbeat_event(struct hrtimer *timer)
{
- struct oz_timer *t;
- struct oz_timer *t2;
struct oz_pd *pd;
- spin_lock_bh(&g_polling_lock);
- if (!g_cur_timer) {
- /* This happens if we remove the current timer but can't stop
- * the timer from firing. In this case just get out.
- */
- spin_unlock_bh(&g_polling_lock);
- return;
- }
- g_timer_state = OZ_TIMER_IN_HANDLER;
- t = g_cur_timer;
- g_cur_timer = NULL;
- list_del(&t->link);
- spin_unlock_bh(&g_polling_lock);
- do {
- pd = t->pd;
- oz_pd_handle_timer(pd, t->type);
- spin_lock_bh(&g_polling_lock);
- if (g_timer_pool_count < OZ_MAX_TIMER_POOL_SIZE) {
- t->link.next = g_timer_pool;
- g_timer_pool = &t->link;
- g_timer_pool_count++;
- t = NULL;
- }
- if (!list_empty(&g_timer_list)) {
- t2 = container_of(g_timer_list.next,
- struct oz_timer, link);
- if (time_before_eq(t2->due_time, jiffies))
- list_del(&t2->link);
- else
- t2 = NULL;
- } else {
- t2 = NULL;
- }
- spin_unlock_bh(&g_polling_lock);
- oz_pd_put(pd);
- kfree(t);
- t = t2;
- } while (t);
- g_timer_state = OZ_TIMER_IDLE;
- oz_protocol_timer_start();
+
+ pd = container_of(timer, struct oz_pd, heartbeat);
+ hrtimer_forward_now(timer, ktime_set(pd->pulse_period /
+ MSEC_PER_SEC, (pd->pulse_period % MSEC_PER_SEC) * NSEC_PER_MSEC));
+ tasklet_schedule(&pd->heartbeat_tasklet);
+ return HRTIMER_RESTART;
}
/*------------------------------------------------------------------------------
- * Context: softirq
+ * Context: Interrupt
*/
-static void oz_protocol_timer_start(void)
+enum hrtimer_restart oz_pd_timeout_event(struct hrtimer *timer)
{
- spin_lock_bh(&g_polling_lock);
- if (!list_empty(&g_timer_list)) {
- g_cur_timer =
- container_of(g_timer_list.next, struct oz_timer, link);
- if (g_timer_state == OZ_TIMER_SET) {
- mod_timer(&g_timer, g_cur_timer->due_time);
- } else {
- g_timer.expires = g_cur_timer->due_time;
- g_timer.function = oz_protocol_timer;
- g_timer.data = 0;
- add_timer(&g_timer);
- }
- g_timer_state = OZ_TIMER_SET;
- } else {
- oz_dbg(ON, "No queued timers\n");
- }
- spin_unlock_bh(&g_polling_lock);
+ struct oz_pd *pd;
+
+ pd = container_of(timer, struct oz_pd, timeout);
+ tasklet_schedule(&pd->timeout_tasklet);
+ return HRTIMER_NORESTART;
}
/*------------------------------------------------------------------------------
* Context: softirq or process
*/
-void oz_timer_add(struct oz_pd *pd, int type, unsigned long due_time,
- int remove)
+void oz_timer_add(struct oz_pd *pd, int type, unsigned long due_time)
{
- struct list_head *e;
- struct oz_timer *t = NULL;
- int restart_needed = 0;
- spin_lock(&g_polling_lock);
- if (remove) {
- list_for_each(e, &g_timer_list) {
- t = container_of(e, struct oz_timer, link);
- if ((t->pd == pd) && (t->type == type)) {
- if (g_cur_timer == t) {
- restart_needed = 1;
- g_cur_timer = NULL;
- }
- list_del(e);
- break;
- }
- t = NULL;
- }
- }
- if (!t) {
- if (g_timer_pool) {
- t = container_of(g_timer_pool, struct oz_timer, link);
- g_timer_pool = g_timer_pool->next;
- g_timer_pool_count--;
+ spin_lock_bh(&g_polling_lock);
+ switch (type) {
+ case OZ_TIMER_TOUT:
+ case OZ_TIMER_STOP:
+ if (hrtimer_active(&pd->timeout)) {
+ hrtimer_set_expires(&pd->timeout, ktime_set(due_time /
+ MSEC_PER_SEC, (due_time % MSEC_PER_SEC) *
+ NSEC_PER_MSEC));
+ hrtimer_start_expires(&pd->timeout, HRTIMER_MODE_REL);
} else {
- t = kmalloc(sizeof(struct oz_timer), GFP_ATOMIC);
- }
- if (t) {
- t->pd = pd;
- t->type = type;
- oz_pd_get(pd);
+ hrtimer_start(&pd->timeout, ktime_set(due_time /
+ MSEC_PER_SEC, (due_time % MSEC_PER_SEC) *
+ NSEC_PER_MSEC), HRTIMER_MODE_REL);
}
+ pd->timeout_type = type;
+ break;
+ case OZ_TIMER_HEARTBEAT:
+ if (!hrtimer_active(&pd->heartbeat))
+ hrtimer_start(&pd->heartbeat, ktime_set(due_time /
+ MSEC_PER_SEC, (due_time % MSEC_PER_SEC) *
+ NSEC_PER_MSEC), HRTIMER_MODE_REL);
+ break;
}
- if (t) {
- struct oz_timer *t2;
- t->due_time = due_time;
- list_for_each(e, &g_timer_list) {
- t2 = container_of(e, struct oz_timer, link);
- if (time_before(due_time, t2->due_time)) {
- if (t2 == g_cur_timer) {
- g_cur_timer = NULL;
- restart_needed = 1;
- }
- break;
- }
- }
- list_add_tail(&t->link, e);
- }
- if (g_timer_state == OZ_TIMER_IDLE)
- restart_needed = 1;
- else if (g_timer_state == OZ_TIMER_IN_HANDLER)
- restart_needed = 0;
- spin_unlock(&g_polling_lock);
- if (restart_needed)
- oz_protocol_timer_start();
-}
-/*------------------------------------------------------------------------------
- * Context: softirq or process
- */
-void oz_timer_delete(struct oz_pd *pd, int type)
-{
- struct list_head *chain = NULL;
- struct oz_timer *t;
- struct oz_timer *n;
- int restart_needed = 0;
- int release = 0;
- spin_lock(&g_polling_lock);
- list_for_each_entry_safe(t, n, &g_timer_list, link) {
- if ((t->pd == pd) && ((type == 0) || (t->type == type))) {
- if (g_cur_timer == t) {
- restart_needed = 1;
- g_cur_timer = NULL;
- del_timer(&g_timer);
- }
- list_del(&t->link);
- release++;
- if (g_timer_pool_count < OZ_MAX_TIMER_POOL_SIZE) {
- t->link.next = g_timer_pool;
- g_timer_pool = &t->link;
- g_timer_pool_count++;
- } else {
- t->link.next = chain;
- chain = &t->link;
- }
- if (type)
- break;
- }
- }
- if (g_timer_state == OZ_TIMER_IN_HANDLER)
- restart_needed = 0;
- else if (restart_needed)
- g_timer_state = OZ_TIMER_IDLE;
- spin_unlock(&g_polling_lock);
- if (restart_needed)
- oz_protocol_timer_start();
- while (release--)
- oz_pd_put(pd);
- while (chain) {
- t = container_of(chain, struct oz_timer, link);
- chain = chain->next;
- kfree(t);
- }
+ spin_unlock_bh(&g_polling_lock);
}
/*------------------------------------------------------------------------------
* Context: softirq or process
*/
void oz_pd_request_heartbeat(struct oz_pd *pd)
{
- unsigned long now = jiffies;
- unsigned long t;
- spin_lock(&g_polling_lock);
- if (pd->heartbeat_requested) {
- spin_unlock(&g_polling_lock);
- return;
- }
- if (pd->pulse_period_j)
- t = ((now / pd->pulse_period_j) + 1) * pd->pulse_period_j;
- else
- t = now + 1;
- pd->heartbeat_requested = 1;
- spin_unlock(&g_polling_lock);
- oz_timer_add(pd, OZ_TIMER_HEARTBEAT, t, 0);
+ oz_timer_add(pd, OZ_TIMER_HEARTBEAT, pd->pulse_period > 0 ?
+ pd->pulse_period : OZ_QUANTUM);
}
/*------------------------------------------------------------------------------
* Context: softirq or process
@@ -915,7 +765,6 @@ int oz_protocol_init(char *devs)
oz_binding_add(d);
}
}
- init_timer(&g_timer);
return 0;
}
/*------------------------------------------------------------------------------