Пример #1
0
irqreturn_t whc_int_handler(struct usb_hcd *hcd)
{
	struct wusbhc *wusbhc = usb_hcd_to_wusbhc(hcd);
	struct whc *whc = wusbhc_to_whc(wusbhc);
	u32 sts;

	sts = le_readl(whc->base + WUSBSTS);
	if (!(sts & WUSBSTS_INT_MASK))
		return IRQ_NONE;
	le_writel(sts & WUSBSTS_INT_MASK, whc->base + WUSBSTS);

	if (sts & WUSBSTS_GEN_CMD_DONE)
		wake_up(&whc->cmd_wq);

	if (sts & WUSBSTS_HOST_ERR)
		dev_err(&whc->umc->dev, "FIXME: host system error\n");

	if (sts & WUSBSTS_ASYNC_SCHED_SYNCED)
		wake_up(&whc->async_list_wq);

	if (sts & WUSBSTS_PERIODIC_SCHED_SYNCED)
		wake_up(&whc->periodic_list_wq);

	if (sts & WUSBSTS_DNTS_INT)
		queue_work(whc->workqueue, &whc->dn_work);

	
	if (sts & (WUSBSTS_INT | WUSBSTS_ERR_INT))
		transfer_done(whc);

	return IRQ_HANDLED;
}
Пример #2
0
/**
 * Execute an UWB RC command on WHCI/RC
 *
 * @rc:       Instance of a Radio Controller that is a whcrc
 * @cmd:      Buffer containing the RCCB and payload to execute
 * @cmd_size: Size of the command buffer.
 *
 * We copy the command into whcrc->cmd_buf (as it is pretty and
 * aligned`and physically contiguous) and then press the right keys in
 * the controller's URCCMD register to get it to read it. We might
 * have to wait for the cmd_sem to be open to us.
 *
 * NOTE: rc's mutex has to be locked
 */
static int whcrc_cmd(struct uwb_rc *uwb_rc,
	      const struct uwb_rccb *cmd, size_t cmd_size)
{
	int result = 0;
	struct whcrc *whcrc = uwb_rc->priv;
	struct device *dev = &whcrc->umc_dev->dev;
	u32 urccmd;

	if (cmd_size >= 4096)
		return -EINVAL;

	/*
	 * If the URC is halted, then the hardware has reset itself.
	 * Attempt to recover by restarting the device and then return
	 * an error as it's likely that the current command isn't
	 * valid for a newly started RC.
	 */
	if (le_readl(whcrc->rc_base + URCSTS) & URCSTS_HALTED) {
		dev_err(dev, "requesting reset of halted radio controller\n");
		uwb_rc_reset_all(uwb_rc);
		return -EIO;
	}

	result = wait_event_timeout(whcrc->cmd_wq,
		!(le_readl(whcrc->rc_base + URCCMD) & URCCMD_ACTIVE), HZ/2);
	if (result == 0) {
		dev_err(dev, "device is not ready to execute commands\n");
		return -ETIMEDOUT;
	}

	memmove(whcrc->cmd_buf, cmd, cmd_size);
	le_writeq(whcrc->cmd_dma_buf, whcrc->rc_base + URCCMDADDR);

	spin_lock(&whcrc->irq_lock);
	urccmd = le_readl(whcrc->rc_base + URCCMD);
	urccmd &= ~(URCCMD_EARV | URCCMD_SIZE_MASK);
	le_writel(urccmd | URCCMD_ACTIVE | URCCMD_IWR | cmd_size,
		  whcrc->rc_base + URCCMD);
	spin_unlock(&whcrc->irq_lock);

	return 0;
}
Пример #3
0
/**
 * Reset event reception mechanism and tell hw we are ready to get more
 *
 * We have read all the events in the event buffer, so we are ready to
 * reset it to the beginning.
 *
 * This is only called during initialization or after an event buffer
 * has been retired.  This means we can be sure that event processing
 * is disabled and it's safe to update the URCEVTADDR register.
 *
 * There's no need to wait for the event processing to start as the
 * URC will not clear URCCMD_ACTIVE until (internal) event buffer
 * space is available.
 */
static
void whcrc_enable_events(struct whcrc *whcrc)
{
	u32 urccmd;

	le_writeq(whcrc->evt_dma_buf, whcrc->rc_base + URCEVTADDR);

	spin_lock(&whcrc->irq_lock);
	urccmd = le_readl(whcrc->rc_base + URCCMD) & ~URCCMD_ACTIVE;
	le_writel(urccmd | URCCMD_EARV, whcrc->rc_base + URCCMD);
	spin_unlock(&whcrc->irq_lock);
}
Пример #4
0
void whc_wusbhc_stop(struct wusbhc *wusbhc, int delay)
{
	struct whc *whc = wusbhc_to_whc(wusbhc);
	u32 stop_time, now_time;
	int ret;

	pzl_stop(whc);
	asl_stop(whc);

	now_time = le_readl(whc->base + WUSBTIME) & WUSBTIME_CHANNEL_TIME_MASK;
	stop_time = (now_time + ((delay * 8) << 7)) & 0x00ffffff;
	ret = whc_do_gencmd(whc, WUSBGENCMDSTS_CHAN_STOP, stop_time, NULL, 0);
	if (ret == 0)
		msleep(delay);
}
Пример #5
0
/**
 * Catch interrupts?
 *
 * We ack inmediately (and expect the hw to do the right thing and
 * raise another IRQ if things have changed :)
 */
