Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b18d26f6 authored by Sebastian Andrzej Siewior's avatar Sebastian Andrzej Siewior Committed by Felipe Balbi
Browse files

usb: musb: Perform only write access on MUSB_INTRTXE



This is part of the workaround for AM35x advisory Advisory 1.1.20.
The advisory says that the IPSS bridge can't handle 8 & 16 bit read
access. An 16bit read access to MUSB_INTRTXE results in an 32bit read
access which also reads INTRRX and therefore may lose interrupts.
This patch uses a shadow register of MUSB_INTRTXE so we only perform
write access to it.

Signed-off-by: default avatarSebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: default avatarFelipe Balbi <balbi@ti.com>
parent af5ec14d
Loading
Loading
Loading
Loading
+6 −4
Original line number Diff line number Diff line
@@ -724,7 +724,8 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
		if (is_peripheral_active(musb)) {
			/* REVISIT HNP; just force disconnect */
		}
		musb_writew(musb->mregs, MUSB_INTRTXE, musb->epmask);
		musb->intrtxe = musb->epmask;
		musb_writew(musb->mregs, MUSB_INTRTXE, musb->intrtxe);
		musb->intrrxe = musb->epmask & 0xfffe;
		musb_writew(musb->mregs, MUSB_INTRRXE, musb->intrrxe);
		musb_writeb(musb->mregs, MUSB_INTRUSBE, 0xf7);
@@ -947,7 +948,8 @@ void musb_start(struct musb *musb)
	dev_dbg(musb->controller, "<== devctl %02x\n", devctl);

	/*  Set INT enable registers, enable interrupts */
	musb_writew(regs, MUSB_INTRTXE, musb->epmask);
	musb->intrtxe = musb->epmask;
	musb_writew(regs, MUSB_INTRTXE, musb->intrtxe);
	musb->intrrxe = musb->epmask & 0xfffe;
	musb_writew(regs, MUSB_INTRRXE, musb->intrrxe);
	musb_writeb(regs, MUSB_INTRUSBE, 0xf7);
@@ -987,6 +989,7 @@ static void musb_generic_disable(struct musb *musb)

	/* disable interrupts */
	musb_writeb(mbase, MUSB_INTRUSBE, 0);
	musb->intrtxe = 0;
	musb_writew(mbase, MUSB_INTRTXE, 0);
	musb->intrrxe = 0;
	musb_writew(mbase, MUSB_INTRRXE, 0);
@@ -2124,7 +2127,6 @@ static void musb_save_context(struct musb *musb)
	musb->context.testmode = musb_readb(musb_base, MUSB_TESTMODE);
	musb->context.busctl = musb_read_ulpi_buscontrol(musb->mregs);
	musb->context.power = musb_readb(musb_base, MUSB_POWER);
	musb->context.intrtxe = musb_readw(musb_base, MUSB_INTRTXE);
	musb->context.intrusbe = musb_readb(musb_base, MUSB_INTRUSBE);
	musb->context.index = musb_readb(musb_base, MUSB_INDEX);
	musb->context.devctl = musb_readb(musb_base, MUSB_DEVCTL);
@@ -2197,7 +2199,7 @@ static void musb_restore_context(struct musb *musb)
	musb_writeb(musb_base, MUSB_TESTMODE, musb->context.testmode);
	musb_write_ulpi_buscontrol(musb->mregs, musb->context.busctl);
	musb_writeb(musb_base, MUSB_POWER, musb->context.power);
	musb_writew(musb_base, MUSB_INTRTXE, musb->context.intrtxe);
	musb_writew(musb_base, MUSB_INTRTXE, musb->intrtxe);
	musb_writew(musb_base, MUSB_INTRRXE, musb->intrrxe);
	musb_writeb(musb_base, MUSB_INTRUSBE, musb->context.intrusbe);
	musb_writeb(musb_base, MUSB_DEVCTL, musb->context.devctl);
+1 −1
Original line number Diff line number Diff line
@@ -288,7 +288,6 @@ struct musb_csr_regs {
struct musb_context_registers {

	u8 power;
	u16 intrtxe;
	u8 intrusbe;
	u16 frame;
	u8 index, testmode;
@@ -314,6 +313,7 @@ struct musb {
	u16			hwvers;

	u16			intrrxe;
	u16			intrtxe;
/* this hub status bit is reserved by USB 2.0 and not seen by usbcore */
#define MUSB_PORT_STAT_RESUME	(1 << 31)

+7 −10
Original line number Diff line number Diff line
@@ -1068,7 +1068,6 @@ static int musb_gadget_enable(struct usb_ep *ep,
	 */
	musb_ep_select(mbase, epnum);
	if (usb_endpoint_dir_in(desc)) {
		u16 int_txe = musb_readw(mbase, MUSB_INTRTXE);

		if (hw_ep->is_shared_fifo)
			musb_ep->is_in = 1;
@@ -1080,8 +1079,8 @@ static int musb_gadget_enable(struct usb_ep *ep,
			goto fail;
		}

		int_txe |= (1 << epnum);
		musb_writew(mbase, MUSB_INTRTXE, int_txe);
		musb->intrtxe |= (1 << epnum);
		musb_writew(mbase, MUSB_INTRTXE, musb->intrtxe);

		/* REVISIT if can_bulk_split(), use by updating "tmp";
		 * likewise high bandwidth periodic tx
@@ -1208,9 +1207,8 @@ static int musb_gadget_disable(struct usb_ep *ep)

	/* zero the endpoint sizes */
	if (musb_ep->is_in) {
		u16 int_txe = musb_readw(musb->mregs, MUSB_INTRTXE);
		int_txe &= ~(1 << epnum);
		musb_writew(musb->mregs, MUSB_INTRTXE, int_txe);
		musb->intrtxe &= ~(1 << epnum);
		musb_writew(musb->mregs, MUSB_INTRTXE, musb->intrtxe);
		musb_writew(epio, MUSB_TXMAXP, 0);
	} else {
		musb->intrrxe &= ~(1 << epnum);
@@ -1530,7 +1528,7 @@ static void musb_gadget_fifo_flush(struct usb_ep *ep)
	void __iomem	*epio = musb->endpoints[epnum].regs;
	void __iomem	*mbase;
	unsigned long	flags;
	u16		csr, int_txe;
	u16		csr;

	mbase = musb->mregs;

@@ -1538,8 +1536,7 @@ static void musb_gadget_fifo_flush(struct usb_ep *ep)
	musb_ep_select(mbase, (u8) epnum);

	/* disable interrupts */
	int_txe = musb_readw(mbase, MUSB_INTRTXE);
	musb_writew(mbase, MUSB_INTRTXE, int_txe & ~(1 << epnum));
	musb_writew(mbase, MUSB_INTRTXE, musb->intrtxe & ~(1 << epnum));

	if (musb_ep->is_in) {
		csr = musb_readw(epio, MUSB_TXCSR);
@@ -1563,7 +1560,7 @@ static void musb_gadget_fifo_flush(struct usb_ep *ep)
	}

	/* re-enable interrupt */
	musb_writew(mbase, MUSB_INTRTXE, int_txe);
	musb_writew(mbase, MUSB_INTRTXE, musb->intrtxe);
	spin_unlock_irqrestore(&musb->lock, flags);
}

+1 −1
Original line number Diff line number Diff line
@@ -740,7 +740,7 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
		csr = musb_readw(epio, MUSB_TXCSR);

		/* disable interrupt in case we flush */
		int_txe = musb_readw(mbase, MUSB_INTRTXE);
		int_txe = musb->intrtxe;
		musb_writew(mbase, MUSB_INTRTXE, int_txe & ~(1 << epnum));

		/* general endpoint setup */