aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/libertas/main.c
diff options
context:
space:
mode:
authorHolger Schurig <hs4233@mail.mn-solutions.de>2008-04-01 08:50:43 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-04-16 15:59:56 -0400
commit7919b89c8276d657976d4d4d6b7cb58ea1aa08c3 (patch)
tree31fc24e2f8b7d8eeee67347333e078591796d4b7 /drivers/net/wireless/libertas/main.c
parent98dd6a575928ed9c42130d208e6bfb0f7a914d5a (diff)
libertas: convert libertas driver to use an event/cmdresp queue
This patch (co-developed by Dan Williams and Holger Schurig) uses a kfifo object for events and a swapping buffer scheme for the command response to preserve the zero-copy semantics of the CF driver and keep memory usage low. The main thread should only ever touch the buffer indexed by priv->resp_idx, while the interface code is free to write to the second buffer, then swap priv->resp_idx under the driver spinlock. The firmware specs only permit one in-flight command, so there will only ever be one command response to process at a time. Signed-off-by: Holger Schurig <hs4233@mail.mn-solutions.de> Signed-off-by: Dan Williams <dcbw@redhat.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/libertas/main.c')
-rw-r--r--drivers/net/wireless/libertas/main.c158
1 files changed, 88 insertions, 70 deletions
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index 8f1122610974..406f54d40956 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -10,6 +10,7 @@
10#include <linux/netdevice.h> 10#include <linux/netdevice.h>
11#include <linux/if_arp.h> 11#include <linux/if_arp.h>
12#include <linux/kthread.h> 12#include <linux/kthread.h>
13#include <linux/kfifo.h>
13 14
14#include <net/iw_handler.h> 15#include <net/iw_handler.h>
15#include <net/ieee80211.h> 16#include <net/ieee80211.h>
@@ -480,10 +481,9 @@ static void lbs_tx_timeout(struct net_device *dev)
480 481
481 dev->trans_start = jiffies; 482 dev->trans_start = jiffies;
482 483
483 if (priv->currenttxskb) { 484 if (priv->currenttxskb)
484 priv->eventcause = 0x01000000; 485 lbs_send_tx_feedback(priv, 0);
485 lbs_send_tx_feedback(priv); 486
486 }
487 /* XX: Shouldn't we also call into the hw-specific driver 487 /* XX: Shouldn't we also call into the hw-specific driver
488 to kick it somehow? */ 488 to kick it somehow? */
489 lbs_host_to_card_done(priv); 489 lbs_host_to_card_done(priv);
@@ -659,7 +659,6 @@ static int lbs_thread(void *data)
659 struct net_device *dev = data; 659 struct net_device *dev = data;
660 struct lbs_private *priv = dev->priv; 660 struct lbs_private *priv = dev->priv;
661 wait_queue_t wait; 661 wait_queue_t wait;
662 u8 ireg = 0;
663 662
664 lbs_deb_enter(LBS_DEB_THREAD); 663 lbs_deb_enter(LBS_DEB_THREAD);
665 664
@@ -667,9 +666,10 @@ static int lbs_thread(void *data)
667 666
668 for (;;) { 667 for (;;) {
669 int shouldsleep; 668 int shouldsleep;
669 u8 resp_idx;
670 670
671 lbs_deb_thread( "main-thread 111: intcounter=%d currenttxskb=%p dnld_sent=%d\n", 671 lbs_deb_thread("1: currenttxskb %p, dnld_sent %d\n",
672 priv->intcounter, priv->currenttxskb, priv->dnld_sent); 672 priv->currenttxskb, priv->dnld_sent);
673 673
674 add_wait_queue(&priv->waitq, &wait); 674 add_wait_queue(&priv->waitq, &wait);
675 set_current_state(TASK_INTERRUPTIBLE); 675 set_current_state(TASK_INTERRUPTIBLE);
@@ -681,8 +681,6 @@ static int lbs_thread(void *data)
681 shouldsleep = 1; /* We need to wait until we're _told_ to die */ 681 shouldsleep = 1; /* We need to wait until we're _told_ to die */
682 else if (priv->psstate == PS_STATE_SLEEP) 682 else if (priv->psstate == PS_STATE_SLEEP)
683 shouldsleep = 1; /* Sleep mode. Nothing we can do till it wakes */ 683 shouldsleep = 1; /* Sleep mode. Nothing we can do till it wakes */
684 else if (priv->intcounter)
685 shouldsleep = 0; /* Interrupt pending. Deal with it now */
686 else if (priv->cmd_timed_out) 684 else if (priv->cmd_timed_out)
687 shouldsleep = 0; /* Command timed out. Recover */ 685 shouldsleep = 0; /* Command timed out. Recover */
688 else if (!priv->fw_ready) 686 else if (!priv->fw_ready)
@@ -695,29 +693,34 @@ static int lbs_thread(void *data)
695 shouldsleep = 1; /* Can't send a command; one already running */ 693 shouldsleep = 1; /* Can't send a command; one already running */
696 else if (!list_empty(&priv->cmdpendingq)) 694 else if (!list_empty(&priv->cmdpendingq))
697 shouldsleep = 0; /* We have a command to send */ 695 shouldsleep = 0; /* We have a command to send */
696 else if (__kfifo_len(priv->event_fifo))
697 shouldsleep = 0; /* We have an event to process */
698 else if (priv->resp_len[priv->resp_idx])
699 shouldsleep = 0; /* We have a command response */
698 else 700 else
699 shouldsleep = 1; /* No command */ 701 shouldsleep = 1; /* No command */
700 702
701 if (shouldsleep) { 703 if (shouldsleep) {
702 lbs_deb_thread("main-thread sleeping... Conn=%d IntC=%d PS_mode=%d PS_State=%d\n", 704 lbs_deb_thread("sleeping, connect_status %d, "
703 priv->connect_status, priv->intcounter, 705 "ps_mode %d, ps_state %d\n",
704 priv->psmode, priv->psstate); 706 priv->connect_status,
707 priv->psmode, priv->psstate);
705 spin_unlock_irq(&priv->driver_lock); 708 spin_unlock_irq(&priv->driver_lock);
706 schedule(); 709 schedule();
707 } else 710 } else
708 spin_unlock_irq(&priv->driver_lock); 711 spin_unlock_irq(&priv->driver_lock);
709 712
710 lbs_deb_thread("main-thread 222 (waking up): intcounter=%d currenttxskb=%p dnld_sent=%d\n", 713 lbs_deb_thread("2: currenttxskb %p, dnld_send %d\n",
711 priv->intcounter, priv->currenttxskb, priv->dnld_sent); 714 priv->currenttxskb, priv->dnld_sent);
712 715
713 set_current_state(TASK_RUNNING); 716 set_current_state(TASK_RUNNING);
714 remove_wait_queue(&priv->waitq, &wait); 717 remove_wait_queue(&priv->waitq, &wait);
715 718
716 lbs_deb_thread("main-thread 333: intcounter=%d currenttxskb=%p dnld_sent=%d\n", 719 lbs_deb_thread("3: currenttxskb %p, dnld_sent %d\n",
717 priv->intcounter, priv->currenttxskb, priv->dnld_sent); 720 priv->currenttxskb, priv->dnld_sent);
718 721
719 if (kthread_should_stop()) { 722 if (kthread_should_stop()) {
720 lbs_deb_thread("main-thread: break from main thread\n"); 723 lbs_deb_thread("break from main thread\n");
721 break; 724 break;
722 } 725 }
723 726
@@ -726,35 +729,23 @@ static int lbs_thread(void *data)
726 continue; 729 continue;
727 } 730 }
728 731
729 spin_lock_irq(&priv->driver_lock); 732 lbs_deb_thread("4: currenttxskb %p, dnld_sent %d\n",
730 733 priv->currenttxskb, priv->dnld_sent);
731 if (priv->intcounter) {
732 u8 int_status;
733 734
734 priv->intcounter = 0; 735 spin_lock_irq(&priv->driver_lock);
735 int_status = priv->hw_get_int_status(priv, &ireg); 736 /* Process any pending command response */
736 737 resp_idx = priv->resp_idx;
737 if (int_status) { 738 if (priv->resp_len[resp_idx]) {
738 lbs_deb_thread("main-thread: reading HOST_INT_STATUS_REG failed\n");
739 spin_unlock_irq(&priv->driver_lock);
740 continue;
741 }
742 priv->hisregcpy |= ireg;
743 }
744
745 lbs_deb_thread("main-thread 444: intcounter=%d currenttxskb=%p dnld_sent=%d\n",
746 priv->intcounter, priv->currenttxskb, priv->dnld_sent);
747
748 /* command response? */
749 if (priv->hisregcpy & MRVDRV_CMD_UPLD_RDY) {
750 lbs_deb_thread("main-thread: cmd response ready\n");
751
752 priv->hisregcpy &= ~MRVDRV_CMD_UPLD_RDY;
753 spin_unlock_irq(&priv->driver_lock); 739 spin_unlock_irq(&priv->driver_lock);
754 lbs_process_rx_command(priv); 740 lbs_process_command_response(priv,
741 priv->resp_buf[resp_idx],
742 priv->resp_len[resp_idx]);
755 spin_lock_irq(&priv->driver_lock); 743 spin_lock_irq(&priv->driver_lock);
744 priv->resp_len[resp_idx] = 0;
756 } 745 }
746 spin_unlock_irq(&priv->driver_lock);
757 747
748 /* command timeout stuff */
758 if (priv->cmd_timed_out && priv->cur_cmd) { 749 if (priv->cmd_timed_out && priv->cur_cmd) {
759 struct cmd_ctrl_node *cmdnode = priv->cur_cmd; 750 struct cmd_ctrl_node *cmdnode = priv->cur_cmd;
760 751
@@ -775,21 +766,18 @@ static int lbs_thread(void *data)
775 } 766 }
776 priv->cmd_timed_out = 0; 767 priv->cmd_timed_out = 0;
777 768
778 /* Any Card Event */ 769 /* Process hardware events, e.g. card removed, link lost */
779 if (priv->hisregcpy & MRVDRV_CARDEVENT) { 770 spin_lock_irq(&priv->driver_lock);
780 lbs_deb_thread("main-thread: Card Event Activity\n"); 771 while (__kfifo_len(priv->event_fifo)) {
781 772 u32 event;
782 priv->hisregcpy &= ~MRVDRV_CARDEVENT;
783 773
784 if (priv->hw_read_event_cause(priv)) { 774 __kfifo_get(priv->event_fifo, (unsigned char *) &event,
785 lbs_pr_alert("main-thread: hw_read_event_cause failed\n"); 775 sizeof(event));
786 spin_unlock_irq(&priv->driver_lock);
787 continue;
788 }
789 spin_unlock_irq(&priv->driver_lock);
790 lbs_process_event(priv);
791 } else
792 spin_unlock_irq(&priv->driver_lock); 776 spin_unlock_irq(&priv->driver_lock);
777 lbs_process_event(priv, event);
778 spin_lock_irq(&priv->driver_lock);
779 }
780 spin_unlock_irq(&priv->driver_lock);
793 781
794 if (!priv->fw_ready) 782 if (!priv->fw_ready)
795 continue; 783 continue;
@@ -798,8 +786,10 @@ static int lbs_thread(void *data)
798 if (priv->psstate == PS_STATE_PRE_SLEEP && 786 if (priv->psstate == PS_STATE_PRE_SLEEP &&
799 !priv->dnld_sent && !priv->cur_cmd) { 787 !priv->dnld_sent && !priv->cur_cmd) {
800 if (priv->connect_status == LBS_CONNECTED) { 788 if (priv->connect_status == LBS_CONNECTED) {
801 lbs_deb_thread("main_thread: PRE_SLEEP--intcounter=%d currenttxskb=%p dnld_sent=%d cur_cmd=%p, confirm now\n", 789 lbs_deb_thread("pre-sleep, currenttxskb %p, "
802 priv->intcounter, priv->currenttxskb, priv->dnld_sent, priv->cur_cmd); 790 "dnld_sent %d, cur_cmd %p\n",
791 priv->currenttxskb, priv->dnld_sent,
792 priv->cur_cmd);
803 793
804 lbs_ps_confirm_sleep(priv); 794 lbs_ps_confirm_sleep(priv);
805 } else { 795 } else {
@@ -809,7 +799,8 @@ static int lbs_thread(void *data)
809 * after firmware fixes it 799 * after firmware fixes it
810 */ 800 */
811 priv->psstate = PS_STATE_AWAKE; 801 priv->psstate = PS_STATE_AWAKE;
812 lbs_pr_alert("main-thread: ignore PS_SleepConfirm in non-connected state\n"); 802 lbs_pr_alert("ignore PS_SleepConfirm in "
803 "non-connected state\n");
813 } 804 }
814 } 805 }
815 806
@@ -1046,7 +1037,18 @@ static int lbs_init_adapter(struct lbs_private *priv)
1046 /* Allocate the command buffers */ 1037 /* Allocate the command buffers */
1047 if (lbs_allocate_cmd_buffer(priv)) { 1038 if (lbs_allocate_cmd_buffer(priv)) {
1048 lbs_pr_err("Out of memory allocating command buffers\n"); 1039 lbs_pr_err("Out of memory allocating command buffers\n");
1049 ret = -1; 1040 ret = -ENOMEM;
1041 goto out;
1042 }
1043 priv->resp_idx = 0;
1044 priv->resp_len[0] = priv->resp_len[1] = 0;
1045
1046 /* Create the event FIFO */
1047 priv->event_fifo = kfifo_alloc(sizeof(u32) * 16, GFP_KERNEL, NULL);
1048 if (IS_ERR(priv->event_fifo)) {
1049 lbs_pr_err("Out of memory allocating event FIFO buffer\n");
1050 ret = -ENOMEM;
1051 goto out;
1050 } 1052 }
1051 1053
1052out: 1054out:
@@ -1060,6 +1062,8 @@ static void lbs_free_adapter(struct lbs_private *priv)
1060 lbs_deb_enter(LBS_DEB_MAIN); 1062 lbs_deb_enter(LBS_DEB_MAIN);
1061 1063
1062 lbs_free_cmd_buffer(priv); 1064 lbs_free_cmd_buffer(priv);
1065 if (priv->event_fifo)
1066 kfifo_free(priv->event_fifo);
1063 del_timer(&priv->command_timer); 1067 del_timer(&priv->command_timer);
1064 kfree(priv->networks); 1068 kfree(priv->networks);
1065 priv->networks = NULL; 1069 priv->networks = NULL;
@@ -1434,27 +1438,41 @@ out:
1434 return ret; 1438 return ret;
1435} 1439}
1436 1440
1437/** 1441void lbs_queue_event(struct lbs_private *priv, u32 event)
1438 * @brief This function handles the interrupt. it will change PS 1442{
1439 * state if applicable. it will wake up main_thread to handle 1443 unsigned long flags;
1440 * the interrupt event as well. 1444
1441 * 1445 lbs_deb_enter(LBS_DEB_THREAD);
1442 * @param dev A pointer to net_device structure 1446 spin_lock_irqsave(&priv->driver_lock, flags);
1443 * @return n/a 1447
1444 */ 1448 if (priv->psstate == PS_STATE_SLEEP)
1445void lbs_interrupt(struct lbs_private *priv) 1449 priv->psstate = PS_STATE_AWAKE;
1450
1451 __kfifo_put(priv->event_fifo, (unsigned char *) &event, sizeof(u32));
1452
1453 wake_up_interruptible(&priv->waitq);
1454
1455 spin_unlock_irqrestore(&priv->driver_lock, flags);
1456 lbs_deb_leave(LBS_DEB_THREAD);
1457}
1458EXPORT_SYMBOL_GPL(lbs_queue_event);
1459
1460void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx)
1446{ 1461{
1447 lbs_deb_enter(LBS_DEB_THREAD); 1462 lbs_deb_enter(LBS_DEB_THREAD);
1448 1463
1449 lbs_deb_thread("lbs_interrupt: intcounter=%d\n", priv->intcounter);
1450 priv->intcounter++;
1451 if (priv->psstate == PS_STATE_SLEEP) 1464 if (priv->psstate == PS_STATE_SLEEP)
1452 priv->psstate = PS_STATE_AWAKE; 1465 priv->psstate = PS_STATE_AWAKE;
1466
1467 /* Swap buffers by flipping the response index */
1468 BUG_ON(resp_idx > 1);
1469 priv->resp_idx = resp_idx;
1470
1453 wake_up_interruptible(&priv->waitq); 1471 wake_up_interruptible(&priv->waitq);
1454 1472
1455 lbs_deb_leave(LBS_DEB_THREAD); 1473 lbs_deb_leave(LBS_DEB_THREAD);
1456} 1474}
1457EXPORT_SYMBOL_GPL(lbs_interrupt); 1475EXPORT_SYMBOL_GPL(lbs_notify_command_response);
1458 1476
1459static int __init lbs_init_module(void) 1477static int __init lbs_init_module(void)
1460{ 1478{