diff options
Diffstat (limited to 'drivers/hsi/clients/ssi_protocol.c')
-rw-r--r-- | drivers/hsi/clients/ssi_protocol.c | 110 |
1 files changed, 65 insertions, 45 deletions
diff --git a/drivers/hsi/clients/ssi_protocol.c b/drivers/hsi/clients/ssi_protocol.c index 6595d2091268..6031cd146556 100644 --- a/drivers/hsi/clients/ssi_protocol.c +++ b/drivers/hsi/clients/ssi_protocol.c @@ -88,6 +88,8 @@ void ssi_waketest(struct hsi_client *cl, unsigned int enable); #define SSIP_READY_CMD SSIP_CMD(SSIP_READY, 0) #define SSIP_SWBREAK_CMD SSIP_CMD(SSIP_SW_BREAK, 0) +#define SSIP_WAKETEST_FLAG 0 + /* Main state machine states */ enum { INIT, @@ -116,7 +118,7 @@ enum { * @main_state: Main state machine * @send_state: TX state machine * @recv_state: RX state machine - * @waketest: Flag to follow wake line test + * @flags: Flags, currently only used to follow wake line test * @rxid: RX data id * @txid: TX data id * @txqueue_len: TX queue length @@ -137,7 +139,7 @@ struct ssi_protocol { unsigned int main_state; unsigned int send_state; unsigned int recv_state; - unsigned int waketest:1; + unsigned long flags; u8 rxid; u8 txid; unsigned int txqueue_len; @@ -148,6 +150,7 @@ struct ssi_protocol { struct net_device *netdev; struct list_head txqueue; struct list_head cmdqueue; + struct work_struct work; struct hsi_client *cl; struct list_head link; atomic_t tx_usecnt; @@ -405,15 +408,17 @@ static void ssip_reset(struct hsi_client *cl) spin_lock_bh(&ssi->lock); if (ssi->send_state != SEND_IDLE) hsi_stop_tx(cl); - if (ssi->waketest) - ssi_waketest(cl, 0); + spin_unlock_bh(&ssi->lock); + if (test_and_clear_bit(SSIP_WAKETEST_FLAG, &ssi->flags)) + ssi_waketest(cl, 0); /* FIXME: To be removed */ + spin_lock_bh(&ssi->lock); del_timer(&ssi->rx_wd); del_timer(&ssi->tx_wd); del_timer(&ssi->keep_alive); ssi->main_state = 0; ssi->send_state = 0; ssi->recv_state = 0; - ssi->waketest = 0; + ssi->flags = 0; ssi->rxid = 0; ssi->txid = 0; list_for_each_safe(head, tmp, &ssi->txqueue) { @@ -437,7 +442,8 @@ static void ssip_dump_state(struct hsi_client *cl) dev_err(&cl->device, "Send state: %d\n", ssi->send_state); dev_err(&cl->device, "CMT %s\n", (ssi->main_state == ACTIVE) ? "Online" : "Offline"); - dev_err(&cl->device, "Wake test %d\n", ssi->waketest); + dev_err(&cl->device, "Wake test %d\n", + test_bit(SSIP_WAKETEST_FLAG, &ssi->flags)); dev_err(&cl->device, "Data RX id: %d\n", ssi->rxid); dev_err(&cl->device, "Data TX id: %d\n", ssi->txid); @@ -515,17 +521,17 @@ static void ssip_start_rx(struct hsi_client *cl) dev_dbg(&cl->device, "RX start M(%d) R(%d)\n", ssi->main_state, ssi->recv_state); - spin_lock(&ssi->lock); + spin_lock_bh(&ssi->lock); /* * We can have two UP events in a row due to a short low * high transition. Therefore we need to ignore the sencond UP event. */ if ((ssi->main_state != ACTIVE) || (ssi->recv_state == RECV_READY)) { - spin_unlock(&ssi->lock); + spin_unlock_bh(&ssi->lock); return; } ssip_set_rxstate(ssi, RECV_READY); - spin_unlock(&ssi->lock); + spin_unlock_bh(&ssi->lock); msg = ssip_claim_cmd(ssi); ssip_set_cmd(msg, SSIP_READY_CMD); @@ -539,10 +545,10 @@ static void ssip_stop_rx(struct hsi_client *cl) struct ssi_protocol *ssi = hsi_client_drvdata(cl); dev_dbg(&cl->device, "RX stop M(%d)\n", ssi->main_state); - spin_lock(&ssi->lock); + spin_lock_bh(&ssi->lock); if (likely(ssi->main_state == ACTIVE)) ssip_set_rxstate(ssi, RECV_IDLE); - spin_unlock(&ssi->lock); + spin_unlock_bh(&ssi->lock); } static void ssip_free_strans(struct hsi_msg *msg) @@ -559,9 +565,9 @@ static void ssip_strans_complete(struct hsi_msg *msg) data = msg->context; ssip_release_cmd(msg); - spin_lock(&ssi->lock); + spin_lock_bh(&ssi->lock); ssip_set_txstate(ssi, SENDING); - spin_unlock(&ssi->lock); + spin_unlock_bh(&ssi->lock); hsi_async_write(cl, data); } @@ -666,15 +672,17 @@ static void ssip_rx_bootinforeq(struct hsi_client *cl, u32 cmd) /* Fall through */ case INIT: case HANDSHAKE: - spin_lock(&ssi->lock); + spin_lock_bh(&ssi->lock); ssi->main_state = HANDSHAKE; - if (!ssi->waketest) { - ssi->waketest = 1; + spin_unlock_bh(&ssi->lock); + + if (!test_and_set_bit(SSIP_WAKETEST_FLAG, &ssi->flags)) ssi_waketest(cl, 1); /* FIXME: To be removed */ - } + + spin_lock_bh(&ssi->lock); /* Start boot handshake watchdog */ mod_timer(&ssi->tx_wd, jiffies + msecs_to_jiffies(SSIP_WDTOUT)); - spin_unlock(&ssi->lock); + spin_unlock_bh(&ssi->lock); dev_dbg(&cl->device, "Send BOOTINFO_RESP\n"); if (SSIP_DATA_VERSION(cmd) != SSIP_LOCAL_VERID) dev_warn(&cl->device, "boot info req verid mismatch\n"); @@ -696,14 +704,14 @@ static void ssip_rx_bootinforesp(struct hsi_client *cl, u32 cmd) if (SSIP_DATA_VERSION(cmd) != SSIP_LOCAL_VERID) dev_warn(&cl->device, "boot info resp verid mismatch\n"); - spin_lock(&ssi->lock); + spin_lock_bh(&ssi->lock); if (ssi->main_state != ACTIVE) /* Use tx_wd as a boot watchdog in non ACTIVE state */ mod_timer(&ssi->tx_wd, jiffies + msecs_to_jiffies(SSIP_WDTOUT)); else dev_dbg(&cl->device, "boot info resp ignored M(%d)\n", ssi->main_state); - spin_unlock(&ssi->lock); + spin_unlock_bh(&ssi->lock); } static void ssip_rx_waketest(struct hsi_client *cl, u32 cmd) @@ -711,20 +719,22 @@ static void ssip_rx_waketest(struct hsi_client *cl, u32 cmd) struct ssi_protocol *ssi = hsi_client_drvdata(cl); unsigned int wkres = SSIP_PAYLOAD(cmd); - spin_lock(&ssi->lock); + spin_lock_bh(&ssi->lock); if (ssi->main_state != HANDSHAKE) { dev_dbg(&cl->device, "wake lines test ignored M(%d)\n", ssi->main_state); - spin_unlock(&ssi->lock); + spin_unlock_bh(&ssi->lock); return; } - if (ssi->waketest) { - ssi->waketest = 0; + spin_unlock_bh(&ssi->lock); + + if (test_and_clear_bit(SSIP_WAKETEST_FLAG, &ssi->flags)) ssi_waketest(cl, 0); /* FIXME: To be removed */ - } + + spin_lock_bh(&ssi->lock); ssi->main_state = ACTIVE; del_timer(&ssi->tx_wd); /* Stop boot handshake timer */ - spin_unlock(&ssi->lock); + spin_unlock_bh(&ssi->lock); dev_notice(&cl->device, "WAKELINES TEST %s\n", wkres & SSIP_WAKETEST_FAILED ? "FAILED" : "OK"); @@ -741,20 +751,20 @@ static void ssip_rx_ready(struct hsi_client *cl) { struct ssi_protocol *ssi = hsi_client_drvdata(cl); - spin_lock(&ssi->lock); + spin_lock_bh(&ssi->lock); if (unlikely(ssi->main_state != ACTIVE)) { dev_dbg(&cl->device, "READY on wrong state: S(%d) M(%d)\n", ssi->send_state, ssi->main_state); - spin_unlock(&ssi->lock); + spin_unlock_bh(&ssi->lock); return; } if (ssi->send_state != WAIT4READY) { dev_dbg(&cl->device, "Ignore spurious READY command\n"); - spin_unlock(&ssi->lock); + spin_unlock_bh(&ssi->lock); return; } ssip_set_txstate(ssi, SEND_READY); - spin_unlock(&ssi->lock); + spin_unlock_bh(&ssi->lock); ssip_xmit(cl); } @@ -766,22 +776,22 @@ static void ssip_rx_strans(struct hsi_client *cl, u32 cmd) int len = SSIP_PDU_LENGTH(cmd); dev_dbg(&cl->device, "RX strans: %d frames\n", len); - spin_lock(&ssi->lock); + spin_lock_bh(&ssi->lock); if (unlikely(ssi->main_state != ACTIVE)) { dev_err(&cl->device, "START TRANS wrong state: S(%d) M(%d)\n", ssi->send_state, ssi->main_state); - spin_unlock(&ssi->lock); + spin_unlock_bh(&ssi->lock); return; } ssip_set_rxstate(ssi, RECEIVING); if (unlikely(SSIP_MSG_ID(cmd) != ssi->rxid)) { dev_err(&cl->device, "START TRANS id %d expected %d\n", SSIP_MSG_ID(cmd), ssi->rxid); - spin_unlock(&ssi->lock); + spin_unlock_bh(&ssi->lock); goto out1; } ssi->rxid++; - spin_unlock(&ssi->lock); + spin_unlock_bh(&ssi->lock); skb = netdev_alloc_skb(ssi->netdev, len * 4); if (unlikely(!skb)) { dev_err(&cl->device, "No memory for rx skb\n"); @@ -849,7 +859,7 @@ static void ssip_swbreak_complete(struct hsi_msg *msg) struct ssi_protocol *ssi = hsi_client_drvdata(cl); ssip_release_cmd(msg); - spin_lock(&ssi->lock); + spin_lock_bh(&ssi->lock); if (list_empty(&ssi->txqueue)) { if (atomic_read(&ssi->tx_usecnt)) { ssip_set_txstate(ssi, SEND_READY); @@ -857,9 +867,9 @@ static void ssip_swbreak_complete(struct hsi_msg *msg) ssip_set_txstate(ssi, SEND_IDLE); hsi_stop_tx(cl); } - spin_unlock(&ssi->lock); + spin_unlock_bh(&ssi->lock); } else { - spin_unlock(&ssi->lock); + spin_unlock_bh(&ssi->lock); ssip_xmit(cl); } netif_wake_queue(ssi->netdev); @@ -876,17 +886,17 @@ static void ssip_tx_data_complete(struct hsi_msg *msg) ssip_error(cl); goto out; } - spin_lock(&ssi->lock); + spin_lock_bh(&ssi->lock); if (list_empty(&ssi->txqueue)) { ssip_set_txstate(ssi, SENDING_SWBREAK); - spin_unlock(&ssi->lock); + spin_unlock_bh(&ssi->lock); cmsg = ssip_claim_cmd(ssi); ssip_set_cmd(cmsg, SSIP_SWBREAK_CMD); cmsg->complete = ssip_swbreak_complete; dev_dbg(&cl->device, "Send SWBREAK\n"); hsi_async_write(cl, cmsg); } else { - spin_unlock(&ssi->lock); + spin_unlock_bh(&ssi->lock); ssip_xmit(cl); } out: @@ -926,11 +936,11 @@ static int ssip_pn_open(struct net_device *dev) } dev_dbg(&cl->device, "Configuring SSI port\n"); hsi_setup(cl); - spin_lock_bh(&ssi->lock); - if (!ssi->waketest) { - ssi->waketest = 1; + + if (!test_and_set_bit(SSIP_WAKETEST_FLAG, &ssi->flags)) ssi_waketest(cl, 1); /* FIXME: To be removed */ - } + + spin_lock_bh(&ssi->lock); ssi->main_state = HANDSHAKE; spin_unlock_bh(&ssi->lock); @@ -959,6 +969,15 @@ static int ssip_pn_set_mtu(struct net_device *dev, int new_mtu) return 0; } +static void ssip_xmit_work(struct work_struct *work) +{ + struct ssi_protocol *ssi = + container_of(work, struct ssi_protocol, work); + struct hsi_client *cl = ssi->cl; + + ssip_xmit(cl); +} + static int ssip_pn_xmit(struct sk_buff *skb, struct net_device *dev) { struct hsi_client *cl = to_hsi_client(dev->dev.parent); @@ -1011,7 +1030,7 @@ static int ssip_pn_xmit(struct sk_buff *skb, struct net_device *dev) dev_dbg(&cl->device, "Start TX on SEND READY qlen %d\n", ssi->txqueue_len); spin_unlock_bh(&ssi->lock); - ssip_xmit(cl); + schedule_work(&ssi->work); } else { spin_unlock_bh(&ssi->lock); } @@ -1088,6 +1107,7 @@ static int ssi_protocol_probe(struct device *dev) atomic_set(&ssi->tx_usecnt, 0); hsi_client_set_drvdata(cl, ssi); ssi->cl = cl; + INIT_WORK(&ssi->work, ssip_xmit_work); ssi->channel_id_cmd = hsi_get_channel_id_by_name(cl, "mcsaab-control"); if (ssi->channel_id_cmd < 0) { |