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; }
/** * 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; }
/** * 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); }
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); }
/** * 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; }
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; }