예제 #1
0
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;
}
예제 #2
0
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;
}
예제 #3
0
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;
}
예제 #4
0
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;
}