static void handle_thp_avl_msg(struct sqn_private *priv , struct sqn_lsp_packet *lsp) { struct sqn_sdio_card *card = priv->card; struct sk_buff *skb_reply = 0; enum sqn_thp_available_reply thp_rpl; unsigned long irq_flags = 0; sqn_pr_enter(); spin_lock_irqsave(&priv->drv_lock, irq_flags); /* if (card->is_card_sleeps) { */ if (priv->is_tx_queue_empty(priv)) { if (mmc_wimax_get_sdio_lsp_log()) { sqn_pr_info("TX queue empty, thp_rpl=FINISH\n"); } /* sqn_pr_dbg("card was asleep, thp_rpl=FINISH\n"); */ thp_rpl = LSP_THPA_FINISHED; card->is_card_sleeps = 1; gHostWakeupFWEvent = 0; /* } else if (priv->is_tx_queue_empty(priv)) { */ /* sqn_pr_dbg("card was not asleep and tx_queue is empty, thp_rpl=FINISHED\n"); */ /* thp_rpl = LSP_THPA_FINISHED; */ /* card->is_card_sleeps = 1; */ } else { /* sqn_pr_info("card was not asleep but tx_queue is no empty, thp_rpl=EXIT\n"); */ if (mmc_wimax_get_sdio_lsp_log()) { sqn_pr_info("TX queue not empty, thp_rpl=ACK\n"); } /* sqn_pr_dbg("card was not asleep, thp_rpl=ACK\n"); */ thp_rpl = LSP_THPA_ACK; card->is_card_sleeps = 0; } spin_unlock_irqrestore(&priv->drv_lock, irq_flags); skb_reply = construct_lsp_packet(THSP_THP_AVAILABLE_REPLY , ntohl(lsp->lsp_header.u.thp_avl.tid) , thp_rpl); if (0 != (skb_reply = sqn_sdio_prepare_skb_for_tx(skb_reply))) sqn_sdio_tx_skb(card, skb_reply, 0); wake_up_interruptible(&g_card_sleep_waitq); if (netif_queue_stopped(priv->dev)) netif_wake_queue(priv->dev); if (!card->is_card_sleeps && !gHostWakeupFWEvent) { gHostWakeupFWEvent = 1; // Dump next TX packet after LSP ThpAvailableReply(ACK); } sqn_pr_leave(); }
int sqn_handle_lsp_packet(struct sqn_private *priv , struct sk_buff *skb) { struct sqn_sdio_card *card = priv->card; unsigned long irq_flags = 0; struct sqn_lsp_packet *lsp_response = (struct sqn_lsp_packet*) ((u8*)skb->data + sizeof(struct sqn_eth_header)); sqn_pr_enter(); if (!sqn_is_rx_lsp_packet(skb)) { sqn_pr_dbg("not LSP packet\n"); sqn_pr_leave(); return 0; } sqn_pr_dbg("LSP packet\n"); switch (ntohl(lsp_response->lsp_header.id)) { case THSP_GET_MEDIA_CONNECTION_STATE: if (mmc_wimax_get_sdio_lsp_log()) { sqn_pr_info("RX LSP: THSP_GET_MEDIA_CONNECTION_STATE state=%xh\n" , ntohl(lsp_response->lsp_header.u.media_con_state)); } sqn_pr_warn("THSP_GET_MEDIA_CONNECTION_STATE not implemented\n"); break; case THSP_MEDIA_CONNECTION_STATE_CHANGE: if (mmc_wimax_get_sdio_lsp_log()) { sqn_pr_info("RX LSP: THSP_MEDIA_CONNECTION_STATE_CHANGE state=%xh\n" , ntohl(lsp_response->lsp_header.u.media_con_state)); } if (THSP_MEDIA_CONNECTION_ATTACHED == ntohl(lsp_response->lsp_header.u.media_con_state)) { #if IGNORE_CARRIER_STATE /* netif_carrier_on(priv->dev); */ sqn_pr_info("WiMAX carrier PRESENT [ignored]\n"); #else netif_carrier_on(priv->dev); sqn_pr_info("WiMAX carrier PRESENT\n"); #endif } else { #if IGNORE_CARRIER_STATE /* netif_carrier_off(priv->dev); */ sqn_pr_info("WiMAX carrier LOST [ignored]\n"); #else netif_carrier_off(priv->dev); sqn_pr_info("WiMAX carrier LOST\n"); #endif } break; case THSP_SET_HOST_POWER_MODE_ACK: if (mmc_wimax_get_sdio_lsp_log()) { sqn_pr_info("RX LSP: THSP_SET_HOST_POWER_MODE_ACK tid=0x%x\n" , ntohl(lsp_response->lsp_header.u.host_power.tid)); } free_last_request(); spin_lock_irqsave(&priv->drv_lock, irq_flags); card->is_card_sleeps = 1; spin_unlock_irqrestore(&priv->drv_lock, irq_flags); signal_pm_request_completion(priv); break; case THSP_SET_FW_POWER_MODE_ACK: if (mmc_wimax_get_sdio_lsp_log()) { sqn_pr_info("RX LSP: THSP_SET_FW_POWER_MODE_ACK tid=0x%x\n" , ntohl(lsp_response->lsp_header.u.fw_power.tid)); } sqn_pr_info("THSP_SET_FW_POWER_MODE_ACK not implemented\n"); break; case THSP_SQN_STATE_CHANGE: if (mmc_wimax_get_sdio_lsp_log()) { sqn_pr_info("RX LSP: THSP_SQN_STATE_CHANGE tid=0x%x, state=%xh\n" , ntohl(lsp_response->lsp_header.u.fw_state.tid) , ntohl(lsp_response->lsp_header.u.fw_state.state)); } handle_sqn_state_change_msg(priv, lsp_response); break; case THSP_THP_AVAILABLE: if (mmc_wimax_get_sdio_lsp_log()) { sqn_pr_info("RX LSP: THSP_THP_AVAILABLE tid=0x%x, reply=%xh\n" , ntohl(lsp_response->lsp_header.u.thp_avl.tid) , ntohl(lsp_response->lsp_header.u.thp_avl.reply)); } handle_thp_avl_msg(priv, lsp_response); break; default: if (mmc_wimax_get_sdio_lsp_log()) { sqn_pr_info("RX LSP: UNKNOWN=0x%x\n" , ntohl(lsp_response->lsp_header.id)); } } dev_kfree_skb_any(skb); sqn_pr_leave(); return 1; }
static struct sk_buff *lsp_to_skb(struct sqn_lsp_packet *lsp_packet) /* RX */ { struct sqn_eth_header eth_header = { .len = htons(sizeof(struct sqn_lsp_packet)) }; struct sk_buff *skb = __dev_alloc_skb(sizeof(eth_header) + sizeof(struct sqn_lsp_packet) , GFP_ATOMIC | GFP_DMA); sqn_pr_enter(); if (0 == skb) goto out; skb_reserve(skb, 2); memcpy(eth_header.dst_addr, g_lsp_device_mac, sizeof(g_lsp_device_mac)); memcpy(eth_header.src_addr, g_lsp_host_mac, sizeof(g_lsp_host_mac)); memcpy(skb->data, ð_header, sizeof(eth_header)); skb_put(skb, sizeof(eth_header)); memcpy(skb->data + skb->len, lsp_packet, sizeof(struct sqn_lsp_packet)); skb_put(skb, sizeof(struct sqn_lsp_packet)); sqn_pr_leave(); out: return skb; } static struct sk_buff* construct_lsp_packet(u32 id, u32 param1, u32 param2) { struct sqn_lsp_packet lsp_packet = { .thp_header = { .transport_version = 1 , .flags = 1 , .seq_number = 0 , .ack_number = 0 } , .lsp_header = { .id = htonl(id) } }; struct sk_buff *skb = 0; sqn_pr_enter(); switch (id) { case THSP_GET_MEDIA_CONNECTION_STATE: /* no parameters are needed */ if (mmc_wimax_get_sdio_lsp_log()) sqn_pr_info("TX LSP: THSP_GET_MEDIA_CONNECTION_STATE\n"); lsp_packet.thp_header.length = htons(sizeof(struct sqn_lsp_header) - 4); lsp_packet.thp_header.total_length = htonl(sizeof(struct sqn_lsp_header) - 4); break; case THSP_SET_POWER_MODE: /* deprecated */ if (mmc_wimax_get_sdio_lsp_log()) sqn_pr_info("TX LSP: THSP_SET_POWER_MODE (deprecated)\n"); break; case THSP_SET_HOST_POWER_MODE: lsp_packet.thp_header.length = htons(sizeof(struct sqn_lsp_header)); lsp_packet.thp_header.total_length = htonl(sizeof(struct sqn_lsp_header)); lsp_packet.lsp_header.u.host_power.tid = htonl(get_next_tid()); lsp_packet.lsp_header.u.host_power.mode = htonl(param1); if (mmc_wimax_get_sdio_lsp_log()) { sqn_pr_info("TX LSP: THSP_SET_HOST_POWER_MODE, tid: 0x%x, mode: %d\n" , ntohl(lsp_packet.lsp_header.u.host_power.tid) , param1); } break; case THSP_SET_FW_POWER_MODE: lsp_packet.thp_header.length = htons(sizeof(struct sqn_lsp_header)); lsp_packet.thp_header.total_length = htonl(sizeof(struct sqn_lsp_header)); lsp_packet.lsp_header.u.fw_power.tid = htonl(get_next_tid()); lsp_packet.lsp_header.u.fw_power.mode = htonl(param1); if (mmc_wimax_get_sdio_lsp_log()) { sqn_pr_info("TX LSP: THSP_SET_FW_POWER_MODE, tid: 0x%x, mode: %d\n" , htonl(lsp_packet.lsp_header.u.fw_power.tid) , param1); } break; case THSP_SQN_STATE_CHANGE_REPLY: lsp_packet.thp_header.length = htons(sizeof(struct sqn_lsp_header) - 4); lsp_packet.thp_header.total_length = htonl(sizeof(struct sqn_lsp_header) - 4); lsp_packet.lsp_header.u.fw_state.tid = htonl(param1); if (mmc_wimax_get_sdio_lsp_log()) { sqn_pr_info("TX LSP: THSP_SQN_STATE_CHANGE_REPLY, tid: %xh\n" , param1); } break; case THSP_THP_AVAILABLE_REPLY: lsp_packet.thp_header.length = htons(sizeof(struct sqn_lsp_header)); lsp_packet.thp_header.total_length = htonl(sizeof(struct sqn_lsp_header)); lsp_packet.lsp_header.u.thp_avl.tid = htonl(param1); lsp_packet.lsp_header.u.thp_avl.reply = htonl(param2); if (mmc_wimax_get_sdio_lsp_log()) { sqn_pr_info("TX LSP: THSP_THP_AVAILABLE_REPLY, tid: 0x%x, reply: %d\n" , param1, param2); } break; default: if (mmc_wimax_get_sdio_lsp_log()) sqn_pr_info("TX LSP: UNKNOWN\n"); } skb = lsp_to_skb(&lsp_packet); sqn_pr_leave(); return skb; }