int sqn_notify_host_sleep(struct sdio_func *func) { int rv = 0; unsigned long irq_flags = 0; u32 timeout = 0; struct sqn_sdio_card *sqn_card = sdio_get_drvdata(func); sqn_pr_enter(); sqn_card->waiting_pm_notification = 1; sqn_pr_info("notify card about host goes to sleep...\n"); sqn_set_host_power_mode(func, LSP_HPM_ASLEEP); timeout = 50; sqn_pr_info("wait for completion (timeout %u msec)...\n", timeout); rv = wait_event_interruptible_timeout(sqn_card->pm_waitq , sqn_card->pm_complete, msecs_to_jiffies(timeout)); if (-ERESTARTSYS == rv) { sqn_pr_warn("got a signal from kernel %d\n", rv); } else if (0 == rv) { /* a timeout elapsed */ sqn_pr_warn("timeout elapsed - still no ack from card" ", assume that card in sleep mode now\n"); sqn_card->is_card_sleeps = 1; } else { /* we got an ack from card */ sqn_pr_info("card in sleep mode now\n"); sqn_card->is_card_sleeps = 1; rv = 0; } sqn_card->pm_complete = 0; sqn_card->waiting_pm_notification = 0; sqn_pr_leave(); return rv; }
static int is_good_ahb_address(u32 address, enum sqn_card_version card_version) { u32 sdram_base = 0; u32 sdram_end = 0; u32 sdram_ctl_base = 0; u32 sdram_ctl_end = 0; int status = 0; sqn_pr_enter(); if (address % 4) return 0; if (SQN_1130 == card_version) { sqn_pr_dbg("using 1130 AHB address boundaries\n"); sdram_base = SQN_1130_SDRAM_BASE; sdram_end = SQN_1130_SDRAM_END; sdram_ctl_base = SQN_1130_SDRAMCTL_BASE; sdram_ctl_end = SQN_1130_SDRAMCTL_END; } else if (SQN_1210 == card_version) { sqn_pr_dbg("using 1210 AHB address boundaries\n"); sdram_base = SQN_1210_SDRAM_BASE; sdram_end = SQN_1210_SDRAM_END; sdram_ctl_base = SQN_1210_SDRAMCTL_BASE; sdram_ctl_end = SQN_1210_SDRAMCTL_END; } else { sqn_pr_warn("Can't check AHB address because of unknown" " card version\n"); status = 0; goto out; } status = ((sdram_base <= address && address < sdram_end) || (sdram_ctl_base <= address && address < sdram_ctl_end)); out: sqn_pr_leave(); return status; }
int sqn_wakeup_fw(struct sdio_func *func) { int rv = 0; int ver = 0; int counter = 0; int retry_cnt = 3; u32 wakeup_delay = 0; unsigned long timeout = msecs_to_jiffies(800); unsigned long irq_flags = 0; struct sqn_private *priv = ((struct sqn_sdio_card *)sdio_get_drvdata(func))->priv; struct sqn_sdio_card *card = priv->card; u8 need_to_unlock_wakelock = 0; sqn_pr_enter(); sqn_pr_info("waking up the card...\n"); if (!wake_lock_active(&card->wakelock_tx)) { if (mmc_wimax_get_sdio_wakelock_log()) { printk(KERN_INFO "[WIMAX] lock wl_tx2,"); PRINTRTC; } wake_lock(&card->wakelock_tx); need_to_unlock_wakelock = 1; } retry: if (priv->removed) goto out; sdio_claim_host(func); #define SDIO_CCCR_CCCR_SDIO_VERSION_VALUE 0x11 wakeup_delay = 2; counter = 5; do { sqn_pr_dbg("CMD52 #%d, delay %d msec\n", counter, wakeup_delay); ver = sdio_readb(func, SDIO_CCCR_CCCR_SDIO_VERSION, &rv); // To avoid FW sutck in PLLOFF, SDIO isn't able to wake up it. mdelay(wakeup_delay); --counter; } while((rv || ver != SDIO_CCCR_CCCR_SDIO_VERSION_VALUE) && counter > 0); if (rv) { sqn_pr_err("error when reading SDIO_VERSION\n"); if (mmc_wimax_get_wimax_FW_freeze_WK_TX()) { sqn_pr_info("[ste]set is_card_sleeps 0 to avoid TX polling\n"); card->is_card_sleeps = 0; } sdio_release_host(func); goto out; } else sqn_pr_dbg("SDIO_VERSION has been read successfully\n"); sqn_pr_dbg("send wake-up signal to card\n"); sdio_writeb(func, 1, SQN_SOC_SIGS_LSBS, &rv); if (rv) sqn_pr_err("error when writing to SQN_SOC_SIGS_LSBS: %d\n", rv); sdio_release_host(func); sqn_pr_info("wait for completion (timeout %d msec)...\n" , jiffies_to_msecs(timeout)); rv = wait_event_interruptible_timeout(g_card_sleep_waitq , 0 == card->is_card_sleeps || priv->removed, timeout); if (priv->removed) goto out; if (-ERESTARTSYS == rv) { sqn_pr_warn("got a signal from kernel %d\n", rv); } else if (0 == rv) { rv = -1; sqn_pr_err("can't wake up the card - timeout elapsed\n"); if (retry_cnt-- > 0 && card->is_card_sleeps) { sqn_pr_info("retry wake up\n"); goto retry; } sqn_pr_info("giving up to wake up the card\n"); spin_lock_irqsave(&priv->drv_lock, irq_flags); card->is_card_sleeps = 0; spin_unlock_irqrestore(&priv->drv_lock, irq_flags); } else { rv = 0; sqn_pr_info("card is waked up successfully\n"); } out: if (need_to_unlock_wakelock && wake_lock_active(&card->wakelock_tx)) { if (mmc_wimax_get_sdio_wakelock_log()) { printk(KERN_INFO "[WIMAX] release wake_lock_tx in %s,", __func__); PRINTRTC; } wake_unlock(&card->wakelock_tx); /* TX */ } sqn_pr_leave(); return rv; }
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; }