Пример #1
0
static void iwm_sdio_isr_worker(struct work_struct *work)
{
	struct iwm_sdio_priv *hw;
	struct iwm_priv *iwm;
	struct iwm_rx_info *rx_info;
	struct sk_buff *skb;
	u8 *rx_buf;
	unsigned long rx_size;

	hw = container_of(work, struct iwm_sdio_priv, isr_worker);
	iwm = hw_to_iwm(hw);

	while (!skb_queue_empty(&iwm->rx_list)) {
		skb = skb_dequeue(&iwm->rx_list);
		rx_info = skb_to_rx_info(skb);
		rx_size = rx_info->rx_size;
		rx_buf = skb->data;

		IWM_HEXDUMP(iwm, DBG, SDIO, "RX: ", rx_buf, rx_size);
		if (iwm_rx_handle(iwm, rx_buf, rx_size) < 0)
			IWM_WARN(iwm, "RX error\n");

		kfree_skb(skb);
	}
}
Пример #2
0
static void iwm_sdio_rx_free(struct iwm_sdio_priv *hw)
{
	struct iwm_priv *iwm = hw_to_iwm(hw);

	flush_workqueue(hw->isr_wq);

	skb_queue_purge(&iwm->rx_list);
}
Пример #3
0
static void iwm_sdio_remove(struct sdio_func *func)
{
	struct iwm_sdio_priv *hw = sdio_get_drvdata(func);
	struct iwm_priv *iwm = hw_to_iwm(hw);
	struct device *dev = &func->dev;

	iwm_if_remove(iwm);
	destroy_workqueue(hw->isr_wq);
	iwm_debugfs_exit(iwm);
	iwm_if_free(iwm);

	sdio_set_drvdata(func, NULL);

	dev_info(dev, "IWM SDIO remove\n");
}
Пример #4
0
static void iwm_sdio_isr(struct sdio_func *func)
{
	struct iwm_priv *iwm;
	struct iwm_sdio_priv *hw;
	struct iwm_rx_info *rx_info;
	struct sk_buff *skb;
	unsigned long buf_size, read_size;
	int ret;
	u8 val;

	hw = sdio_get_drvdata(func);
	iwm = hw_to_iwm(hw);

	buf_size = hw->blk_size;

	/* We're checking the status */
	val = sdio_readb(func, IWM_SDIO_INTR_STATUS_ADDR, &ret);
	if (val == 0 || ret < 0) {
		IWM_ERR(iwm, "Wrong INTR_STATUS\n");
		return;
	}

	/* See if we have free buffers */
	if (skb_queue_len(&iwm->rx_list) > IWM_RX_LIST_SIZE) {
		IWM_ERR(iwm, "No buffer for more Rx frames\n");
		return;
	}

	/* We first read the transaction size */
	read_size = sdio_readb(func, IWM_SDIO_INTR_GET_SIZE_ADDR + 1, &ret);
	read_size = read_size << 8;

	if (ret < 0) {
		IWM_ERR(iwm, "Couldn't read the xfer size\n");
		return;
	}

	/* We need to clear the INT register */
	sdio_writeb(func, 1, IWM_SDIO_INTR_CLEAR_ADDR, &ret);
	if (ret < 0) {
		IWM_ERR(iwm, "Couldn't clear the INT register\n");
		return;
	}

	while (buf_size < read_size)
		buf_size <<= 1;

	skb = dev_alloc_skb(buf_size);
	if (!skb) {
		IWM_ERR(iwm, "Couldn't alloc RX skb\n");
		return;
	}
	rx_info = skb_to_rx_info(skb);
	rx_info->rx_size = read_size;
	rx_info->rx_buf_size = buf_size;

	/* Now we can read the actual buffer */
	ret = sdio_memcpy_fromio(func, skb_put(skb, read_size),
				 IWM_SDIO_DATA_ADDR, read_size);

	/* The skb is put on a driver's specific Rx SKB list */
	skb_queue_tail(&iwm->rx_list, skb);

	/* We can now schedule the actual worker */
	queue_work(hw->isr_wq, &hw->isr_worker);
}
Пример #5
0
static void iwm_sdio_isr(struct sdio_func *func)
{
	struct iwm_priv *iwm;
	struct iwm_sdio_priv *hw;
	struct iwm_rx_info *rx_info;
	struct sk_buff *skb;
	unsigned long buf_size, read_size;
	int ret;
	u8 val;

	hw = sdio_get_drvdata(func);
	iwm = hw_to_iwm(hw);

	buf_size = hw->blk_size;

	
	val = sdio_readb(func, IWM_SDIO_INTR_STATUS_ADDR, &ret);
	if (val == 0 || ret < 0) {
		IWM_ERR(iwm, "Wrong INTR_STATUS\n");
		return;
	}

	
	if (skb_queue_len(&iwm->rx_list) > IWM_RX_LIST_SIZE) {
		IWM_ERR(iwm, "No buffer for more Rx frames\n");
		return;
	}

	
	read_size = sdio_readb(func, IWM_SDIO_INTR_GET_SIZE_ADDR + 1, &ret);
	read_size = read_size << 8;

	if (ret < 0) {
		IWM_ERR(iwm, "Couldn't read the xfer size\n");
		return;
	}

	
	sdio_writeb(func, 1, IWM_SDIO_INTR_CLEAR_ADDR, &ret);
	if (ret < 0) {
		IWM_ERR(iwm, "Couldn't clear the INT register\n");
		return;
	}

	while (buf_size < read_size)
		buf_size <<= 1;

	skb = dev_alloc_skb(buf_size);
	if (!skb) {
		IWM_ERR(iwm, "Couldn't alloc RX skb\n");
		return;
	}
	rx_info = skb_to_rx_info(skb);
	rx_info->rx_size = read_size;
	rx_info->rx_buf_size = buf_size;

	
	ret = sdio_memcpy_fromio(func, skb_put(skb, read_size),
				 IWM_SDIO_DATA_ADDR, read_size);

	
	skb_queue_tail(&iwm->rx_list, skb);

	
	queue_work(hw->isr_wq, &hw->isr_worker);
}