linux/drivers/usb/host/whci/int.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Wireless Host Controller (WHC) interrupt handling.
   4 *
   5 * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
   6 */
   7#include <linux/kernel.h>
   8#include <linux/uwb/umc.h>
   9
  10#include "../../wusbcore/wusbhc.h"
  11
  12#include "whcd.h"
  13
  14static void transfer_done(struct whc *whc)
  15{
  16        queue_work(whc->workqueue, &whc->async_work);
  17        queue_work(whc->workqueue, &whc->periodic_work);
  18}
  19
  20irqreturn_t whc_int_handler(struct usb_hcd *hcd)
  21{
  22        struct wusbhc *wusbhc = usb_hcd_to_wusbhc(hcd);
  23        struct whc *whc = wusbhc_to_whc(wusbhc);
  24        u32 sts;
  25
  26        sts = le_readl(whc->base + WUSBSTS);
  27        if (!(sts & WUSBSTS_INT_MASK))
  28                return IRQ_NONE;
  29        le_writel(sts & WUSBSTS_INT_MASK, whc->base + WUSBSTS);
  30
  31        if (sts & WUSBSTS_GEN_CMD_DONE)
  32                wake_up(&whc->cmd_wq);
  33
  34        if (sts & WUSBSTS_HOST_ERR)
  35                dev_err(&whc->umc->dev, "FIXME: host system error\n");
  36
  37        if (sts & WUSBSTS_ASYNC_SCHED_SYNCED)
  38                wake_up(&whc->async_list_wq);
  39
  40        if (sts & WUSBSTS_PERIODIC_SCHED_SYNCED)
  41                wake_up(&whc->periodic_list_wq);
  42
  43        if (sts & WUSBSTS_DNTS_INT)
  44                queue_work(whc->workqueue, &whc->dn_work);
  45
  46        /*
  47         * A transfer completed (see [WHCI] section 4.7.1.2 for when
  48         * this occurs).
  49         */
  50        if (sts & (WUSBSTS_INT | WUSBSTS_ERR_INT))
  51                transfer_done(whc);
  52
  53        return IRQ_HANDLED;
  54}
  55
  56static int process_dn_buf(struct whc *whc)
  57{
  58        struct wusbhc *wusbhc = &whc->wusbhc;
  59        struct dn_buf_entry *dn;
  60        int processed = 0;
  61
  62        for (dn = whc->dn_buf; dn < whc->dn_buf + WHC_N_DN_ENTRIES; dn++) {
  63                if (dn->status & WHC_DN_STATUS_VALID) {
  64                        wusbhc_handle_dn(wusbhc, dn->src_addr,
  65                                         (struct wusb_dn_hdr *)dn->dn_data,
  66                                         dn->msg_size);
  67                        dn->status &= ~WHC_DN_STATUS_VALID;
  68                        processed++;
  69                }
  70        }
  71        return processed;
  72}
  73
  74void whc_dn_work(struct work_struct *work)
  75{
  76        struct whc *whc = container_of(work, struct whc, dn_work);
  77        int processed;
  78
  79        do {
  80                processed = process_dn_buf(whc);
  81        } while (processed);
  82}
  83