From c5189140fa758c447b6638695745ff5924e122a7 Mon Sep 17 00:00:00 2001 From: Shibby Date: Thu, 17 Oct 2013 20:45:17 +0200 Subject: [PATCH] New routers supported BIG THANKS FOR @tvlz for patches New routers: - Rosewill L600N - Untested but in Tomatanon - D-Link Dir-620 C1 - Untested but in Tomatanon - Linksys E800 - same as E900 - Asus RT-N10P - tested - Asus RT-N53 A1 (boardrev 0x1446) - untested but only minor changes Minor fixes and updates: - USBAP nvram - updated settings - Fast-EHCI - this one adds USB cacheing for USBAP Radios - code from Asus Big thanks once again! --- .../arch/mips/brcm-boards/bcm947xx/pcibios.c | 106 ++++---- .../linux/linux-2.6/drivers/usb/host/ehci-hcd.c | 294 ++++++++++++++++++--- .../linux/linux-2.6/drivers/usb/host/ehci-hub.c | 111 ++++++++ .../linux/linux-2.6/drivers/usb/host/ehci-q.c | 168 +++++++++++- .../linux/linux-2.6/drivers/usb/host/ehci-sched.c | 17 +- .../src-rt/linux/linux-2.6/drivers/usb/host/ehci.h | 94 ++++++- release/src/Makefile | 10 +- release/src/router/rc/buttons.c | 18 ++ release/src/router/rc/init.c | 86 +++++- release/src/router/rc/mtd.c | 1 + release/src/router/rc/usb.c | 19 ++ release/src/router/shared/id.c | 23 ++ release/src/router/shared/led.c | 16 ++ release/src/router/shared/shared.h | 4 + release/src/router/www/advanced-vlan.asp | 36 ++- 15 files changed, 880 insertions(+), 123 deletions(-) diff --git a/release/src-rt/linux/linux-2.6/arch/mips/brcm-boards/bcm947xx/pcibios.c b/release/src-rt/linux/linux-2.6/arch/mips/brcm-boards/bcm947xx/pcibios.c index b79187396e..674a130116 100644 --- a/release/src-rt/linux/linux-2.6/arch/mips/brcm-boards/bcm947xx/pcibios.c +++ b/release/src-rt/linux/linux-2.6/arch/mips/brcm-boards/bcm947xx/pcibios.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include #include @@ -44,6 +43,12 @@ extern si_t *bcm947xx_sih; extern spinlock_t bcm947xx_sih_lock; +/* Global USB capability */ +int usb_hsic_cap = 0; +int usb_hsic_cap_port = 0; +EXPORT_SYMBOL(usb_hsic_cap); +EXPORT_SYMBOL(usb_hsic_cap_port); + /* Convenience */ #define sih bcm947xx_sih #define sih_lock bcm947xx_sih_lock @@ -231,9 +236,9 @@ int pcibios_enable_device(struct pci_dev *dev, int mask) { ulong flags; - uint coreidx; + uint coreidx, coreid; void *regs; - uint32 tmp; + int rc = -1; /* External PCI device enable */ if (dev->bus->number != 0) @@ -248,8 +253,10 @@ pcibios_enable_device(struct pci_dev *dev, int mask) spin_lock_irqsave(&sih_lock, flags); coreidx = si_coreidx(sih); regs = si_setcoreidx(sih, PCI_SLOT(dev->devfn)); - if (!regs) - return PCIBIOS_DEVICE_NOT_FOUND; + if (!regs) { + printk("WARNING! PCIBIOS_DEVICE_NOT_FOUND\n"); + goto out; + } /* * The USB core requires a special bit to be set during core @@ -260,7 +267,7 @@ pcibios_enable_device(struct pci_dev *dev, int mask) * should know about SB and should reset the bit back to 0 * after calling pcibios_enable_device(). */ - if (si_coreid(sih) == USB_CORE_ID) { + if ((coreid = si_coreid(sih)) == USB_CORE_ID) { si_core_disable(sih, si_core_cflags(sih, 0, 0)); si_core_reset(sih, 1 << 29, 0); } @@ -274,12 +281,12 @@ pcibios_enable_device(struct pci_dev *dev, int mask) * Register must be programmed to bring the USB core and various * phy components out of reset. */ - else if (si_coreid(sih) == USB20H_CORE_ID) { + else if (coreid == USB20H_CORE_ID) { if (!si_iscoreup(sih)) { si_core_reset(sih, 0, 0); - // USB hungup issue from broadcom 2009.6.24 mdelay(10); if (si_corerev(sih) >= 5) { + uint32 tmp; /* Enable Misc PLL */ tmp = readl(regs + 0x1e0); tmp |= 0x100; @@ -312,6 +319,7 @@ pcibios_enable_device(struct pci_dev *dev, int mask) 0xc000), 100000); if ((tmp & 0xc000) != 0xc000) { printk("WARNING! USB20H mdio_rddata 0x%08x\n", tmp); + goto out; } writel(0x80000000, regs + 0x528); tmp = readl(regs + 0x314); @@ -321,72 +329,68 @@ pcibios_enable_device(struct pci_dev *dev, int mask) /* Take USB and HSIC out of non-driving modes */ writel(0, regs + 0x510); + } else if (si_corerev(sih) >= 3) { + uint32 tmp = readl(regs + 0x50c); + udelay(50); + /* make sure pll lock is on */ + if (!(tmp & 0x1000000)) { + goto out; + } + writel(0x7ff, regs + 0x200); + udelay(1); } else { writel(0x7ff, regs + 0x200); udelay(1); } } + /* PRxxxx: War for 5354 failures. */ + if (si_corerev(sih) == 1) { + uint32 tmp; - /* War for 5354 failures. */ - if ((sih->chip == BCM5354_CHIP_ID) && (si_corerev(sih) == 1 || si_corerev(sih) == 2)) { /* Change Flush control reg */ tmp = readl(regs + 0x400); tmp &= ~8; writel(tmp, regs + 0x400); + tmp = readl(regs + 0x400); + printk("USB20H fcr: 0x%x\n", tmp); /* Change Shim control reg */ tmp = readl(regs + 0x304); tmp &= ~0x100; writel(tmp, regs + 0x304); - - /* Change Syn01 reg */ - tmp = 0x00fe00fe; - writel(tmp, regs + 0x894); - - /* Change Syn03 reg */ - tmp = 0x1; - writel(tmp, regs + 0x89c); - - udelay(1); + tmp = readl(regs + 0x304); + printk("USB20H shim cr: 0x%x\n", tmp); } - - /* War for 4716 failures. */ - if (sih->chip == BCM4716_CHIP_ID) { - uint32 delay = 500; - uint32 val = 0; - uint32 clk_freq; - - clk_freq = si_cpu_clock(sih); - if(clk_freq == 480000000) - val = 0x1846b; - else if (clk_freq == 453000000) - val = 0x1046b; - - /* Change Shim mdio control reg to fix host not acking at high frequencies - */ - if (val) { - writel(val, regs + 0x524); - udelay(delay); - writel(0x4ab, regs + 0x524); - udelay(delay); - tmp = readl(regs + 0x528); - udelay(delay); - writel(val, regs + 0x524); - udelay(delay); - writel(0x4ab, regs + 0x524); - udelay(delay); - tmp = readl(regs + 0x528); - //printk("USB20H mdio control register : 0x%x\n", tmp); - } + if (si_corerev(sih) == 5) { + usb_hsic_cap = 1; + usb_hsic_cap_port = 2; } - } else si_core_reset(sih, 0, 0); + /* Initialize USBHC core OK */ + rc = 0; +out: si_setcoreidx(sih, coreidx); spin_unlock_irqrestore(&sih_lock, flags); - return 0; +#if 0 + /* Reset the device */ + if (coreid == USB20H_CORE_ID || coreid == USB_CORE_ID) { + int wombo_reset = GPIO_PIN_NOTDEFINED; + if ((wombo_reset = getgpiopin(NULL, "wombo_reset", GPIO_PIN_NOTDEFINED)) != + GPIO_PIN_NOTDEFINED) { + int reset = 1 << wombo_reset; + printk("wombo_reset set to gpio %d\n", wombo_reset); + si_gpioout(sih, reset, 0, GPIO_DRV_PRIORITY); + si_gpioouten(sih, reset, reset, GPIO_DRV_PRIORITY); + mdelay(50); + si_gpioout(sih, reset, reset, GPIO_DRV_PRIORITY); + mdelay(20); + } + } +#endif + return rc; } void diff --git a/release/src-rt/linux/linux-2.6/drivers/usb/host/ehci-hcd.c b/release/src-rt/linux/linux-2.6/drivers/usb/host/ehci-hcd.c index 0cbe18e8f7..2240cd9cc4 100644 --- a/release/src-rt/linux/linux-2.6/drivers/usb/host/ehci-hcd.c +++ b/release/src-rt/linux/linux-2.6/drivers/usb/host/ehci-hcd.c @@ -265,6 +265,15 @@ static int ehci_reset (struct ehci_hcd *ehci) return retval; } +static int ehci_optimized(struct ehci_hcd *ehci, struct ehci_qh *qh) +{ + int p; + for (p = 0; p < 3; ++p) + if (ehci->ehci_pipes[p] == qh) + return p; + return -1; +} + /* idle the controller (from running) */ static void ehci_quiesce (struct ehci_hcd *ehci) { @@ -304,6 +313,196 @@ static void ehci_work(struct ehci_hcd *ehci); /*-------------------------------------------------------------------------*/ +static int qtdc_pid = 0; +module_param (qtdc_pid, int, S_IRUGO); +MODULE_PARM_DESC (qtdc_pid, "qtd cache device pid"); + +static int qtdc_vid = 0; +module_param (qtdc_vid, int, S_IRUGO); +MODULE_PARM_DESC (qtdc_vid, "qtd cache device vid"); + +static int qtdc0_ep = -1; /* turn off qtd cache by default */ +module_param (qtdc0_ep, int, S_IRUGO); +MODULE_PARM_DESC (qtdc0_ep, "qtd cache 0 endpoint"); + +static int qtdc0_sz = 0; /* turn off qtd cache by default */ +module_param (qtdc0_sz, int, S_IRUGO); +MODULE_PARM_DESC (qtdc0_sz, "qtd cache 0 size (# of qtd's)"); + +static int qtdc0_to = 1; +module_param (qtdc0_to, int, S_IRUGO); +MODULE_PARM_DESC (qtdc0_to, "qtd cache 0 timeout (ms)"); + +static int qtdc1_ep = -1; /* turn off qtd cache by default */ +module_param (qtdc1_ep, int, S_IRUGO); +MODULE_PARM_DESC (qtdc1_ep, "qtd cache 1 endpoint"); + +static int qtdc1_sz = 0; /* turn off qtd cache by default */ +module_param (qtdc1_sz, int, S_IRUGO); +MODULE_PARM_DESC (qtdc1_sz, "qtd cache 1 size (# of qtd's)"); + +static int qtdc1_to = 1; +module_param (qtdc1_to, int, S_IRUGO); +MODULE_PARM_DESC (qtdc1_to, "qtd cache 1 timeout (ms)"); + +static int qtdc0_ml = QTDC_MSG_ERR; +module_param (qtdc0_ml, int, S_IRUGO); +MODULE_PARM_DESC (qtdc0_ml, "qtd cache 0 msglevel"); + +static int qtdc1_ml = QTDC_MSG_ERR; +module_param (qtdc1_ml, int, S_IRUGO); +MODULE_PARM_DESC (qtdc1_ml, "qtd cache 1 msglevel"); + +#ifdef EHCI_QTD_CACHE +static void ehci_qtdc_watchdog (unsigned long param) +{ + ehci_qtdc_t *qtdc = (ehci_qtdc_t*) param; + struct ehci_hcd *ehci = (struct ehci_hcd *)(qtdc->ehci); + unsigned long flags, flags2; + struct ehci_qtd *qtd; + struct urb *urb = NULL; + //struct hcd_dev *dev; + int epnum; + struct usb_host_endpoint *ep; + struct list_head *entry; + struct ehci_qh *qh = 0; + + spin_lock_irqsave (&ehci->lock, flags); + + if (unlikely (qtdc->cnt <= 0)) + goto done; + +#ifdef EHCI_QTDC_DEBUG + if (unlikely (list_empty(&qtdc->cache))) + QTDC_ERR(qtdc, ("cnt %d but cache empty\n", qtdc->cnt)); +#endif /* EHCI_QTDC_DEBUG */ + + QTDC_TRACE(qtdc, ("watchdog release! cnt %d\n", qtdc->cnt)); + list_for_each (entry, &qtdc->cache) { + qtd = list_entry (entry, struct ehci_qtd, qtd_list); + urb = qtd->urb; + spin_lock_irqsave (&urb->lock, flags2); + urb->transfer_flags &= ~URB_QTD_CACHED; + spin_unlock_irqrestore (&urb->lock, flags2); + } +// dev = (struct hcd_dev *)urb->dev->hcpriv; + epnum = usb_pipeendpoint (urb->pipe); + if (usb_pipeout(urb->pipe)) { + WARN_ON(usb_pipein(urb->pipe)); + ep = urb->dev->ep_out[epnum]; + } else { + WARN_ON(usb_pipeout(urb->pipe)); + ep = urb->dev->ep_in[epnum]; + } + if (usb_pipein (urb->pipe) && !usb_pipecontrol (urb->pipe)) + epnum |= 0x10; + +#ifdef EHCI_QTDC_DEBUG + qtdc->timeout_qtd += qtdc->cnt; + if (qtdc->cnt > qtdc->timeout_qtd_max) + qtdc->timeout_qtd_max = qtdc->cnt; + qtdc->timeout_cnt++; + if ((jiffies - qtdc->last_printed) > (10 * HZ)) { + QTDC_STATS(qtdc, ("cached_qtd %lu\nrelease_qtd %lu release_cnt %lu\n" + "timeout_qtd %lu timeout_qtd_max %lu timeout_cnt %lu avg_timeout_qtd %lu\n", + qtdc->cached_qtd, qtdc->release_qtd, qtdc->release_cnt, + qtdc->timeout_qtd, qtdc->timeout_qtd_max, qtdc->timeout_cnt, + (qtdc->timeout_qtd / qtdc->timeout_cnt))); + qtdc->last_printed = jiffies; + } +#endif /* EHCI_QTDC_DEBUG */ + qtdc->cnt = 0; + + qh = qh_append_tds (ehci, urb, &qtdc->cache, epnum, &ep->hcpriv); + /* Control/bulk operations through TTs don't need scheduling, + * the HC and TT handle it when the TT has a buffer ready. + */ + if (likely (qh != 0)) { + if (likely (qh->qh_state == QH_STATE_IDLE)) + qh_link_async (ehci, qh_get (qh)); + } + + /* clean up qtd cache */ + INIT_LIST_HEAD(&qtdc->cache); + +done: + spin_unlock_irqrestore (&ehci->lock, flags); + return; +} + +ehci_qtdc_t *ehci_qtdc_init(struct ehci_hcd *ehci, int vid, int pid, int num, int ep, int size, int timeout, unsigned int msglevel) +{ + ehci_qtdc_t *qtdc; + + if (pid == 0 || vid == 0) { + ehci_err (ehci, "pid %x vid %x not valid\n", pid, vid); + return NULL; + } + + if (num >= NUM_QTD_CACHE) { + ehci_err (ehci, "qtdc %d exceeding limit %d\n", num, NUM_QTD_CACHE); + return NULL; + } + + if ((ep < 0) || (ep > 0x1f)) { + ehci_err (ehci, "qtdc %d disabled: invalid ep 0x%x\n", num, ep); + return NULL; + } + + if (size <= 0) { + ehci_err (ehci, "qtdc %d disabled: invalid size %d\n", num, size); + return NULL; + } + + if (timeout <= 0) { + ehci_err (ehci, "qtdc %d disabled: invalid timeout %d\n", num, timeout); + return NULL; + } + + qtdc = kmalloc(sizeof(ehci_qtdc_t), GFP_KERNEL); + if (!qtdc) { + ehci_err (ehci, "qtdc %d disabled: alloc failed\n", num); + return NULL; + } + + memset(qtdc, 0, sizeof(ehci_qtdc_t)); + + ehci->qtdc_vid = vid; + ehci->qtdc_pid = pid; + qtdc->ehci = (void*)ehci; + qtdc->num = num; + qtdc->ep = ep; + qtdc->size = size; + qtdc->timeout = (timeout * HZ) / 1000; /* in ms */ +#ifdef EHCI_QTDC_DEBUG + qtdc->msglevel = msglevel; +#endif /* EHCI_QTDC_DEBUG */ + + INIT_LIST_HEAD(&qtdc->cache); + + init_timer (&qtdc->watchdog); + qtdc->watchdog.function = ehci_qtdc_watchdog; + qtdc->watchdog.data = (unsigned long) qtdc; + + ehci_info (ehci, "qtdc %d enabled: vid %x pid %x ep 0x%x size %d timeout %d\n", + num, vid, pid, ep, size, timeout); + + return qtdc; +} + +void ehci_qtdc_deinit(ehci_qtdc_t* qtdc) +{ + if (list_empty(&qtdc->cache)) + BUG(); + kfree(qtdc); +} +#endif /* EHCI_QTD_CACHE */ + + + + +/*-------------------------------------------------------------------------*/ + static void ehci_iaa_watchdog(unsigned long param) { struct ehci_hcd *ehci = (struct ehci_hcd *) param; @@ -476,7 +675,11 @@ static void ehci_stop (struct usb_hcd *hcd) /* no more interrupts ... */ del_timer_sync (&ehci->watchdog); del_timer_sync(&ehci->iaa_watchdog); - +#ifdef EHCI_QTD_CACHE + del_timer_sync (&ehci->qtdc_watchdog); + ehci_qtdc_deinit (ehci->qtdc[0]); + ehci_qtdc_deinit (ehci->qtdc[1]); +#endif /* EHCI_QTD_CACHE */ spin_lock_irq(&ehci->lock); if (HC_IS_RUNNING (hcd->state)) ehci_quiesce (ehci); @@ -516,6 +719,8 @@ static int ehci_init(struct usb_hcd *hcd) u32 hcc_params; struct ehci_qh_hw *hw; + ehci_info(ehci, "EHCI Fastpath: New EHCI driver starting\n"); + spin_lock_init(&ehci->lock); /* @@ -526,12 +731,17 @@ static int ehci_init(struct usb_hcd *hcd) ehci->watchdog.function = ehci_watchdog; ehci->watchdog.data = (unsigned long) ehci; +#ifdef EHCI_QTD_CACHE + ehci->qtdc[0] = ehci_qtdc_init(ehci, qtdc_vid, qtdc_pid, 0, qtdc0_ep, qtdc0_sz, qtdc0_to, qtdc0_ml); + ehci->qtdc[1] = ehci_qtdc_init(ehci, qtdc_vid, qtdc_pid, 1, qtdc1_ep, qtdc1_sz, qtdc1_to, qtdc1_ml); +#endif /* EHCI_QTD_CACHE */ + + + init_timer(&ehci->iaa_watchdog); ehci->iaa_watchdog.function = ehci_iaa_watchdog; ehci->iaa_watchdog.data = (unsigned long) ehci; - hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params); - /* * hw default: 1K periodic list heads, one per frame. * periodic_size can shrink by USBCMD update if hcc_params allows. @@ -539,20 +749,11 @@ static int ehci_init(struct usb_hcd *hcd) ehci->periodic_size = DEFAULT_I_TDPS; INIT_LIST_HEAD(&ehci->cached_itd_list); INIT_LIST_HEAD(&ehci->cached_sitd_list); - - if (HCC_PGM_FRAMELISTLEN(hcc_params)) { - /* periodic schedule size can be smaller than default */ - switch (EHCI_TUNE_FLS) { - case 0: ehci->periodic_size = 1024; break; - case 1: ehci->periodic_size = 512; break; - case 2: ehci->periodic_size = 256; break; - default: BUG(); - } - } if ((retval = ehci_mem_init(ehci, GFP_KERNEL)) < 0) return retval; /* controllers may cache some of the periodic schedule ... */ + hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params); if (HCC_ISOC_CACHE(hcc_params)) // full frame cache ehci->i_thresh = 2 + 8; else // N microframes cached @@ -601,6 +802,12 @@ static int ehci_init(struct usb_hcd *hcd) /* periodic schedule size can be smaller than default */ temp &= ~(3 << 2); temp |= (EHCI_TUNE_FLS << 2); + switch (EHCI_TUNE_FLS) { + case 0: ehci->periodic_size = 1024; break; + case 1: ehci->periodic_size = 512; break; + case 2: ehci->periodic_size = 256; break; + default: BUG(); + } } ehci->command = temp; @@ -919,6 +1126,14 @@ static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) // case PIPE_CONTROL: // case PIPE_BULK: default: +#ifdef EHCI_QTD_CACHE + if (urb->transfer_flags & URB_QTD_CACHED) { + if (ehci_qtdc_unlink(ehci, urb, NULL)) + err ("%s: can't dequeue urb %p from qtdc", __FUNCTION__, urb); + break; + } +#endif /* EHCI_QTD_CACHE */ + qh = (struct ehci_qh *) urb->hcpriv; if (!qh) break; @@ -1110,42 +1325,48 @@ static int __init ehci_hcd_init(void) #ifdef PLATFORM_DRIVER retval = platform_driver_register(&PLATFORM_DRIVER); - if (retval < 0) - goto clean0; + if (retval < 0) { +#ifdef DEBUG + debugfs_remove(ehci_debug_root); + ehci_debug_root = NULL; +#endif + return retval; + } #endif #ifdef PCI_DRIVER retval = pci_register_driver(&PCI_DRIVER); - if (retval < 0) - goto clean1; + if (retval < 0) { +#ifdef DEBUG + debugfs_remove(ehci_debug_root); + ehci_debug_root = NULL; +#endif +#ifdef PLATFORM_DRIVER + platform_driver_unregister(&PLATFORM_DRIVER); +#endif + return retval; + } #endif #ifdef PS3_SYSTEM_BUS_DRIVER retval = ps3_ehci_driver_register(&PS3_SYSTEM_BUS_DRIVER); - if (retval < 0) - goto clean2; + if (retval < 0) { +#ifdef DEBUG + debugfs_remove(ehci_debug_root); + ehci_debug_root = NULL; #endif - - return retval; - -#ifdef PS3_SYSTEM_BUS_DRIVER - ps3_ehci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); -clean2: +#ifdef PLATFORM_DRIVER + platform_driver_unregister(&PLATFORM_DRIVER); #endif #ifdef PCI_DRIVER - pci_unregister_driver(&PCI_DRIVER); -clean1: -#endif -#ifdef PLATFORM_DRIVER - platform_driver_unregister(&PLATFORM_DRIVER); -clean0: + pci_unregister_driver(&PCI_DRIVER); #endif -#ifdef DEBUG - debugfs_remove(ehci_debug_root); - ehci_debug_root = NULL; err_debug: -#endif clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded); + return retval; + } +#endif + return retval; } module_init(ehci_hcd_init); @@ -1168,3 +1389,6 @@ static void __exit ehci_hcd_cleanup(void) } module_exit(ehci_hcd_cleanup); + + + diff --git a/release/src-rt/linux/linux-2.6/drivers/usb/host/ehci-hub.c b/release/src-rt/linux/linux-2.6/drivers/usb/host/ehci-hub.c index d9b33a241a..6feddb25c7 100644 --- a/release/src-rt/linux/linux-2.6/drivers/usb/host/ehci-hub.c +++ b/release/src-rt/linux/linux-2.6/drivers/usb/host/ehci-hub.c @@ -17,6 +17,10 @@ */ /* this file is part of ehci-hcd.c */ +static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh); +static struct ehci_qh *qh_make (struct ehci_hcd *ehci, struct urb *urb, gfp_t flags); +static inline void ehci_qtd_init (struct ehci_hcd *ehci, struct ehci_qtd *qtd, dma_addr_t dma); +static inline void ehci_qtd_free (struct ehci_hcd *ehci, struct ehci_qtd *qtd); /*-------------------------------------------------------------------------*/ @@ -580,6 +584,7 @@ static int ehci_hub_control ( u32 __iomem *status_reg = &ehci->regs->port_status[ (wIndex & 0xff) - 1]; u32 temp, status; + u32 hcc_params; unsigned long flags; int retval = 0; unsigned selector; @@ -905,6 +910,110 @@ static int ehci_hub_control ( ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */ break; + /* EHCI fastpath acceleration */ + /* Use parameters instead of buffer to avoid core modifications */ + case EHCI_SET_BYPASS_CB: + ehci->ehci_bypass_callback = (void (*)(int, struct ehci_qh *, spinlock_t *lock))(wValue | (wIndex << 16)); + ehci_info(ehci, "EHCI Fastpath: Got the bypass callback command in EHCI %p\n", ehci->ehci_bypass_callback); + break; + case EHCI_SET_BYPASS_DEV: + hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params); + if (HCC_64BIT_ADDR (hcc_params)) { + ehci_info(ehci, "EHCI Fastpath: EHCI 64bit addressing mode not supported\n"); + goto error; + } + ehci->bypass_device = (struct usb_device *)(wValue | (wIndex << 16)); + ehci_info(ehci, "EHCI Fastpath: Got the bypass device command in EHCI %p\n", ehci->bypass_device); + break; + case EHCI_SET_EP_BYPASS: + { + struct urb dummy_urb; + /* In/out bit mask is 0x10 */ + int pipe = wValue; + int pipeindex = wIndex; + struct usb_device *udev = ehci->bypass_device; + struct ehci_qh *qh; + int usb_pipe; + bool pipeout = ((pipe&0x10) == 0); + + struct usb_host_endpoint *ep; + + ehci_info(ehci, "EHCI Fastpath: Got the RH bypass command in EHCI for EP #%d %04x\n", pipeindex, pipe); + + pipe &= 0xf; + ep = pipeout ? udev->ep_out[pipe] : udev->ep_in[pipe]; + usb_pipe = pipeout ? usb_sndbulkpipe(udev, pipe) : usb_rcvbulkpipe(udev, pipe); + + usb_fill_bulk_urb(&dummy_urb, ehci->bypass_device, usb_pipe, NULL, 0, NULL, NULL); + + qh = qh_make(ehci, &dummy_urb, GFP_ATOMIC); + + if (ehci->fastpath_pool != NULL) { + dma_addr_t dma; + + ehci_info(ehci, "EHCI Fastpath: release native dummy qtd and alloc new one\n"); + ehci_qtd_free (ehci, qh->dummy); + + qh->dummy = dma_pool_alloc (ehci->fastpath_pool, GFP_ATOMIC, &dma); + if (qh->dummy != NULL) + ehci_qtd_init (ehci, qh->dummy, dma); + else + printk("re-alloc dummy qtd from fastpath_pool error !!\n"); + } + + ep->hcpriv = qh; + qh->first_qtd = qh->dummy; + + ehci_info(ehci, "EHCI Fastpath: EP %p QH %p dummy %p\n", ep, qh, qh->dummy); + + /* Start the QH */ + qh_link_async (ehci, qh); + + /* Detach the QH */ + qh->qh_state = QH_STATE_DETACHED; + + /* Save the pipe pointer */ + ehci->ehci_pipes[pipeindex] = qh; + + } + break; + + case EHCI_DUMP_STATE: + { + int sts = ehci_readl(ehci, &ehci->regs->status); + + printk("EHCI IRQ status %08x\n", sts); + printk("EHCI INT status %08x\n", ehci->regs->intr_enable); + } + break; + + case EHCI_SET_BYPASS_POOL: + ehci->fastpath_pool= (struct dma_pool *)(wValue | (wIndex << 16)); + ehci_info(ehci, "EHCI Fastpath: Got the bypass fastpath pool command in EHCI %p\n", ehci->fastpath_pool); + break; + + case EHCI_CLR_EP_BYPASS: + { + int idx; + + /* reset callback func and bapass dev */ + ehci->ehci_bypass_callback = NULL; + ehci->bypass_device = NULL; + + /* freeing qh and qtd info */ + for (idx = 0; idx < 3; idx++) { + printk("%d freeing \n", idx); + if (ehci->ehci_pipes[idx] != NULL) { + struct ehci_qh *rm_qh = ehci->ehci_pipes[idx]; + struct ehci_qtd *rm_qtd= ehci->ehci_pipes[idx]->dummy; + + dma_pool_free(ehci->fastpath_pool, rm_qtd, rm_qtd->qtd_dma); + dma_pool_free(ehci->qh_pool, rm_qh, rm_qh->qh_dma); + ehci->ehci_pipes[idx] = NULL; + } + } + } + break; default: error: /* "stall" on error */ @@ -933,3 +1042,5 @@ static int ehci_port_handed_over(struct usb_hcd *hcd, int portnum) reg = &ehci->regs->port_status[portnum - 1]; return ehci_readl(ehci, reg) & PORT_OWNER; } + + diff --git a/release/src-rt/linux/linux-2.6/drivers/usb/host/ehci-q.c b/release/src-rt/linux/linux-2.6/drivers/usb/host/ehci-q.c index 2b4ca61d5c..9e02d8d5c1 100644 --- a/release/src-rt/linux/linux-2.6/drivers/usb/host/ehci-q.c +++ b/release/src-rt/linux/linux-2.6/drivers/usb/host/ehci-q.c @@ -103,7 +103,7 @@ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd) if (!(hw->hw_info1 & cpu_to_hc32(ehci, 1 << 14))) { unsigned is_out, epnum; - is_out = qh->is_out; + is_out = !(qtd->hw_token & cpu_to_hc32(ehci, 1 << 8)); epnum = (hc32_to_cpup(ehci, &hw->hw_info1) >> 8) & 0x0f; if (unlikely (!usb_gettoggle (qh->dev, epnum, is_out))) { hw->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE); @@ -269,6 +269,59 @@ __acquires(ehci->lock) spin_lock (&ehci->lock); } +#ifdef EHCI_QTD_CACHE +static unsigned +ehci_qtdc_unlink (struct ehci_hcd *ehci, struct urb *unlink, struct pt_regs *regs) +{ + struct list_head *entry, *tmp; + unsigned ret = -ENOENT; + unsigned long flags; + int i; + + spin_lock_irqsave (&ehci->lock, flags); + + for (i = 0; i < NUM_QTD_CACHE; i++) { + ehci_qtdc_t *qtdc_this = ehci->qtdc[i]; + + /* skip if cache empty or found in previous cache */ + if (unlikely (!qtdc_this || list_empty(&qtdc_this->cache)) || (ret == 0)) + continue; + + list_for_each_safe (entry, tmp, &qtdc_this->cache) { + struct ehci_qtd *qtd; + struct urb *urb; + unsigned long flags; + + qtd = list_entry (entry, struct ehci_qtd, qtd_list); + urb = qtd->urb; + + if (likely (urb != unlink)) + continue; + + if (qtd->qtd_list.prev != &qtdc_this->cache) { + struct ehci_qtd *last = 0; + last = list_entry (qtd->qtd_list.prev, + struct ehci_qtd, qtd_list); + last->hw_next = qtd->hw_next; + } + list_del (&qtd->qtd_list); + spin_lock_irqsave (&urb->lock, flags); + urb->transfer_flags &= ~URB_QTD_CACHED; + spin_unlock_irqrestore (&urb->lock, flags); + ehci_urb_done (ehci, urb); + ehci_qtd_free (ehci, qtd); + ret = 0; + + break; + } + } + + spin_unlock_irqrestore (&ehci->lock, flags); + return ret; +} +#endif /* EHCI_QTD_CACHE */ + + static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh); static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh); @@ -288,6 +341,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) int stopped; unsigned count = 0; u8 state; + const __le32 halt = HALT_BIT(ehci); struct ehci_qh_hw *hw = qh->hw; if (unlikely (list_empty (&qh->qtd_list))) @@ -394,6 +448,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) && !(qtd->hw_alt_next & EHCI_LIST_END(ehci))) { stopped = 1; + goto halt; } /* stop scanning when we reach qtds the hc is using */ @@ -420,6 +475,16 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) && cpu_to_hc32(ehci, qtd->qtd_dma) == hw->hw_current) token = hc32_to_cpu(ehci, hw->hw_token); + + /* force halt for unlinked or blocked qh, so we'll + * patch the qh later and so that completions can't + * activate it while we "know" it's stopped. + */ + if ((halt & hw->hw_token) == 0) { +halt: + hw->hw_token |= halt; + wmb (); + } } /* unless we already know the urb's status, collect qtd status @@ -751,7 +816,6 @@ qh_make ( is_input, 0, hb_mult(maxp) * max_packet(maxp))); qh->start = NO_FRAME; - qh->stamp = ehci->periodic_stamp; if (urb->dev->speed == USB_SPEED_HIGH) { qh->c_usecs = 0; @@ -871,7 +935,6 @@ done: hw = qh->hw; hw->hw_info1 = cpu_to_hc32(ehci, info1); hw->hw_info2 = cpu_to_hc32(ehci, info2); - qh->is_out = !is_input; usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1); qh_refresh (ehci, qh); return qh; @@ -946,6 +1009,13 @@ static struct ehci_qh *qh_append_tds ( qh = qh_make (ehci, urb, GFP_ATOMIC); *ptr = qh; } + + if(ehci_optimized(ehci, qh) >= 0) + { + ehci_err(ehci, "EHCI Fastpath: Attempted non-optimzed write to optimzed pipe\n"); + return qh; + } + if (likely (qh != NULL)) { struct ehci_qtd *qtd; @@ -963,6 +1033,18 @@ static struct ehci_qh *qh_append_tds ( qh->hw->hw_info1 &= ~qh_addr_mask; } +#ifdef EHCI_QTD_CACHE + { + struct list_head *entry; + struct ehci_qtd *qtd2; + + list_for_each (entry, qtd_list) { + qtd2 = list_entry (entry, struct ehci_qtd, qtd_list); + qtd2->urb->hcpriv = qh_get (qh); + } + } +#endif /* EHCI_QTD_CACHE */ + /* just one way to queue requests: swap with the dummy qtd. * only hc or qh_refresh() ever modify the overlay. */ @@ -1036,6 +1118,79 @@ submit_async ( #endif spin_lock_irqsave (&ehci->lock, flags); + +#ifdef EHCI_QTD_CACHE + { + ehci_qtdc_t *qtdc_hit = NULL; + + if (!ehci->qtdc_dev) { + if (ehci->qtdc_vid && (urb->dev->descriptor.idVendor == ehci->qtdc_vid) && + ehci->qtdc_pid && (urb->dev->descriptor.idProduct == ehci->qtdc_pid)) { + ehci->qtdc_dev = urb->dev; + printk("QTDC: matched pid %x vid %x dev %p\n", + urb->dev->descriptor.idProduct, urb->dev->descriptor.idVendor, + urb->dev); + } + } + + if (ehci->qtdc[0] && (urb->dev == ehci->qtdc_dev) && (epnum == ehci->qtdc[0]->ep)) + qtdc_hit = ehci->qtdc[0]; + else if (ehci->qtdc[1] && (urb->dev == ehci->qtdc_dev) && + (epnum == ehci->qtdc[1]->ep)) + qtdc_hit = ehci->qtdc[1]; + + if (likely ((int)qtdc_hit)) { + unsigned long flags2; + + /* Link the hw_next when there're cached qtd's in qtdc_hit */ + if (likely (qtdc_hit->cnt)) { + struct ehci_qtd *qtd_prev, *qtd_this; + + qtd_prev = list_entry (qtdc_hit->cache.prev, struct ehci_qtd, qtd_list); + qtd_this = list_entry (qtd_list->next, struct ehci_qtd, qtd_list); + qtd_prev->hw_next = QTD_NEXT (qtd_this->qtd_dma); + } + + if (likely (qtdc_hit->cnt < qtdc_hit->size)) { /* queue it to the cache and return */ + /* Set the urb cached flag */ + spin_lock_irqsave (&urb->lock, flags2); + urb->transfer_flags |= URB_QTD_CACHED; + spin_unlock_irqrestore (&urb->lock, flags2); + + list_splice_init (qtd_list, qtdc_hit->cache.prev); + qtdc_hit->cnt++; +#ifdef EHCI_QTDC_DEBUG + qtdc_hit->cached_qtd++; +#endif /* EHCI_QTDC_DEBUG */ + QTDC_TRACE(qtdc_hit, ("caching! cnt %d\n", qtdc_hit->cnt)); + mod_timer (&qtdc_hit->watchdog, + jiffies + qtdc_hit->timeout); + spin_unlock_irqrestore (&ehci->lock, flags); + return 0; + } else { /* insert the cache list into qtd_list and go on */ + struct list_head *entry; + + /* clear urb cached flag */ + list_for_each (entry, &qtdc_hit->cache) { + qtd = list_entry (entry, struct ehci_qtd, qtd_list); + urb = qtd->urb; + spin_lock_irqsave (&urb->lock, flags2); + urb->transfer_flags &= ~URB_QTD_CACHED; + spin_unlock_irqrestore (&urb->lock, flags2); + } + list_splice_init (&qtdc_hit->cache, qtd_list); +#ifdef EHCI_QTDC_DEBUG + qtdc_hit->release_qtd += qtdc_hit->cnt; + qtdc_hit->release_cnt++; +#endif /* EHCI_QTDC_DEBUG */ + QTDC_TRACE(qtdc_hit, ("releasing! cnt %d\n", qtdc_hit->cnt)); + qtdc_hit->cnt = 0; + del_timer_sync (&qtdc_hit->watchdog); + } + } + } +#endif /* EHCI_QTD_CACHE */ + if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &ehci_to_hcd(ehci)->flags))) { rc = -ESHUTDOWN; @@ -1124,6 +1279,11 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) BUG (); #endif + if(ehci_optimized(ehci, qh) >= 0) + { + ehci_err(ehci, "EHCI Fastpath: Regular unlink of optimzed pipe\n"); + } + /* stop async schedule right now? */ if (unlikely (qh == ehci->async)) { /* can't get here without STS_ASS set */ @@ -1221,3 +1381,5 @@ rescan: if (action == TIMER_ASYNC_SHRINK) timer_action (ehci, TIMER_ASYNC_SHRINK); } + + diff --git a/release/src-rt/linux/linux-2.6/drivers/usb/host/ehci-sched.c b/release/src-rt/linux/linux-2.6/drivers/usb/host/ehci-sched.c index 19318f42ed..c617f648c4 100644 --- a/release/src-rt/linux/linux-2.6/drivers/usb/host/ehci-sched.c +++ b/release/src-rt/linux/linux-2.6/drivers/usb/host/ehci-sched.c @@ -1049,6 +1049,8 @@ iso_stream_put(struct ehci_hcd *ehci, struct ehci_iso_stream *stream) * not like a QH -- no persistent state (toggle, halt) */ if (stream->refcount == 1) { + int is_in; + // BUG_ON (!list_empty(&stream->td_list)); while (!list_empty (&stream->free_list)) { @@ -1075,6 +1077,7 @@ iso_stream_put(struct ehci_hcd *ehci, struct ehci_iso_stream *stream) } } + is_in = (stream->bEndpointAddress & USB_DIR_IN) ? 0x10 : 0; stream->bEndpointAddress &= 0x0f; if (stream->ep) stream->ep->hcpriv = NULL; @@ -2268,7 +2271,6 @@ scan_periodic (struct ehci_hcd *ehci) } clock &= mod - 1; clock_frame = clock >> 3; - ++ehci->periodic_stamp; for (;;) { union ehci_shadow q, *q_p; @@ -2297,14 +2299,10 @@ restart: temp.qh = qh_get (q.qh); type = Q_NEXT_TYPE(ehci, q.qh->hw->hw_next); q = q.qh->qh_next; - if (temp.qh->stamp != ehci->periodic_stamp) { - modified = qh_completions(ehci, temp.qh); - if (!modified) - temp.qh->stamp = ehci->periodic_stamp; - if (unlikely(list_empty(&temp.qh->qtd_list) || - temp.qh->needs_rescan)) - intr_deschedule(ehci, temp.qh); - } + modified = qh_completions (ehci, temp.qh); + if (unlikely(list_empty(&temp.qh->qtd_list) || + temp.qh->needs_rescan)) + intr_deschedule (ehci, temp.qh); qh_put (temp.qh); break; case Q_TYPE_FSTN: @@ -2446,7 +2444,6 @@ restart: if (ehci->clock_frame != clock_frame) { free_cached_lists(ehci); ehci->clock_frame = clock_frame; - ++ehci->periodic_stamp; } } else { now_uframe++; diff --git a/release/src-rt/linux/linux-2.6/drivers/usb/host/ehci.h b/release/src-rt/linux/linux-2.6/drivers/usb/host/ehci.h index 9755f1c006..6a0679197d 100644 --- a/release/src-rt/linux/linux-2.6/drivers/usb/host/ehci.h +++ b/release/src-rt/linux/linux-2.6/drivers/usb/host/ehci.h @@ -56,6 +56,61 @@ struct ehci_stats { unsigned long unlink; }; +/* qtdc message level */ +#define QTDC_MSG_ERR (1<<0) +#define QTDC_MSG_STATS (1<<1) +#define QTDC_MSG_TRACE (1<<2) + +#ifdef EHCI_QTD_CACHE +typedef struct ehci_qtdc { + void *ehci; /* pointer to ehci */ + int num; /* qtdc number */ + int ep; /* endpoint */ + int size; /* max qtd's in cache */ + int cnt; /* current qtd's in cache */ + int timeout; /* max time to stay in cache */ + struct list_head cache; /* the qtd cache list */ + struct timer_list watchdog; +#ifdef EHCI_QTDC_DEBUG + unsigned long last_printed; /* last time when we printed stats */ + unsigned long cached_qtd; /* counter for cached qtd's */ + unsigned long timeout_qtd; /* counter for qtd's released in timeout */ + unsigned long timeout_qtd_max;/* max qtd's released in timeout */ + unsigned long timeout_cnt; /* counter for timeouts */ + unsigned long release_qtd; /* counter for qtd's released normally */ + unsigned long release_cnt; /* counter for normal release */ + unsigned int msglevel; +#endif /* EHCI_QTDC_DEBUG */ +} ehci_qtdc_t; + +#define NUM_QTD_CACHE 2 /* # of ep's supported (1 IN 1 OUT for now) */ + +#ifdef EHCI_QTDC_DEBUG +#define QTDC_ERR(qtdc, msg) do { \ + if (qtdc->msglevel & QTDC_MSG_ERR) { \ + printk("qtdc ep 0x%x: ", qtdc->ep); \ + printk msg; \ + } \ + } while(0) +#define QTDC_STATS(qtdc, msg) do { \ + if (qtdc->msglevel & QTDC_MSG_STATS) { \ + printk("qtdc ep 0x%x: ", qtdc->ep); \ + printk msg; \ + } \ + } while(0) +#define QTDC_TRACE(qtdc, msg) do { \ + if (qtdc->msglevel & QTDC_MSG_TRACE) { \ + printk("qtdc ep 0x%x: ", qtdc->ep); \ + printk msg; \ + } \ + } while(0) +#else +#define QTDC_ERR(qtdc, msg) +#define QTDC_STATS(qtdc, msg) +#define QTDC_TRACE(qtdc, msg) +#endif /* EHCI_QTDC_DEBUG */ +#endif /* EHCI_QTD_CACHE */ + /* ehci_hcd->lock guards shared data against other CPUs: * ehci_hcd: async, reclaim, periodic (and shadow), ... * usb_host_endpoint: hcpriv @@ -124,7 +179,6 @@ struct ehci_hcd { /* one per controller */ struct timer_list watchdog; unsigned long actions; unsigned stamp; - unsigned periodic_stamp; unsigned random_frame; unsigned long next_statechange; ktime_t last_periodic_enable; @@ -142,6 +196,14 @@ struct ehci_hcd { /* one per controller */ u8 sbrn; /* packed release number */ +#ifdef EHCI_QTD_CACHE + int qtdc_pid; + int qtdc_vid; + struct usb_device *qtdc_dev; + ehci_qtdc_t* qtdc[NUM_QTD_CACHE]; + struct timer_list qtdc_watchdog; +#endif /* EHCI_QTD_CACHE */ + /* irq statistics */ #ifdef EHCI_STATS struct ehci_stats stats; @@ -154,6 +216,12 @@ struct ehci_hcd { /* one per controller */ #ifdef DEBUG struct dentry *debug_dir; #endif + + /* EHCI fastpath acceleration */ + struct usb_device *bypass_device; + struct ehci_qh *ehci_pipes[3]; /* pointer to ep location with qh address */ + void (*ehci_bypass_callback)(int pipeindex, struct ehci_qh *, spinlock_t *lock); + struct dma_pool *fastpath_pool; /* fastpath qtd pool */ }; /* convert between an HCD pointer and the corresponding EHCI_HCD */ @@ -223,7 +291,7 @@ struct ehci_caps { #define HCC_PGM_FRAMELISTLEN(p) ((p)&(1 << 1)) /* true: periodic_size changes*/ #define HCC_64BIT_ADDR(p) ((p)&(1)) /* true: can use 64-bit addr */ u8 portroute [8]; /* nibbles for routing - offset 0xC */ -} __attribute__ ((packed)); +}; /* Section 2.3 Host Controller Operational Registers */ @@ -301,7 +369,7 @@ struct ehci_regs { #define PORT_CSC (1<<1) /* connect status change */ #define PORT_CONNECT (1<<0) /* device connected */ #define PORT_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC) -} __attribute__ ((packed)); +}; #define USBMODE 0x68 /* USB Device mode */ #define USBMODE_SDIS (1<<3) /* Stream disable */ @@ -332,7 +400,7 @@ struct ehci_dbg_port { u32 data47; u32 address; #define DBGP_EPADDR(dev,ep) (((dev)<<8)|(ep)) -} __attribute__ ((packed)); +}; /*-------------------------------------------------------------------------*/ @@ -483,7 +551,7 @@ struct ehci_qh { #define QH_STATE_IDLE 3 /* HC doesn't see this */ #define QH_STATE_UNLINK_WAIT 4 /* LINKED and on reclaim q */ #define QH_STATE_COMPLETING 5 /* don't touch token.HALT */ - +#define QH_STATE_DETACHED 6 u8 xacterrs; /* XactErr retry counter */ #define QH_XACTERR_MAX 32 /* XactErr retry limit */ @@ -496,7 +564,7 @@ struct ehci_qh { unsigned short start; /* where polling starts */ #define NO_FRAME ((unsigned short)~0) /* pick new start */ struct usb_device *dev; /* access to TT */ - unsigned is_out:1; /* bulk or intr OUT */ + struct ehci_qtd *first_qtd; /* optimzied equivalent of the qtd_list */ unsigned clearing_tt:1; /* Clear-TT-Buf in progress */ }; @@ -827,6 +895,20 @@ static inline u32 hc32_to_cpup (const struct ehci_hcd *ehci, const __hc32 *x) #define STUB_DEBUG_FILES #endif /* DEBUG */ +/* EHCI fastpath acceleration */ +#define EHCI_FASTPATH 0x31 +#define EHCI_SET_EP_BYPASS (0x4300 | EHCI_FASTPATH) +#define EHCI_SET_BYPASS_CB (0x4300 | (EHCI_FASTPATH+1)) +#define EHCI_SET_BYPASS_DEV (0x4300 | (EHCI_FASTPATH+2)) +#define EHCI_DUMP_STATE (0x4300 | (EHCI_FASTPATH+3)) +#define EHCI_SET_BYPASS_POOL (0x4300 | (EHCI_FASTPATH+4)) +#define EHCI_CLR_EP_BYPASS (0x4300 | (EHCI_FASTPATH+5)) + + + + + /*-------------------------------------------------------------------------*/ #endif /* __LINUX_EHCI_HCD_H */ + diff --git a/release/src/Makefile b/release/src/Makefile index a2911dbaeb..035403b911 100644 --- a/release/src/Makefile +++ b/release/src/Makefile @@ -223,6 +223,7 @@ endif ifeq ($(LINKSYS_E_64k),y) # Linksys E-series(64k Nvram) images @btools/fpkg -i lzma-loader/loader.gz -i $(LINUXDIR)/arch/mips/brcm-boards/bcm947xx/compressed/vmlinuz -a 1024 -i router/mipsel-uclibc/target.image \ + -l E800,image/tomato-E800$(current_BUILD_USB)$(if $(filter $(NVRAM_SIZE),0),,-NVRAM$(NVRAM_SIZE)K)-$(current_TOMATO_VER).$(V1)$(mips_rev)$(beta)$(V2)-$(current_BUILD_DESC).bin \ -l E900,image/tomato-E900$(current_BUILD_USB)$(if $(filter $(NVRAM_SIZE),0),,-NVRAM$(NVRAM_SIZE)K)-$(current_TOMATO_VER).$(V1)$(mips_rev)$(beta)$(V2)-$(current_BUILD_DESC).bin \ -l E122,image/tomato-E1200v2$(current_BUILD_USB)$(if $(filter $(NVRAM_SIZE),0),,-NVRAM$(NVRAM_SIZE)K)-$(current_TOMATO_VER).$(V1)$(mips_rev)$(beta)$(V2)-$(current_BUILD_DESC).bin \ -l E150,image/tomato-E1500$(current_BUILD_USB)$(if $(filter $(NVRAM_SIZE),0),,-NVRAM$(NVRAM_SIZE)K)-$(current_TOMATO_VER).$(V1)$(mips_rev)$(beta)$(V2)-$(current_BUILD_DESC).bin \ @@ -1123,6 +1124,9 @@ e2500: e3200: @$(MAKE) r2z USBAP=y NVRAM_SIZE=60 LINKSYS_E3200=y +l600n: + @$(MAKE) bin MIPS32=r2 OPENVPN=y BBEXTRAS=y EBTABLES=y NO_LIBOPT=y IPV6SUPP=y B=E BUILD_DESC="L600N" USB="USB" SNMP=y DNSCRYPT=y PPTPD=y TOR=y NOCAT=y USBAP=y + #Builds for Asus RT-N66u with 64k NVRAM support ifeq ($(CONFIG_BCMWL6),y) r64z: @@ -1251,7 +1255,7 @@ ifeq ($(CONFIG_LINUX26),y) @echo "n60j Linksys E-series build MiniIPv6 for E2500" @echo "n60v Linksys E-series build IPv6-VPN for E2000" @echo "n60m Linksys E-series build Max for E2000" - @echo " Linksys E-Series with 64k Nvram/8MB Flash(E900/E1200v2/E1500)" + @echo " Linksys E-Series with 64k Nvram/8MB Flash(E800/E900/E1200v2/E1500)" @echo "n64e Linksys E-series(64k Nvram) build VPN" @echo "n64c Linksys E-series(64k Nvram) build BTGui-VPN" @echo "n64d Linksys E-series(64k Nvram) build BTGui-VPN plus Nocat" @@ -1262,10 +1266,11 @@ ifeq ($(CONFIG_LINUX26),y) @echo "n64o Linksys E-series(64k Nvram) build Mega-VPN" @echo "n64v Linksys E-series(64k Nvram) build IPv6-VPN" @echo "n64m Linksys E-series(64k Nvram) build Max" - @echo " Router with wl_high module" + @echo " Routers with wl_high module" @echo "rtn53 Asus RT-N53 with wl_high module (dualband support)" @echo "e2500 Linksys E2500 with wl_high module (dualband support)" @echo "e3200 Linksys E3200 with wl_high module (dualband support)" + @echo "l600n Rosewill L600N Build with wl_high module (dualband support)" @echo " Netgear WNR3500L v2 builds (128MB Flash)" @echo "v2e Netgear WNR3500Lv2 build VPN" @echo "v2g Netgear WNR3500Lv2 build Tor-VPN" @@ -1278,6 +1283,7 @@ ifeq ($(CONFIG_LINUX26),y) @echo "r64o RT-N66u build Mega-VPN" @echo "r64z RT-N66u build AIO" endif + @echo "" @echo "..etc.. other build configs" @echo "clean -C router clean" @echo "cleanimage rm -rf image" diff --git a/release/src/router/rc/buttons.c b/release/src/router/rc/buttons.c index e403df4687..576b408bdc 100644 --- a/release/src/router/rc/buttons.c +++ b/release/src/router/rc/buttons.c @@ -147,6 +147,11 @@ int buttons_main(int argc, char *argv[]) ses_mask = 1 << 20; ses_led = LED_AOSS; break; + case MODEL_RTN10P: + reset_mask = 1 << 20; + ses_mask = 1 << 21; + ses_led = LED_AOSS; + break; case MODEL_RTN12: reset_mask = 1 << 1; ses_mask = 1 << 0; @@ -164,6 +169,10 @@ int buttons_main(int argc, char *argv[]) reset_mask = 1 << 3; ses_mask = 1 << 7; break; + case MODEL_RTN53A1: + reset_mask = 1 << 7; + ses_mask = 1 << 3; + break; case MODEL_RTN66U: reset_mask = 1 << 9; ses_mask = 1 << 4; @@ -222,6 +231,15 @@ int buttons_main(int argc, char *argv[]) ses_mask = 1 << 4; ses_led = LED_WHITE; break; + case MODEL_L600N: + reset_mask = 1 << 21; + ses_mask = 1 << 20; + //wlan button = 1 >> 10 + break; + case MODEL_DIR620C1: + reset_mask = 1 << 21; + ses_mask = 1 << 20; + break; #endif case MODEL_WRT160Nv1: case MODEL_WRT300N: diff --git a/release/src/router/rc/init.c b/release/src/router/rc/init.c index 1461e0f4a1..3b8a281187 100644 --- a/release/src/router/rc/init.c +++ b/release/src/router/rc/init.c @@ -418,6 +418,10 @@ static int init_vlan_ports(void) dirty |= check_nv("vlan2ports", "0 1 2 3 5*"); dirty |= check_nv("vlan1ports", "4 5"); break; + case MODEL_RTN53A1: + dirty |= check_nv("vlan1ports", "4 5"); + dirty |= check_nv("vlan2ports", "3 2 1 0 5*"); + break; case MODEL_WNR2000v2: dirty |= check_nv("vlan1ports", "4 3 2 1 5*"); dirty |= check_nv("vlan2ports", "0 5"); @@ -436,6 +440,7 @@ static int init_vlan_ports(void) dirty |= check_nv("vlan0ports", "1 2 3 4 5*"); dirty |= check_nv("vlan1ports", "0 5"); break; + case MODEL_RTN10P: case MODEL_RTN12: case MODEL_RTN12B1: dirty |= check_nv("vlan0ports", "3 2 1 0 5*"); @@ -457,10 +462,12 @@ static int init_vlan_ports(void) case MODEL_E2500: case MODEL_F7D3302: case MODEL_F7D4302: + case MODEL_DIR620C1: dirty |= check_nv("vlan1ports", "0 1 2 3 5*"); dirty |= check_nv("vlan2ports", "4 5"); break; case MODEL_E1000v2: + case MODEL_L600N: dirty |= check_nv("vlan1ports", "1 2 3 4 5*"); dirty |= check_nv("vlan2ports", "0 5"); break; @@ -630,6 +637,8 @@ static void check_bootnv(void) case MODEL_E2500: case MODEL_E3200: case MODEL_WRT160Nv3: + case MODEL_L600N: + case MODEL_DIR620C1: dirty |= check_nv("vlan2hwname", "et0"); break; #endif @@ -985,6 +994,52 @@ static int init_nvram(void) nvram_set("ag0", "0x0C"); break; #ifdef CONFIG_BCMWL5 + case MODEL_L600N: + mfr = "Rosewill"; + name = "L600N"; + features = SUP_SES | SUP_80211N; + if (!nvram_match("t_fix1", (char *)name)) { +#ifdef TCONFIG_USBAP + nvram_set("wl1_hwaddr", nvram_safe_get("0:macaddr")); + nvram_set("ehciirqt", "3"); + nvram_set("qtdc_pid", "48407"); + nvram_set("qtdc_vid", "2652"); + nvram_set("qtdc0_ep", "4"); + nvram_set("qtdc0_sz", "0"); + nvram_set("qtdc1_ep", "18"); + nvram_set("qtdc1_sz", "10"); + nvram_set("lan_ifnames", "vlan1 eth1 eth2"); + nvram_set("landevs", "vlan1 wl0 wl1"); + nvram_set("wl0_ifname", "wl0"); + nvram_set("wl1_ifname", "wl1"); +#else + nvram_set("lan_ifnames", "vlan1 eth1"); + nvram_set("landevs", "vlan1 wl0"); +#endif + nvram_set("wl_ifname", "eth1"); + nvram_set("wan_ifnameX", "vlan2"); + nvram_set("wandevs", "vlan2"); + } + break; + case MODEL_DIR620C1: + mfr = "D-Link"; + name = "Dir-620 C1"; + features = SUP_SES | SUP_80211N; + if (!nvram_match("t_fix1", (char *)name)) { +#ifdef TCONFIG_USBAP + nvram_set("lan_ifnames", "vlan1 eth1 eth2"); + nvram_set("landevs", "vlan1 wl0 wl1"); + nvram_set("wl0_ifname", "eth1"); + nvram_set("wl1_ifname", "eth2"); +#else + nvram_set("lan_ifnames", "vlan1 eth1"); + nvram_set("landevs", "vlan1 wl0"); +#endif + nvram_set("wan_ifnameX", "vlan2"); + nvram_set("wl_ifname", "eth1"); + + } + break; case MODEL_CW5358U: mfr = "Catchtech"; name = "CW-5358U"; @@ -1044,8 +1099,9 @@ static int init_nvram(void) } break; case MODEL_RTN10: + case MODEL_RTN10P: mfr = "Asus"; - name = "RT-N10"; + name = nvram_match("boardrev", "0x1153") ? "RT-N10P" : "RT-N10"; features = SUP_SES | SUP_80211N; if (!nvram_match("t_fix1", (char *)name)) { nvram_set("lan_ifnames", "vlan0 eth1"); @@ -1117,14 +1173,23 @@ static int init_nvram(void) } break; case MODEL_RTN53: + case MODEL_RTN53A1: mfr = "Asus"; - name = "RT-N53"; + name = nvram_match("boardrev", "0x1446") ? "RT-N53 A1" : "RT-N53"; features = SUP_SES | SUP_80211N; #if defined(LINUX26) && defined(TCONFIG_USBAP) if (nvram_get_int("usb_storage") == 1) nvram_set("usb_storage", "-1"); #endif if (!nvram_match("t_fix1", (char *)name)) { #ifdef TCONFIG_USBAP + nvram_set("wl1_hwaddr", nvram_safe_get("0:macaddr")); + nvram_set("ehciirqt", "3"); + nvram_set("qtdc_pid", "48407"); + nvram_set("qtdc_vid", "2652"); + nvram_set("qtdc0_ep", "4"); + nvram_set("qtdc0_sz", "0"); + nvram_set("qtdc1_ep", "18"); + nvram_set("qtdc1_sz", "10"); nvram_set("lan_ifnames", "vlan2 eth1 eth2"); nvram_set("landevs", "vlan2 wl0 wl1"); nvram_set("wl1_ifname", "eth2"); @@ -1132,6 +1197,7 @@ static int init_nvram(void) nvram_set("lan_ifnames", "vlan2 eth1"); nvram_set("landevs", "vlan2 wl0"); #endif + nvram_set("lan_ifname", "br0"); nvram_set("wl_ifname", "eth1"); nvram_set("wl0_ifname", "eth1"); nvram_set("wan_ifnameX", "vlan1"); @@ -1405,6 +1471,14 @@ static int init_nvram(void) #endif if (!nvram_match("t_fix1", (char *)name)) { #ifdef TCONFIG_USBAP + nvram_set("wl1_hwaddr", nvram_safe_get("0:macaddr")); + nvram_set("ehciirqt", "3"); + nvram_set("qtdc_pid", "48407"); + nvram_set("qtdc_vid", "2652"); + nvram_set("qtdc0_ep", "4"); + nvram_set("qtdc0_sz", "0"); + nvram_set("qtdc1_ep", "18"); + nvram_set("qtdc1_sz", "10"); nvram_set("lan_ifnames", "vlan1 eth1 eth2"); nvram_set("landevs", "vlan1 wl0 wl1"); nvram_set("wl0_ifname", "eth1"); @@ -1428,6 +1502,14 @@ static int init_nvram(void) #endif if (!nvram_match("t_fix1", (char *)name)) { #ifdef TCONFIG_USBAP + nvram_set("wl1_hwaddr", nvram_safe_get("usb/0xBD17/macaddr")); + nvram_set("ehciirqt", "3"); + nvram_set("qtdc_pid", "48407"); + nvram_set("qtdc_vid", "2652"); + nvram_set("qtdc0_ep", "4"); + nvram_set("qtdc0_sz", "0"); + nvram_set("qtdc1_ep", "18"); + nvram_set("qtdc1_sz", "10"); nvram_set("lan_ifnames", "vlan1 eth1 eth2"); nvram_set("landevs", "vlan1 wl0 wl1"); nvram_set("wl0_ifname", "eth1"); diff --git a/release/src/router/rc/mtd.c b/release/src/router/rc/mtd.c index 7662fcc421..4cdac738fb 100644 --- a/release/src/router/rc/mtd.c +++ b/release/src/router/rc/mtd.c @@ -321,6 +321,7 @@ int mtd_write_main(int argc, char *argv[]) case 0x4E583233: // 32XN E2000 case 0x4E303136: // 610N WRT610N v2 case 0x4E583136: // 61XN E3000 + case 0x30303845: // E800 E800 case 0x30303945: // E900 E900 case 0x30303145: // E100 E1000 case 0x30323145: // E120 E1200v1 diff --git a/release/src/router/rc/usb.c b/release/src/router/rc/usb.c index c89da803b0..9e1cecc091 100644 --- a/release/src/router/rc/usb.c +++ b/release/src/router/rc/usb.c @@ -108,6 +108,25 @@ void start_usb(void) #endif #ifdef TCONFIG_USBAP char instance[20]; + /* From Asus QTD cache params */ + char arg1[20] = {0}; + char arg2[20] = {0}; + char arg3[20] = {0}; + char arg4[20] = {0}; + char arg5[20] = {0}; + char arg6[20] = {0}; + char arg7[20] = {0}; + /* Save QTD cache params in nvram */ + sprintf(arg1, "log2_irq_thresh=%d", nvram_get_int("ehciirqt")); + sprintf(arg2, "qtdc_pid=%d", nvram_get_int("qtdc_pid")); + sprintf(arg3, "qtdc_vid=%d", nvram_get_int("qtdc_vid")); + sprintf(arg4, "qtdc0_ep=%d", nvram_get_int("qtdc0_ep")); + sprintf(arg5, "qtdc0_sz=%d", nvram_get_int("qtdc0_sz")); + sprintf(arg6, "qtdc1_ep=%d", nvram_get_int("qtdc1_ep")); + sprintf(arg7, "qtdc1_sz=%d", nvram_get_int("qtdc1_sz")); + + modprobe("ehci-hcd", arg1, arg2, arg3, arg4, arg5, arg6, arg7); + sprintf(instance, "instance_base=1"); modprobe("wl_high", instance ); #endif diff --git a/release/src/router/shared/id.c b/release/src/router/shared/id.c index 60909e5ac4..7ad87ff1f2 100644 --- a/release/src/router/shared/id.c +++ b/release/src/router/shared/id.c @@ -76,7 +76,9 @@ RT-N12 BCM4716 0x04cd 45 0x1201 0x???? RT-N12B1 BCM5357 0x054d 45 0x1101 0x710 RT-N10 BCM5356 0x04ec 45 0x1402 0x???? RT-N10U BCM5357 0x0550 45 0x1102 0x710 +RT-N10P BCM53572 0x058e 45 0x1153 0x710 RT-N53 BCM5357 0x0550 45 0x1442 0x710 +RT-N53A1 BCM5358U 0x0550 45 0x1446 0x710 RT-N66U BCM4706 0xf5b2 00 0x1100 0x0110 WNR3500L BCM4718 0x04cf 3500 0x1213|02 0x0710|0x1710 @@ -87,6 +89,8 @@ F7D4301 v1 BCM4718 0xd4cf 12345 0x1204 F7D3301/F7D3302/F7D4302 v1 BCM4718 0xa4cf 12345 0x1102 F5D8235-4 v3 BCM4718 0xa4cf 12345 0x1100 +Dir-620C1 BCM5358U 0x0550 0015 0x1446 0x710 //530MHz/8MB/64MB +Rosewill L600N BCM5358U 0x0550 1015 0x1400 0x710 //500MHz/8MB/64MB/2.4-5GHz/USB CW-5358U BCM5357 0x0550 1234 0x1100 0x710 //500MHz/8MB/32MB/2.4G/USB FiberHome HG320 BCM5357 0x053d 0527 0x1202 0x610 //16MB/64MB/2.4G/USB ChinaNet RG-200E BCM5357 0x053d 0504 0x1202 0x610 //16MB/64MB/2.4G/USB/FE @@ -178,6 +182,8 @@ int check_hw_type(void) case 0xf53a: case 0xf53b: case 0x0550: //RT-N10U and RT-N53 and CW-5358U + if (nvram_match("boardrev", "0x1400")) return HW_BCM5358U; //L600N + if (nvram_match("boardrev", "0x1446")) return HW_BCM5358U; //DIR-620C1 case 0x054d: case 0x053d: return HW_BCM5357; @@ -343,6 +349,7 @@ int get_model(void) if (nvram_match("boot_hw_model", "E1500")) return MODEL_E1500; break; case HW_BCM53572: + if (nvram_match("boot_hw_model", "E800")) return MODEL_E900; if (nvram_match("boot_hw_model", "E900")) return MODEL_E900; if (nvram_match("boot_hw_model", "E1200") && nvram_match("boot_hw_ver", "2.0")) return MODEL_E900; @@ -374,10 +381,14 @@ int get_model(void) break; case HW_BCM5357: if (nvram_match("boardrev", "0x1102")) return MODEL_RTN10U; + if (nvram_match("boardrev", "0x1153")) return MODEL_RTN10P; if (nvram_match("boardrev", "0x1101")) return MODEL_RTN12B1; if (nvram_match("boardrev", "0x1204")) return MODEL_RTN15U; if (nvram_match("boardrev", "0x1442")) return MODEL_RTN53; break; + case HW_BCM5358U: + if (nvram_match("boardrev", "0x1446")) return MODEL_RTN53A1; + break; case HW_BCM4716: if (nvram_match("boardrev", "0x1201")) return MODEL_RTN12; break; @@ -394,6 +405,18 @@ int get_model(void) return MODEL_WRT320N; } break; + case 1015: + switch (hw) { + case HW_BCM5358U: + if (nvram_match("boardrev", "0x1400")) return MODEL_L600N; + } + break; + case 0015: + switch (hw) { + case HW_BCM5358U: + if (nvram_match("boardrev", "0x1446")) return MODEL_DIR620C1; + } + break; case 1234: switch (hw) { case HW_BCM5357: diff --git a/release/src/router/shared/led.c b/release/src/router/shared/led.c index 36e11548b7..a489b5ef59 100644 --- a/release/src/router/shared/led.c +++ b/release/src/router/shared/led.c @@ -206,8 +206,12 @@ int do_led(int which, int mode) static int wrt610nv2[] = { 255, 5, 3, 0, 255, 255, 255, -7, 255}; static int e4200[] = { 255, 5, -3, 255, 255, 255, 255, 255, 255}; static int rtn10u[] = { 255, 255, 255, 255, 255, -7, 255, -8, 255}; + static int rtn10p[] = { 255, -6, 255, 255, 255, -7, 255, 255, 255}; static int rtn12b1[] = { -5, 255, 255, 255, 255, 255, 255, 225, 255}; static int rtn15u[] = { 1, 255, 3, 255, 255, 255, 255, -9, 255}; + static int rtn53[] = { 0, -17, 255, 255, 255, 255, 255, 255, 255}; + static int l600n[] = { 255, 255, 255, 255, 255, -7, 255, -8, 255}; + static int dir620c1[] = { -6, -8, 255, 255, 255, -7, 255, 255, 255}; static int rtn66u[] = { 255, -12, 255, 255, 255, 255, 255, 15, 13}; static int w1800r[] = { 255, -13, 255, 255, 255, 255, 255, -12, -5}; #endif @@ -320,6 +324,10 @@ int do_led(int which, int mode) case MODEL_RTN15U: b = rtn15u[which]; break; + case MODEL_RTN53: + case MODEL_RTN53A1: + b = rtn53[which]; + break; case MODEL_RTN66U: b = rtn66u[which]; break; @@ -382,9 +390,17 @@ int do_led(int which, int mode) case MODEL_RTN10U: b = rtn10u[which]; break; + case MODEL_RTN10P: + b = rtn10p[which]; + break; case MODEL_RTN12B1: b = rtn12b1[which]; break; + case MODEL_L600N: + b = l600n[which]; + break; + case MODEL_DIR620C1: + b = dir620c1[which]; #endif /* case MODEL_RT390W: diff --git a/release/src/router/shared/shared.h b/release/src/router/shared/shared.h index ba245b1299..57b036787a 100644 --- a/release/src/router/shared/shared.h +++ b/release/src/router/shared/shared.h @@ -180,6 +180,8 @@ enum { MODEL_WL500GD, MODEL_WL520GU, MODEL_DIR320, + MODEL_L600N, + MODEL_DIR620C1, MODEL_H618B, MODEL_CW5358U, MODEL_HG320, @@ -198,11 +200,13 @@ enum { MODEL_RT390W, MODEL_RTN10, MODEL_RTN10U, + MODEL_RTN10P, MODEL_RTN12, MODEL_RTN12B1, MODEL_RTN15U, MODEL_RTN16, MODEL_RTN53, + MODEL_RTN53A1, MODEL_RTN66U, MODEL_WNR3500L, MODEL_WNR3500LV2, diff --git a/release/src/router/www/advanced-vlan.asp b/release/src/router/www/advanced-vlan.asp index 2bf5402d04..3588fb0aaa 100644 --- a/release/src/router/www/advanced-vlan.asp +++ b/release/src/router/www/advanced-vlan.asp @@ -50,7 +50,7 @@