>From f3c088f9e609a54140498cce27f6f12f737c870b Mon Sep 17 00:00:00 2001 From: Jacob Pan <jacob.jun.pan@xxxxxxxxx> Date: Wed, 20 May 2009 14:41:55 +0800 Subject: [PATCH] EHCI: Support Intel Moorestown EHCI controller SRAM as DMA pool caching The Intel Moorestown platform has MPH and OTG EHCI controllers that have Internal SRAM could be used as QH/QTD/ITD/SITD DMA pool caching. The SRAM are exposed via PCI BAR1. The limitation here is the SRAM access should be 32bit aligned. A separate patch "EHCI: Make ehci_qh structure items all 32bit aligned" has been submitted to linux-usb mailling list. Signed-off-by: Jacob Pan <jacob.jun.pan@xxxxxxxxx> Signed-off-by: Alek Du <alek.du@xxxxxxxxx> --- drivers/usb/core/buffer.c | 5 +++++ drivers/usb/core/hcd.h | 1 + drivers/usb/host/ehci-hcd.c | 9 ++++++++- drivers/usb/host/ehci-pci.c | 39 +++++++++++++++++++++++++++++++++++++++ drivers/usb/host/ehci.h | 8 +++++++- 5 files changed, 60 insertions(+), 2 deletions(-) diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c index 3ba2fff..ab0f462 100644 --- a/drivers/usb/core/buffer.c +++ b/drivers/usb/core/buffer.c @@ -115,6 +115,11 @@ void *hcd_buffer_alloc( return kmalloc(size, mem_flags); } + /* we won't use internal SRAM as data payload, we can't get + any benefits from it */ + if (hcd->has_sram) + return dma_alloc_coherent(NULL, size, dma, mem_flags); + for (i = 0; i < HCD_BUFFER_POOLS; i++) { if (size <= pool_max [i]) return dma_pool_alloc(hcd->pool [i], mem_flags, dma); diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index e7d4479..696fcf2 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -104,6 +104,7 @@ struct usb_hcd { unsigned wireless:1; /* Wireless USB HCD */ unsigned authorized_default:1; unsigned has_tt:1; /* Integrated TT in root hub */ + unsigned has_sram:1; /* Local SRAM for caching */ int irq; /* irq allocated */ void __iomem *regs; /* device memory/io */ diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 31122e0..d37de6b 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -106,6 +106,12 @@ static int ignore_oc = 0; module_param (ignore_oc, bool, S_IRUGO); MODULE_PARM_DESC (ignore_oc, "ignore bogus hardware overcurrent indications"); +static unsigned int sram_force_off; +module_param(sram_force_off, int, S_IRUGO); +MODULE_PARM_DESC(sram_force_off, + "force private SRAM off, otherwise SRAM will be used" + "if detected\n"); + #define INTR_MASK (STS_IAA | STS_FATAL | STS_PCD | STS_ERR | STS_INT) /*-------------------------------------------------------------------------*/ @@ -496,7 +502,8 @@ static void ehci_stop (struct usb_hcd *hcd) ehci_work (ehci); spin_unlock_irq (&ehci->lock); ehci_mem_cleanup (ehci); - + if (hcd->has_sram) + sram_deinit(hcd); #ifdef EHCI_STATS ehci_dbg (ehci, "irq normal %ld err %ld reclaim %ld (lost %ld)\n", ehci->stats.normal, ehci->stats.error, ehci->stats.reclaim, diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index e5e05b0..79eb0db 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -61,6 +61,39 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev) return 0; } +/* enable SRAM if sram detected */ +static void sram_init(struct usb_hcd *hcd) +{ + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + struct pci_dev *pdev = to_pci_dev(hcd->self.controller); + + if (!hcd->has_sram) + return; + ehci->sram_addr = pci_resource_start(pdev, 1); + ehci->sram_size = pci_resource_len(pdev, 1); + ehci_info(ehci, "Found HCD SRAM at %x size:%x\n", + ehci->sram_addr, ehci->sram_size); + if (pci_request_region(pdev, 1, kobject_name(&pdev->dev.kobj))) { + ehci_warn(ehci, "SRAM request failed\n"); + hcd->has_sram = 0; + } else if (!dma_declare_coherent_memory(&pdev->dev, ehci->sram_addr, + ehci->sram_addr, ehci->sram_size, DMA_MEMORY_MAP)) { + ehci_warn(ehci, "SRAM DMA declare failed\n"); + pci_release_region(pdev, 1); + hcd->has_sram = 0; + } +} + +static void sram_deinit(struct usb_hcd *hcd) +{ + struct pci_dev *pdev = to_pci_dev(hcd->self.controller); + + if (!hcd->has_sram) + return; + dma_release_declared_memory(&pdev->dev); + pci_release_region(pdev, 1); +} + /* called during probe() after chip reset completes */ static int ehci_pci_setup(struct usb_hcd *hcd) { @@ -91,11 +124,17 @@ static int ehci_pci_setup(struct usb_hcd *hcd) hcd->has_tt = 1; ehci->has_hostpc = 1; force_otg_hc_mode = 1; + /* enable SRAM caching if selected */ + hcd->has_sram = (sram_force_off) ? 0 : 1; + sram_init(hcd); } else if (pdev->device == 0x0806) { ehci_info(ehci, "Detected Langwell MPH\n"); ehci->no_io_watchdog = 1; hcd->has_tt = 1; ehci->has_hostpc = 1; + /* enable SRAM caching if selected */ + hcd->has_sram = (sram_force_off) ? 0 : 1; + sram_init(hcd); } } diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 3cfc3cc..cfa16ad 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -138,6 +138,8 @@ struct ehci_hcd { /* one per controller */ unsigned has_hostpc:1; u8 sbrn; /* packed release number */ + unsigned int sram_addr; + unsigned int sram_size; /* irq statistics */ #ifdef EHCI_STATS @@ -718,5 +720,9 @@ static inline u32 hc32_to_cpup (const struct ehci_hcd *ehci, const __hc32 *x) #endif /* DEBUG */ /*-------------------------------------------------------------------------*/ - +#ifdef CONFIG_PCI +static void sram_deinit(struct usb_hcd *hcd); +#else +static void sram_deinit(struct usb_hcd *hcd) { return; }; +#endif #endif /* __LINUX_EHCI_HCD_H */ -- 1.6.0.4 -- 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