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

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

 



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?


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