RE: [PATCH RESEND] EHCI: AMD periodic frame list table quirk

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



> -----Original Message-----
> From: David Brownell [mailto:david-b@xxxxxxxxxxx]
> Sent: Monday, November 08, 2010 11:36 PM
> To: Xu, Andiry
> Cc: linux-usb@xxxxxxxxxxxxxxx; gregkh@xxxxxxx
> Subject: Re: [PATCH RESEND] EHCI: AMD periodic frame list table quirk
> 
> Thanks for adding the comment to explain that quirk to future patch
> developers...
> 
> My ack is below; I still haven't got time to closely eyeball it, but
it
> seems clean enough, and any issues would look to be easily shaken out.
> 
> SB700 -- that's current stuff, so this would count as a bugfix that
> should merge soonish ... correct?
> 

Yes, that's correct. Thanks for ack this.

> 
> On Mon, 2010-11-08 at 17:58 +0800, Andiry Xu wrote:
> > >From 021f633dc60f89f8fb94783b3494e06e8c496ebb Mon Sep 17 00:00:00
2001
> > From: Andiry Xu <andiry.xu@xxxxxxx>
> > Date: Mon, 8 Nov 2010 15:32:20 +0800
> > Subject: [PATCH] EHCI: AMD periodic frame list table quirk
> >
> > On AMD SB700/SB800/Hudson-2/3 platforms, USB EHCI controller may
> read/write
> > to memory space not allocated to USB controller if there is longer
than
> > normal latency on DMA read encountered. In this condition the
exposure
> will
> > be encountered only if the driver has following format of Periodic
Frame
> > List link pointer structure:
> >
> > For any idle periodic schedule, the Frame List link pointers that
have
> the
> > T-bit set to 1 intending to terminate the use of frame list link
pointer
> > as a physical memory pointer.
> >
> > Idle periodic schedule Frame List Link pointer shoule be in the
> following
> > format to avoid the issue:
> >
> > Frame list link pointer should be always contains a valid pointer to
a
> > inactive QHead with T-bit set to 0.
> >
> > Signed-off-by: Andiry Xu <andiry.xu@xxxxxxx>
> Acked-by: David Brownell <dbrownell@xxxxxxxxxxxxxxxxxxxxx>
> 
> > ---
> >  drivers/usb/host/ehci-mem.c   |   26 ++++++++++++++++++++++++--
> >  drivers/usb/host/ehci-pci.c   |   13 +++++++++++++
> >  drivers/usb/host/ehci-sched.c |   21 ++++++++++++++++++---
> >  drivers/usb/host/ehci.h       |    2 ++
> >  4 files changed, 57 insertions(+), 5 deletions(-)
> >
> > diff --git a/drivers/usb/host/ehci-mem.c
b/drivers/usb/host/ehci-mem.c
> > index d36e4e7..12f70c3 100644
> > --- a/drivers/usb/host/ehci-mem.c
> > +++ b/drivers/usb/host/ehci-mem.c
> > @@ -141,6 +141,10 @@ static void ehci_mem_cleanup (struct ehci_hcd
*ehci)
> >  		qh_put (ehci->async);
> >  	ehci->async = NULL;
> >
> > +	if (ehci->dummy)
> > +		qh_put(ehci->dummy);
> > +	ehci->dummy = NULL;
> > +
> >  	/* DMA consistent memory and pools */
> >  	if (ehci->qtd_pool)
> >  		dma_pool_destroy (ehci->qtd_pool);
> > @@ -227,8 +231,26 @@ static int ehci_mem_init (struct ehci_hcd
*ehci,
> gfp_t flags)
> >  	if (ehci->periodic == NULL) {
> >  		goto fail;
> >  	}
> > -	for (i = 0; i < ehci->periodic_size; i++)
> > -		ehci->periodic [i] = EHCI_LIST_END(ehci);
> > +
> > +	if (ehci->use_dummy_qh) {
> > +		struct ehci_qh_hw	*hw;
> > +		ehci->dummy = ehci_qh_alloc(ehci, flags);
> > +		if (!ehci->dummy)
> > +			goto fail;
> > +
> > +		hw = ehci->dummy->hw;
> > +		hw->hw_next = EHCI_LIST_END(ehci);
> > +		hw->hw_qtd_next = EHCI_LIST_END(ehci);
> > +		hw->hw_alt_next = EHCI_LIST_END(ehci);
> > +		hw->hw_token &= ~QTD_STS_ACTIVE;
> > +		ehci->dummy->hw = hw;
> > +
> > +		for (i = 0; i < ehci->periodic_size; i++)
> > +			ehci->periodic[i] = ehci->dummy->qh_dma;
> > +	} else {
> > +		for (i = 0; i < ehci->periodic_size; i++)
> > +			ehci->periodic[i] = EHCI_LIST_END(ehci);
> > +	}
> >
> >  	/* software shadow of hardware table */
> >  	ehci->pshadow = kcalloc(ehci->periodic_size, sizeof(void *),
flags);
> > diff --git a/drivers/usb/host/ehci-pci.c
b/drivers/usb/host/ehci-pci.c
> > index a1e8d27..01bb72b 100644
> > --- a/drivers/usb/host/ehci-pci.c
> > +++ b/drivers/usb/host/ehci-pci.c
> > @@ -103,6 +103,19 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
> >  	if (retval)
> >  		return retval;
> >
> > +	if ((pdev->vendor == PCI_VENDOR_ID_AMD && pdev->device ==
0x7808) ||
> > +	    (pdev->vendor == PCI_VENDOR_ID_ATI && pdev->device ==
0x4396)) {
> > +		/* EHCI controller on AMD SB700/SB800/Hudson-2/3
platforms may
> > +		 * read/write memory space which does not belong to it
when
> > +		 * there is NULL pointer with T-bit set to 1 in the
frame list
> > +		 * table. To avoid the issue, the frame list link
pointer
> > +		 * should always contain a valid pointer to a inactive
qh.
> > +		 */
> > +		ehci->use_dummy_qh = 1;
> > +		ehci_info(ehci, "applying AMD SB700/SB800/Hudson-2/3
EHCI "
> > +				"dummy qh workaround\n");
> > +	}
> > +
> >  	/* data structure init */
> >  	retval = ehci_init(hcd);
> >  	if (retval)
> > diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-
> sched.c
> > index a92526d..d9f78eb 100644
> > --- a/drivers/usb/host/ehci-sched.c
> > +++ b/drivers/usb/host/ehci-sched.c
> > @@ -98,7 +98,14 @@ static void periodic_unlink (struct ehci_hcd
*ehci,
> unsigned frame, void *ptr)
> >  	 */
> >  	*prev_p = *periodic_next_shadow(ehci, &here,
> >  			Q_NEXT_TYPE(ehci, *hw_p));
> > -	*hw_p = *shadow_next_periodic(ehci, &here, Q_NEXT_TYPE(ehci,
*hw_p));
> > +
> > +	if (!ehci->use_dummy_qh ||
> > +	    *shadow_next_periodic(ehci, &here, Q_NEXT_TYPE(ehci, *hw_p))
> > +			!= EHCI_LIST_END(ehci))
> > +		*hw_p = *shadow_next_periodic(ehci, &here,
> > +				Q_NEXT_TYPE(ehci, *hw_p));
> > +	else
> > +		*hw_p = ehci->dummy->qh_dma;
> >  }
> >
> >  /* how many of the uframe's 125 usecs are allocated? */
> > @@ -2335,7 +2342,11 @@ restart:
> >  				 * pointer for much longer, if at all.
> >  				 */
> >  				*q_p = q.itd->itd_next;
> > -				*hw_p = q.itd->hw_next;
> > +				if (!ehci->use_dummy_qh ||
> > +				    q.itd->hw_next !=
EHCI_LIST_END(ehci))
> > +					*hw_p = q.itd->hw_next;
> > +				else
> > +					*hw_p = ehci->dummy->qh_dma;
> >  				type = Q_NEXT_TYPE(ehci,
q.itd->hw_next);
> >  				wmb();
> >  				modified = itd_complete (ehci, q.itd);
> > @@ -2368,7 +2379,11 @@ restart:
> >  				 * URB completion.
> >  				 */
> >  				*q_p = q.sitd->sitd_next;
> > -				*hw_p = q.sitd->hw_next;
> > +				if (!ehci->use_dummy_qh ||
> > +				    q.sitd->hw_next !=
EHCI_LIST_END(ehci))
> > +					*hw_p = q.sitd->hw_next;
> > +				else
> > +					*hw_p = ehci->dummy->qh_dma;
> >  				type = Q_NEXT_TYPE(ehci,
q.sitd->hw_next);
> >  				wmb();
> >  				modified = sitd_complete (ehci, q.sitd);
> > diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
> > index bde823f..ba8eab3 100644
> > --- a/drivers/usb/host/ehci.h
> > +++ b/drivers/usb/host/ehci.h
> > @@ -73,6 +73,7 @@ struct ehci_hcd {			/* one per
> controller */
> >
> >  	/* async schedule support */
> >  	struct ehci_qh		*async;
> > +	struct ehci_qh		*dummy;		/* For AMD quirk use */
> >  	struct ehci_qh		*reclaim;
> >  	unsigned		scanning : 1;
> >
> > @@ -131,6 +132,7 @@ struct ehci_hcd {			/* one
per
> controller */
> >  	unsigned		need_io_watchdog:1;
> >  	unsigned		broken_periodic:1;
> >  	unsigned		fs_i_thresh:1;	/* Intel iso scheduling
*/
> > +	unsigned		use_dummy_qh:1;	/* AMD Frame List table
quirk*/
> >
> >  	/* required for usb32 quirk */
> >  	#define OHCI_CTRL_HCFS          (3 << 6)
> 
> 
> 


--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux