static void handle_stat0_irqs()

in gadget/udc/net2280.c [3098:3353]


static void handle_stat0_irqs(struct net2280 *dev, u32 stat)
{
	struct net2280_ep	*ep;
	u32			num, scratch;

	/* most of these don't need individual acks */
	stat &= ~BIT(INTA_ASSERTED);
	if (!stat)
		return;
	/* ep_dbg(dev, "irqstat0 %04x\n", stat); */

	/* starting a control request? */
	if (unlikely(stat & BIT(SETUP_PACKET_INTERRUPT))) {
		union {
			u32			raw[2];
			struct usb_ctrlrequest	r;
		} u;
		int				tmp;
		struct net2280_request		*req;

		if (dev->gadget.speed == USB_SPEED_UNKNOWN) {
			u32 val = readl(&dev->usb->usbstat);
			if (val & BIT(SUPER_SPEED)) {
				dev->gadget.speed = USB_SPEED_SUPER;
				usb_ep_set_maxpacket_limit(&dev->ep[0].ep,
						EP0_SS_MAX_PACKET_SIZE);
			} else if (val & BIT(HIGH_SPEED)) {
				dev->gadget.speed = USB_SPEED_HIGH;
				usb_ep_set_maxpacket_limit(&dev->ep[0].ep,
						EP0_HS_MAX_PACKET_SIZE);
			} else {
				dev->gadget.speed = USB_SPEED_FULL;
				usb_ep_set_maxpacket_limit(&dev->ep[0].ep,
						EP0_HS_MAX_PACKET_SIZE);
			}
			net2280_led_speed(dev, dev->gadget.speed);
			ep_dbg(dev, "%s\n",
					usb_speed_string(dev->gadget.speed));
		}

		ep = &dev->ep[0];
		ep->irqs++;

		/* make sure any leftover request state is cleared */
		stat &= ~BIT(ENDPOINT_0_INTERRUPT);
		while (!list_empty(&ep->queue)) {
			req = list_entry(ep->queue.next,
					struct net2280_request, queue);
			done(ep, req, (req->req.actual == req->req.length)
						? 0 : -EPROTO);
		}
		ep->stopped = 0;
		dev->protocol_stall = 0;
		if (!(dev->quirks & PLX_PCIE)) {
			if (ep->dev->quirks & PLX_2280)
				tmp = BIT(FIFO_OVERFLOW) |
				    BIT(FIFO_UNDERFLOW);
			else
				tmp = 0;

			writel(tmp | BIT(TIMEOUT) |
				   BIT(USB_STALL_SENT) |
				   BIT(USB_IN_NAK_SENT) |
				   BIT(USB_IN_ACK_RCVD) |
				   BIT(USB_OUT_PING_NAK_SENT) |
				   BIT(USB_OUT_ACK_SENT) |
				   BIT(SHORT_PACKET_OUT_DONE_INTERRUPT) |
				   BIT(SHORT_PACKET_TRANSFERRED_INTERRUPT) |
				   BIT(DATA_PACKET_RECEIVED_INTERRUPT) |
				   BIT(DATA_PACKET_TRANSMITTED_INTERRUPT) |
				   BIT(DATA_OUT_PING_TOKEN_INTERRUPT) |
				   BIT(DATA_IN_TOKEN_INTERRUPT),
				   &ep->regs->ep_stat);
		}
		u.raw[0] = readl(&dev->usb->setup0123);
		u.raw[1] = readl(&dev->usb->setup4567);

		cpu_to_le32s(&u.raw[0]);
		cpu_to_le32s(&u.raw[1]);

		if ((dev->quirks & PLX_PCIE) && !dev->bug7734_patched)
			defect7374_workaround(dev, u.r);

		tmp = 0;

#define	w_value		le16_to_cpu(u.r.wValue)
#define	w_index		le16_to_cpu(u.r.wIndex)
#define	w_length	le16_to_cpu(u.r.wLength)

		/* ack the irq */
		writel(BIT(SETUP_PACKET_INTERRUPT), &dev->regs->irqstat0);
		stat ^= BIT(SETUP_PACKET_INTERRUPT);

		/* watch control traffic at the token level, and force
		 * synchronization before letting the status stage happen.
		 * FIXME ignore tokens we'll NAK, until driver responds.
		 * that'll mean a lot less irqs for some drivers.
		 */
		ep->is_in = (u.r.bRequestType & USB_DIR_IN) != 0;
		if (ep->is_in) {
			scratch = BIT(DATA_PACKET_TRANSMITTED_INTERRUPT) |
				BIT(DATA_OUT_PING_TOKEN_INTERRUPT) |
				BIT(DATA_IN_TOKEN_INTERRUPT);
			stop_out_naking(ep);
		} else
			scratch = BIT(DATA_PACKET_RECEIVED_INTERRUPT) |
				BIT(DATA_OUT_PING_TOKEN_INTERRUPT) |
				BIT(DATA_IN_TOKEN_INTERRUPT);
		writel(scratch, &dev->epregs[0].ep_irqenb);

		/* we made the hardware handle most lowlevel requests;
		 * everything else goes uplevel to the gadget code.
		 */
		ep->responded = 1;

		if (dev->gadget.speed == USB_SPEED_SUPER) {
			handle_stat0_irqs_superspeed(dev, ep, u.r);
			goto next_endpoints;
		}

		switch (u.r.bRequest) {
		case USB_REQ_GET_STATUS: {
			struct net2280_ep	*e;
			__le32			status;

			/* hw handles device and interface status */
			if (u.r.bRequestType != (USB_DIR_IN|USB_RECIP_ENDPOINT))
				goto delegate;
			e = get_ep_by_addr(dev, w_index);
			if (!e || w_length > 2)
				goto do_stall;

			if (readl(&e->regs->ep_rsp) & BIT(SET_ENDPOINT_HALT))
				status = cpu_to_le32(1);
			else
				status = cpu_to_le32(0);

			/* don't bother with a request object! */
			writel(0, &dev->epregs[0].ep_irqenb);
			set_fifo_bytecount(ep, w_length);
			writel((__force u32)status, &dev->epregs[0].ep_data);
			allow_status(ep);
			ep_vdbg(dev, "%s stat %02x\n", ep->ep.name, status);
			goto next_endpoints;
			}
			break;
		case USB_REQ_CLEAR_FEATURE: {
			struct net2280_ep	*e;

			/* hw handles device features */
			if (u.r.bRequestType != USB_RECIP_ENDPOINT)
				goto delegate;
			if (w_value != USB_ENDPOINT_HALT || w_length != 0)
				goto do_stall;
			e = get_ep_by_addr(dev, w_index);
			if (!e)
				goto do_stall;
			if (e->wedged) {
				ep_vdbg(dev, "%s wedged, halt not cleared\n",
						ep->ep.name);
			} else {
				ep_vdbg(dev, "%s clear halt\n", e->ep.name);
				clear_halt(e);
				if ((ep->dev->quirks & PLX_PCIE) &&
					!list_empty(&e->queue) && e->td_dma)
						restart_dma(e);
			}
			allow_status(ep);
			goto next_endpoints;
			}
			break;
		case USB_REQ_SET_FEATURE: {
			struct net2280_ep	*e;

			/* hw handles device features */
			if (u.r.bRequestType != USB_RECIP_ENDPOINT)
				goto delegate;
			if (w_value != USB_ENDPOINT_HALT || w_length != 0)
				goto do_stall;
			e = get_ep_by_addr(dev, w_index);
			if (!e)
				goto do_stall;
			if (e->ep.name == ep0name)
				goto do_stall;
			set_halt(e);
			if ((dev->quirks & PLX_PCIE) && e->dma)
				abort_dma(e);
			allow_status(ep);
			ep_vdbg(dev, "%s set halt\n", ep->ep.name);
			goto next_endpoints;
			}
			break;
		default:
delegate:
			ep_vdbg(dev, "setup %02x.%02x v%04x i%04x l%04x "
				"ep_cfg %08x\n",
				u.r.bRequestType, u.r.bRequest,
				w_value, w_index, w_length,
				readl(&ep->cfg->ep_cfg));
			ep->responded = 0;
			if (dev->async_callbacks) {
				spin_unlock(&dev->lock);
				tmp = dev->driver->setup(&dev->gadget, &u.r);
				spin_lock(&dev->lock);
			}
		}

		/* stall ep0 on error */
		if (tmp < 0) {
do_stall:
			ep_vdbg(dev, "req %02x.%02x protocol STALL; stat %d\n",
					u.r.bRequestType, u.r.bRequest, tmp);
			dev->protocol_stall = 1;
		}

		/* some in/out token irq should follow; maybe stall then.
		 * driver must queue a request (even zlp) or halt ep0
		 * before the host times out.
		 */
	}

#undef	w_value
#undef	w_index
#undef	w_length

next_endpoints:
	if ((dev->quirks & PLX_PCIE) && dev->enhanced_mode) {
		u32 mask = (BIT(ENDPOINT_0_INTERRUPT) |
			USB3380_IRQSTAT0_EP_INTR_MASK_IN |
			USB3380_IRQSTAT0_EP_INTR_MASK_OUT);

		if (stat & mask) {
			usb338x_handle_ep_intr(dev, stat & mask);
			stat &= ~mask;
		}
	} else {
		/* endpoint data irq ? */
		scratch = stat & 0x7f;
		stat &= ~0x7f;
		for (num = 0; scratch; num++) {
			u32		t;

			/* do this endpoint's FIFO and queue need tending? */
			t = BIT(num);
			if ((scratch & t) == 0)
				continue;
			scratch ^= t;

			ep = &dev->ep[num];
			handle_ep_small(ep);
		}
	}

	if (stat)
		ep_dbg(dev, "unhandled irqstat0 %08x\n", stat);
}