static
irqreturn_t whcrc_irq_cb(int irq, void *_whcrc)
{
	struct whcrc *whcrc = _whcrc;
	struct device *dev = &whcrc->umc_dev->dev;
	u32 urcsts;

	urcsts = le_readl(whcrc->rc_base + URCSTS);
	if (!(urcsts & URCSTS_INT_MASK))
		return IRQ_NONE;
	le_writel(urcsts & URCSTS_INT_MASK, whcrc->rc_base + URCSTS);

	if (urcsts & URCSTS_HSE) {
		dev_err(dev, "host system error -- hardware halted\n");
		/* FIXME: do something sensible here */
		goto out;
	}
	if (urcsts & URCSTS_ER)
		schedule_work(&whcrc->event_work);
	if (urcsts & URCSTS_RCI)
		wake_up_all(&whcrc->cmd_wq);
out:
	return IRQ_HANDLED;
}
Пример #6
0
int whc_init(struct whc *whc)
{
	u32 whcsparams;
	int ret, i;
	resource_size_t start, len;

	spin_lock_init(&whc->lock);
	mutex_init(&whc->mutex);
	init_waitqueue_head(&whc->cmd_wq);
	init_waitqueue_head(&whc->async_list_wq);
	init_waitqueue_head(&whc->periodic_list_wq);
	whc->workqueue = alloc_ordered_workqueue(dev_name(&whc->umc->dev), 0);
	if (whc->workqueue == NULL) {
		ret = -ENOMEM;
		goto error;
	}
	INIT_WORK(&whc->dn_work, whc_dn_work);

	INIT_WORK(&whc->async_work, scan_async_work);
	INIT_LIST_HEAD(&whc->async_list);
	INIT_LIST_HEAD(&whc->async_removed_list);

	INIT_WORK(&whc->periodic_work, scan_periodic_work);
	for (i = 0; i < 5; i++)
		INIT_LIST_HEAD(&whc->periodic_list[i]);
	INIT_LIST_HEAD(&whc->periodic_removed_list);

	/* Map HC registers. */
	start = whc->umc->resource.start;
	len   = whc->umc->resource.end - start + 1;
	if (!request_mem_region(start, len, "whci-hc")) {
		dev_err(&whc->umc->dev, "can't request HC region\n");
		ret = -EBUSY;
		goto error;
	}
	whc->base_phys = start;
	whc->base = ioremap(start, len);
	if (!whc->base) {
		dev_err(&whc->umc->dev, "ioremap\n");
		ret = -ENOMEM;
		goto error;
	}

	whc_hw_reset(whc);

	/* Read maximum number of devices, keys and MMC IEs. */
	whcsparams = le_readl(whc->base + WHCSPARAMS);
	whc->n_devices = WHCSPARAMS_TO_N_DEVICES(whcsparams);
	whc->n_keys    = WHCSPARAMS_TO_N_KEYS(whcsparams);
	whc->n_mmc_ies = WHCSPARAMS_TO_N_MMC_IES(whcsparams);

	dev_dbg(&whc->umc->dev, "N_DEVICES = %d, N_KEYS = %d, N_MMC_IES = %d\n",
		whc->n_devices, whc->n_keys, whc->n_mmc_ies);

	whc->qset_pool = dma_pool_create("qset", &whc->umc->dev,
					 sizeof(struct whc_qset), 64, 0);
	if (whc->qset_pool == NULL) {
		ret = -ENOMEM;
		goto error;
	}

	ret = asl_init(whc);
	if (ret < 0)
		goto error;
	ret = pzl_init(whc);
	if (ret < 0)
		goto error;

	/* Allocate and initialize a buffer for generic commands, the
	   Device Information buffer, and the Device Notification
	   buffer. */

	whc->gen_cmd_buf = dma_alloc_coherent(&whc->umc->dev, WHC_GEN_CMD_DATA_LEN,
					      &whc->gen_cmd_buf_dma, GFP_KERNEL);
	if (whc->gen_cmd_buf == NULL) {
		ret = -ENOMEM;
		goto error;
	}

	whc->dn_buf = dma_alloc_coherent(&whc->umc->dev,
					 sizeof(struct dn_buf_entry) * WHC_N_DN_ENTRIES,
					 &whc->dn_buf_dma, GFP_KERNEL);
	if (!whc->dn_buf) {
		ret = -ENOMEM;
		goto error;
	}
	whc_hw_init_dn_buf(whc);

	whc->di_buf = dma_alloc_coherent(&whc->umc->dev,
					 sizeof(struct di_buf_entry) * whc->n_devices,
					 &whc->di_buf_dma, GFP_KERNEL);
	if (!whc->di_buf) {
		ret = -ENOMEM;
		goto error;
	}
	whc_hw_init_di_buf(whc);

	return 0;

error:
	whc_clean_up(whc);
	return ret;
}