diff options
Diffstat (limited to 'drivers/staging/ozwpan/ozpd.c')
-rw-r--r-- | drivers/staging/ozwpan/ozpd.c | 321 |
1 files changed, 94 insertions, 227 deletions
diff --git a/drivers/staging/ozwpan/ozpd.c b/drivers/staging/ozwpan/ozpd.c index 10f1b3ac8832..852c288aaf13 100644 --- a/drivers/staging/ozwpan/ozpd.c +++ b/drivers/staging/ozwpan/ozpd.c @@ -21,8 +21,6 @@ #include <linux/uaccess.h> #include <net/psnap.h> -#define OZ_MAX_TX_POOL_SIZE 6 - static struct oz_tx_frame *oz_tx_frame_alloc(struct oz_pd *pd); static void oz_tx_frame_free(struct oz_pd *pd, struct oz_tx_frame *f); static void oz_tx_isoc_free(struct oz_pd *pd, struct oz_tx_frame *f); @@ -32,11 +30,6 @@ static void oz_retire_frame(struct oz_pd *pd, struct oz_tx_frame *f); static void oz_isoc_stream_free(struct oz_isoc_stream *st); static int oz_send_next_queued_frame(struct oz_pd *pd, int more_data); static void oz_isoc_destructor(struct sk_buff *skb); -static int oz_def_app_init(void); -static void oz_def_app_term(void); -static int oz_def_app_start(struct oz_pd *pd, int resume); -static void oz_def_app_stop(struct oz_pd *pd, int pause); -static void oz_def_app_rx(struct oz_pd *pd, struct oz_elt *elt); /* * Counts the uncompleted isoc frames submitted to netcard. @@ -45,80 +38,25 @@ static atomic_t g_submitted_isoc = ATOMIC_INIT(0); /* Application handler functions. */ -static const struct oz_app_if g_app_if[OZ_APPID_MAX] = { - {oz_usb_init, - oz_usb_term, - oz_usb_start, - oz_usb_stop, - oz_usb_rx, - oz_usb_heartbeat, - oz_usb_farewell, - OZ_APPID_USB}, - - {oz_def_app_init, - oz_def_app_term, - oz_def_app_start, - oz_def_app_stop, - oz_def_app_rx, - NULL, - NULL, - OZ_APPID_UNUSED1}, - - {oz_def_app_init, - oz_def_app_term, - oz_def_app_start, - oz_def_app_stop, - oz_def_app_rx, - NULL, - NULL, - OZ_APPID_UNUSED2}, - - {oz_cdev_init, - oz_cdev_term, - oz_cdev_start, - oz_cdev_stop, - oz_cdev_rx, - NULL, - NULL, - OZ_APPID_SERIAL}, +static const struct oz_app_if g_app_if[OZ_NB_APPS] = { + [OZ_APPID_USB] = { + .init = oz_usb_init, + .term = oz_usb_term, + .start = oz_usb_start, + .stop = oz_usb_stop, + .rx = oz_usb_rx, + .heartbeat = oz_usb_heartbeat, + .farewell = oz_usb_farewell, + }, + [OZ_APPID_SERIAL] = { + .init = oz_cdev_init, + .term = oz_cdev_term, + .start = oz_cdev_start, + .stop = oz_cdev_stop, + .rx = oz_cdev_rx, + }, }; -/* - * Context: process - */ -static int oz_def_app_init(void) -{ - return 0; -} - -/* - * Context: process - */ -static void oz_def_app_term(void) -{ -} - -/* - * Context: softirq - */ -static int oz_def_app_start(struct oz_pd *pd, int resume) -{ - return 0; -} - -/* - * Context: softirq - */ -static void oz_def_app_stop(struct oz_pd *pd, int pause) -{ -} - -/* - * Context: softirq - */ -static void oz_def_app_rx(struct oz_pd *pd, struct oz_elt *elt) -{ -} /* * Context: softirq or process @@ -168,17 +106,15 @@ struct oz_pd *oz_pd_alloc(const u8 *mac_addr) if (pd) { int i; + atomic_set(&pd->ref_count, 2); - for (i = 0; i < OZ_APPID_MAX; i++) + for (i = 0; i < OZ_NB_APPS; i++) spin_lock_init(&pd->app_lock[i]); pd->last_rx_pkt_num = 0xffffffff; oz_pd_set_state(pd, OZ_PD_S_IDLE); pd->max_tx_size = OZ_MAX_TX_SIZE; ether_addr_copy(pd->mac_addr, mac_addr); - if (0 != oz_elt_buf_init(&pd->elt_buff)) { - kfree(pd); - pd = NULL; - } + oz_elt_buf_init(&pd->elt_buff); spin_lock_init(&pd->tx_frame_lock); INIT_LIST_HEAD(&pd->tx_queue); INIT_LIST_HEAD(&pd->farewell_list); @@ -202,10 +138,7 @@ struct oz_pd *oz_pd_alloc(const u8 *mac_addr) */ static void oz_pd_free(struct work_struct *work) { - struct list_head *e; - struct oz_tx_frame *f; - struct oz_isoc_stream *st; - struct oz_farewell *fwell; + struct list_head *e, *n; struct oz_pd *pd; oz_pd_dbg(pd, ON, "Destroying PD\n"); @@ -213,40 +146,25 @@ static void oz_pd_free(struct work_struct *work) /*Disable timer tasklets*/ tasklet_kill(&pd->heartbeat_tasklet); tasklet_kill(&pd->timeout_tasklet); - /* Delete any streams. - */ - e = pd->stream_list.next; - while (e != &pd->stream_list) { - st = container_of(e, struct oz_isoc_stream, link); - e = e->next; - oz_isoc_stream_free(st); - } - /* Free any queued tx frames. - */ - e = pd->tx_queue.next; - while (e != &pd->tx_queue) { - f = container_of(e, struct oz_tx_frame, link); - e = e->next; + + /* Free streams, queued tx frames and farewells. */ + + list_for_each_safe(e, n, &pd->stream_list) + oz_isoc_stream_free(list_entry(e, struct oz_isoc_stream, link)); + + list_for_each_safe(e, n, &pd->tx_queue) { + struct oz_tx_frame *f = list_entry(e, struct oz_tx_frame, link); + if (f->skb != NULL) kfree_skb(f->skb); oz_retire_frame(pd, f); } + oz_elt_buf_term(&pd->elt_buff); - /* Free any farewells. - */ - e = pd->farewell_list.next; - while (e != &pd->farewell_list) { - fwell = container_of(e, struct oz_farewell, link); - e = e->next; - kfree(fwell); - } - /* Deallocate all frames in tx pool. - */ - while (pd->tx_pool) { - e = pd->tx_pool; - pd->tx_pool = e->next; - kfree(container_of(e, struct oz_tx_frame, link)); - } + + list_for_each_safe(e, n, &pd->farewell_list) + kfree(list_entry(e, struct oz_farewell, link)); + if (pd->net_dev) dev_put(pd->net_dev); kfree(pd); @@ -272,23 +190,21 @@ void oz_pd_destroy(struct oz_pd *pd) */ int oz_services_start(struct oz_pd *pd, u16 apps, int resume) { - const struct oz_app_if *ai; - int rc = 0; + int i, rc = 0; oz_pd_dbg(pd, ON, "%s: (0x%x) resume(%d)\n", __func__, apps, resume); - for (ai = g_app_if; ai < &g_app_if[OZ_APPID_MAX]; ai++) { - if (apps & (1<<ai->app_id)) { - if (ai->start(pd, resume)) { + for (i = 0; i < OZ_NB_APPS; i++) { + if (g_app_if[i].start && (apps & (1 << i))) { + if (g_app_if[i].start(pd, resume)) { rc = -1; oz_pd_dbg(pd, ON, - "Unable to start service %d\n", - ai->app_id); + "Unable to start service %d\n", i); break; } spin_lock_bh(&g_polling_lock); - pd->total_apps |= (1<<ai->app_id); + pd->total_apps |= (1 << i); if (resume) - pd->paused_apps &= ~(1<<ai->app_id); + pd->paused_apps &= ~(1 << i); spin_unlock_bh(&g_polling_lock); } } @@ -300,20 +216,20 @@ int oz_services_start(struct oz_pd *pd, u16 apps, int resume) */ void oz_services_stop(struct oz_pd *pd, u16 apps, int pause) { - const struct oz_app_if *ai; + int i; oz_pd_dbg(pd, ON, "%s: (0x%x) pause(%d)\n", __func__, apps, pause); - for (ai = g_app_if; ai < &g_app_if[OZ_APPID_MAX]; ai++) { - if (apps & (1<<ai->app_id)) { + for (i = 0; i < OZ_NB_APPS; i++) { + if (g_app_if[i].stop && (apps & (1 << i))) { spin_lock_bh(&g_polling_lock); if (pause) { - pd->paused_apps |= (1<<ai->app_id); + pd->paused_apps |= (1 << i); } else { - pd->total_apps &= ~(1<<ai->app_id); - pd->paused_apps &= ~(1<<ai->app_id); + pd->total_apps &= ~(1 << i); + pd->paused_apps &= ~(1 << i); } spin_unlock_bh(&g_polling_lock); - ai->stop(pd, pause); + g_app_if[i].stop(pd, pause); } } } @@ -323,12 +239,11 @@ void oz_services_stop(struct oz_pd *pd, u16 apps, int pause) */ void oz_pd_heartbeat(struct oz_pd *pd, u16 apps) { - const struct oz_app_if *ai; - int more = 0; + int i, more = 0; - for (ai = g_app_if; ai < &g_app_if[OZ_APPID_MAX]; ai++) { - if (ai->heartbeat && (apps & (1<<ai->app_id))) { - if (ai->heartbeat(pd)) + for (i = 0; i < OZ_NB_APPS; i++) { + if (g_app_if[i].heartbeat && (apps & (1 << i))) { + if (g_app_if[i].heartbeat(pd)) more = 1; } } @@ -336,6 +251,7 @@ void oz_pd_heartbeat(struct oz_pd *pd, u16 apps) hrtimer_cancel(&pd->heartbeat); if (pd->mode & OZ_F_ISOC_ANYTIME) { int count = 8; + while (count-- && (oz_send_isoc_frame(pd) >= 0)) ; } @@ -399,17 +315,9 @@ int oz_pd_sleep(struct oz_pd *pd) */ static struct oz_tx_frame *oz_tx_frame_alloc(struct oz_pd *pd) { - struct oz_tx_frame *f = NULL; + struct oz_tx_frame *f; - spin_lock_bh(&pd->tx_frame_lock); - if (pd->tx_pool) { - f = container_of(pd->tx_pool, struct oz_tx_frame, link); - pd->tx_pool = pd->tx_pool->next; - pd->tx_pool_count--; - } - spin_unlock_bh(&pd->tx_frame_lock); - if (f == NULL) - f = kmalloc(sizeof(struct oz_tx_frame), GFP_ATOMIC); + f = kmem_cache_alloc(oz_tx_frame_cache, GFP_ATOMIC); if (f) { f->total_size = sizeof(struct oz_hdr); INIT_LIST_HEAD(&f->link); @@ -425,13 +333,9 @@ static void oz_tx_isoc_free(struct oz_pd *pd, struct oz_tx_frame *f) { pd->nb_queued_isoc_frames--; list_del_init(&f->link); - if (pd->tx_pool_count < OZ_MAX_TX_POOL_SIZE) { - f->link.next = pd->tx_pool; - pd->tx_pool = &f->link; - pd->tx_pool_count++; - } else { - kfree(f); - } + + kmem_cache_free(oz_tx_frame_cache, f); + oz_dbg(TX_FRAMES, "Releasing ISOC Frame isoc_nb= %d\n", pd->nb_queued_isoc_frames); } @@ -441,15 +345,7 @@ static void oz_tx_isoc_free(struct oz_pd *pd, struct oz_tx_frame *f) */ static void oz_tx_frame_free(struct oz_pd *pd, struct oz_tx_frame *f) { - spin_lock_bh(&pd->tx_frame_lock); - if (pd->tx_pool_count < OZ_MAX_TX_POOL_SIZE) { - f->link.next = pd->tx_pool; - pd->tx_pool = &f->link; - pd->tx_pool_count++; - f = NULL; - } - spin_unlock_bh(&pd->tx_frame_lock); - kfree(f); + kmem_cache_free(oz_tx_frame_cache, f); } /* @@ -513,7 +409,7 @@ static struct sk_buff *oz_build_frame(struct oz_pd *pd, struct oz_tx_frame *f) struct net_device *dev = pd->net_dev; struct oz_hdr *oz_hdr; struct oz_elt *elt; - struct list_head *e; + struct oz_elt_info *ei; /* Allocate skb with enough space for the lower layers as well * as the space we need. @@ -538,9 +434,7 @@ static struct sk_buff *oz_build_frame(struct oz_pd *pd, struct oz_tx_frame *f) /* Copy the elements into the frame body. */ elt = (struct oz_elt *)(oz_hdr+1); - for (e = f->elt_list.next; e != &f->elt_list; e = e->next) { - struct oz_elt_info *ei; - ei = container_of(e, struct oz_elt_info, link); + list_for_each_entry(ei, &f->elt_list, link) { memcpy(elt, ei->data, ei->length); elt = oz_next_elt(elt); } @@ -555,13 +449,9 @@ fail: */ static void oz_retire_frame(struct oz_pd *pd, struct oz_tx_frame *f) { - struct list_head *e; - struct oz_elt_info *ei; + struct oz_elt_info *ei, *n; - e = f->elt_list.next; - while (e != &f->elt_list) { - ei = container_of(e, struct oz_elt_info, link); - e = e->next; + list_for_each_entry_safe(ei, n, &f->elt_list, link) { list_del_init(&ei->link); if (ei->callback) ei->callback(pd, ei->context); @@ -570,8 +460,6 @@ static void oz_retire_frame(struct oz_pd *pd, struct oz_tx_frame *f) spin_unlock_bh(&pd->elt_buff.lock); } oz_tx_frame_free(pd, f); - if (pd->elt_buff.free_elts > pd->elt_buff.max_free_elts) - oz_trim_elt_pool(&pd->elt_buff); } /* @@ -589,7 +477,7 @@ static int oz_send_next_queued_frame(struct oz_pd *pd, int more_data) spin_unlock(&pd->tx_frame_lock); return -1; } - f = container_of(e, struct oz_tx_frame, link); + f = list_entry(e, struct oz_tx_frame, link); if (f->skb != NULL) { skb = f->skb; @@ -608,11 +496,10 @@ static int oz_send_next_queued_frame(struct oz_pd *pd, int more_data) oz_dbg(TX_FRAMES, "Sending ISOC Frame, nb_isoc= %d\n", pd->nb_queued_isoc_frames); return 0; - } else { - kfree_skb(skb); - oz_dbg(TX_FRAMES, "Dropping ISOC Frame>\n"); - return -1; } + kfree_skb(skb); + oz_dbg(TX_FRAMES, "Dropping ISOC Frame>\n"); + return -1; } pd->last_sent_frame = e; @@ -677,15 +564,13 @@ static int oz_send_isoc_frame(struct oz_pd *pd) struct net_device *dev = pd->net_dev; struct oz_hdr *oz_hdr; struct oz_elt *elt; - struct list_head *e; - struct list_head list; + struct oz_elt_info *ei; + LIST_HEAD(list); int total_size = sizeof(struct oz_hdr); - INIT_LIST_HEAD(&list); - oz_select_elts_for_tx(&pd->elt_buff, 1, &total_size, pd->max_tx_size, &list); - if (list.next == &list) + if (list_empty(&list)) return 0; skb = alloc_skb(total_size + OZ_ALLOCATED_SPACE(dev), GFP_ATOMIC); if (skb == NULL) { @@ -707,9 +592,7 @@ static int oz_send_isoc_frame(struct oz_pd *pd) oz_hdr->last_pkt_num = pd->trigger_pkt_num & OZ_LAST_PN_MASK; elt = (struct oz_elt *)(oz_hdr+1); - for (e = list.next; e != &list; e = e->next) { - struct oz_elt_info *ei; - ei = container_of(e, struct oz_elt_info, link); + list_for_each_entry(ei, &list, link) { memcpy(elt, ei->data, ei->length); elt = oz_next_elt(elt); } @@ -723,41 +606,30 @@ static int oz_send_isoc_frame(struct oz_pd *pd) */ void oz_retire_tx_frames(struct oz_pd *pd, u8 lpn) { - struct list_head *e; - struct oz_tx_frame *f; - struct list_head *first = NULL; - struct list_head *last = NULL; + struct oz_tx_frame *f, *tmp = NULL; u8 diff; u32 pkt_num; + LIST_HEAD(list); + spin_lock(&pd->tx_frame_lock); - e = pd->tx_queue.next; - while (e != &pd->tx_queue) { - f = container_of(e, struct oz_tx_frame, link); + list_for_each_entry(f, &pd->tx_queue, link) { pkt_num = le32_to_cpu(get_unaligned(&f->hdr.pkt_num)); diff = (lpn - (pkt_num & OZ_LAST_PN_MASK)) & OZ_LAST_PN_MASK; if ((diff > OZ_LAST_PN_HALF_CYCLE) || (pkt_num == 0)) break; oz_dbg(TX_FRAMES, "Releasing pkt_num= %u, nb= %d\n", pkt_num, pd->nb_queued_frames); - if (first == NULL) - first = e; - last = e; - e = e->next; + tmp = f; pd->nb_queued_frames--; } - if (first) { - last->next->prev = &pd->tx_queue; - pd->tx_queue.next = last->next; - last->next = NULL; - } + if (tmp) + list_cut_position(&list, &pd->tx_queue, &tmp->link); pd->last_sent_frame = &pd->tx_queue; spin_unlock(&pd->tx_frame_lock); - while (first) { - f = container_of(first, struct oz_tx_frame, link); - first = first->next; + + list_for_each_entry_safe(f, tmp, &list, link) oz_retire_frame(pd, f); - } } /* @@ -766,11 +638,9 @@ void oz_retire_tx_frames(struct oz_pd *pd, u8 lpn) */ static struct oz_isoc_stream *pd_stream_find(struct oz_pd *pd, u8 ep_num) { - struct list_head *e; struct oz_isoc_stream *st; - list_for_each(e, &pd->stream_list) { - st = container_of(e, struct oz_isoc_stream, link); + list_for_each_entry(st, &pd->stream_list, link) { if (st->ep_num == ep_num) return st; } @@ -884,6 +754,7 @@ int oz_send_isoc_unit(struct oz_pd *pd, u8 ep_num, const u8 *data, int len) } else { struct oz_hdr oz; struct oz_isoc_large iso; + spin_lock_bh(&pd->stream_lock); iso.frame_number = st->frame_num; st->frame_num += nb_units; @@ -906,15 +777,14 @@ int oz_send_isoc_unit(struct oz_pd *pd, u8 ep_num, const u8 *data, int len) if (!(pd->mode & OZ_F_ISOC_ANYTIME)) { struct oz_tx_frame *isoc_unit = NULL; int nb = pd->nb_queued_isoc_frames; + if (nb >= pd->isoc_latency) { - struct list_head *e; struct oz_tx_frame *f; + oz_dbg(TX_FRAMES, "Dropping ISOC Unit nb= %d\n", nb); spin_lock(&pd->tx_frame_lock); - list_for_each(e, &pd->tx_queue) { - f = container_of(e, struct oz_tx_frame, - link); + list_for_each_entry(f, &pd->tx_queue, link) { if (f->skb != NULL) { oz_tx_isoc_free(pd, f); break; @@ -942,8 +812,7 @@ int oz_send_isoc_unit(struct oz_pd *pd, u8 ep_num, const u8 *data, int len) atomic_inc(&g_submitted_isoc); if (dev_queue_xmit(skb) < 0) return -1; - else - return 0; + return 0; } out: kfree_skb(skb); @@ -960,9 +829,10 @@ void oz_apps_init(void) { int i; - for (i = 0; i < OZ_APPID_MAX; i++) + for (i = 0; i < OZ_NB_APPS; i++) { if (g_app_if[i].init) g_app_if[i].init(); + } } /* @@ -973,9 +843,10 @@ void oz_apps_term(void) int i; /* Terminate all the apps. */ - for (i = 0; i < OZ_APPID_MAX; i++) + for (i = 0; i < OZ_NB_APPS; i++) { if (g_app_if[i].term) g_app_if[i].term(); + } } /* @@ -983,12 +854,8 @@ void oz_apps_term(void) */ void oz_handle_app_elt(struct oz_pd *pd, u8 app_id, struct oz_elt *elt) { - const struct oz_app_if *ai; - - if (app_id == 0 || app_id > OZ_APPID_MAX) - return; - ai = &g_app_if[app_id-1]; - ai->rx(pd, elt); + if (app_id < OZ_NB_APPS && g_app_if[app_id].rx) + g_app_if[app_id].rx(pd, elt); } /* @@ -997,7 +864,7 @@ void oz_handle_app_elt(struct oz_pd *pd, u8 app_id, struct oz_elt *elt) void oz_pd_indicate_farewells(struct oz_pd *pd) { struct oz_farewell *f; - const struct oz_app_if *ai = &g_app_if[OZ_APPID_USB-1]; + const struct oz_app_if *ai = &g_app_if[OZ_APPID_USB]; while (1) { spin_lock_bh(&g_polling_lock); |