--- drivers/usb/usb-ohci-orig.h Wed Mar 14 12:40:36 2001 +++ drivers/usb/usb-ohci.h Fri Mar 23 10:13:17 2001 @@ -39,7 +39,7 @@ #define ED_URB_DEL 0x08 /* usb_ohci_ed */ -typedef struct ed { +struct ed { __u32 hwINFO; __u32 hwTailP; __u32 hwHeadP; @@ -53,9 +53,12 @@ __u8 state; __u8 type; __u16 last_iso; - struct ed * ed_rm_list; - -} ed_t; + struct ed * ed_rm_list; + + dma_addr_t dma; + __u32 unused[3]; +} __attribute((aligned(16))); +typedef struct ed ed_t; /* TD info field */ @@ -96,19 +99,23 @@ #define MAXPSW 1 -typedef struct td { +struct td { __u32 hwINFO; __u32 hwCBP; /* Current Buffer Pointer */ __u32 hwNextTD; /* Next TD Pointer */ __u32 hwBE; /* Memory Buffer End Pointer */ - __u16 hwPSW[MAXPSW]; + __u16 hwPSW[MAXPSW]; __u8 unused; __u8 index; struct ed * ed; struct td * next_dl_td; urb_t * urb; -} td_t; + + dma_addr_t td_dma; + __u32 unused2[3]; +} __attribute((aligned(16))); +typedef struct td td_t; #define OHCI_ED_SKIP (1 << 14) @@ -121,7 +128,7 @@ #define NUM_INTS 32 /* part of the OHCI standard */ struct ohci_hcca { - __u32 int_table[NUM_INTS]; /* Interrupt ED table */ + __u32 int_table[NUM_INTS]; /* Interrupt ED table */ __u16 frame_no; /* current frame number */ __u16 pad1; /* set to 0 on each frame_no change */ __u32 done_head; /* info returned for an interrupt */ @@ -356,7 +363,7 @@ struct ohci_regs * regs; /* OHCI controller's memory */ struct list_head ohci_hcd_list; /* list of all ohci_hcd */ - struct ohci * next; // chain of uhci device contexts + struct ohci * next; // chain of ohci device contexts // struct list_head urb_list; // list of all pending urbs // spinlock_t urb_list_lock; // lock to keep consistency @@ -371,17 +378,18 @@ struct usb_device * dev[128]; struct virt_root_hub rh; - /* PCI device handle and settings */ + /* PCI device handle, settings, ... */ struct pci_dev *ohci_dev; u8 pci_latency; + struct pci_pool *td_cache; + struct pci_pool *dev_cache; } ohci_t; - -#define NUM_TDS 0 /* num of preallocated transfer descriptors */ #define NUM_EDS 32 /* num of preallocated endpoint descriptors */ struct ohci_device { ed_t ed[NUM_EDS]; + dma_addr_t dma; int ed_cnt; wait_queue_head_t * wait; }; @@ -393,7 +401,7 @@ /* endpoint */ static int ep_link(ohci_t * ohci, ed_t * ed); static int ep_unlink(ohci_t * ohci, ed_t * ed); -static ed_t * ep_add_ed(struct usb_device * usb_dev, unsigned int pipe, int interval, int load); +static ed_t * ep_add_ed(struct usb_device * usb_dev, unsigned int pipe, int interval, int load, int mem_flags); static void ep_rm_ed(struct usb_device * usb_dev, ed_t * ed); /* td */ static void td_fill(unsigned int info, void * data, int len, urb_t * urb, int index); @@ -406,97 +414,91 @@ /*-------------------------------------------------------------------------*/ #define ALLOC_FLAGS (in_interrupt () ? GFP_ATOMIC : GFP_KERNEL) - -#ifdef OHCI_MEM_SLAB -#define __alloc(t,c) kmem_cache_alloc(c,ALLOC_FLAGS) -#define __free(c,x) kmem_cache_free(c,x) -static kmem_cache_t *td_cache, *ed_cache; -/* - * WARNING: do NOT use this with "forced slab debug"; it won't respect - * our hardware alignment requirement. - */ -#ifndef OHCI_MEM_FLAGS -#define OHCI_MEM_FLAGS 0 +#ifdef DEBUG +# define OHCI_MEM_FLAGS SLAB_POISON +#else +# define OHCI_MEM_FLAGS 0 +#endif + +#ifndef CONFIG_PCI +# error "usb-ohci currently requires PCI-based controllers" + /* to support non-PCI OHCIs, you need custom bus/mem/... glue */ #endif -static int ohci_mem_init (void) +static int ohci_mem_init (struct ohci *ohci) { - /* redzoning (or forced debug!) breaks alignment */ - int flags = (OHCI_MEM_FLAGS) & ~SLAB_RED_ZONE; - - /* TDs accessed by controllers and host */ - td_cache = kmem_cache_create ("ohci_td", sizeof (struct td), 0, - flags | SLAB_HWCACHE_ALIGN, NULL, NULL); - if (!td_cache) { - dbg ("no TD cache?"); + ohci->td_cache = pci_pool_create ("ohci_td", ohci->ohci_dev, + sizeof (struct td), + 16 /* byte alignment */, + 0 /* no page-crossing issues */, + GFP_KERNEL | OHCI_MEM_FLAGS); + if (!ohci->td_cache) return -ENOMEM; - } - - /* EDs are accessed by controllers and host; dev part is host-only */ - ed_cache = kmem_cache_create ("ohci_ed", sizeof (struct ohci_device), 0, - flags | SLAB_HWCACHE_ALIGN, NULL, NULL); - if (!ed_cache) { - dbg ("no ED cache?"); - kmem_cache_destroy (td_cache); - td_cache = 0; + ohci->dev_cache = pci_pool_create ("ohci_dev", ohci->ohci_dev, + sizeof (struct ohci_device), + 16 /* byte alignment */, + 0 /* no page-crossing issues */, + GFP_KERNEL | OHCI_MEM_FLAGS); + if (!ohci->dev_cache) return -ENOMEM; - } - dbg ("slab flags 0x%x", flags); return 0; } -static void ohci_mem_cleanup (void) +static void ohci_mem_cleanup (struct ohci *ohci) { - if (ed_cache && kmem_cache_destroy (ed_cache)) - err ("ed_cache remained"); - ed_cache = 0; - - if (td_cache && kmem_cache_destroy (td_cache)) - err ("td_cache remained"); - td_cache = 0; + if (ohci->td_cache) { + pci_pool_destroy (ohci->td_cache); + ohci->td_cache = 0; + } + if (ohci->dev_cache) { + pci_pool_destroy (ohci->dev_cache); + ohci->dev_cache = 0; + } } -#else -#define __alloc(t,c) kmalloc(sizeof(t),ALLOC_FLAGS) -#define __free(dev,x) kfree(x) -#define td_cache 0 -#define ed_cache 0 - -static inline int ohci_mem_init (void) { return 0; } -static inline void ohci_mem_cleanup (void) { return; } - -/* FIXME: pci_consistent version */ - -#endif - - /* TDs ... */ static inline struct td * -td_alloc (struct ohci *hc) +td_alloc (struct ohci *hc, int mem_flags) { - struct td *td = (struct td *) __alloc (struct td, td_cache); + dma_addr_t dma; + struct td *td; + + td = pci_pool_alloc (hc->td_cache, mem_flags, &dma); + if (td) + td->td_dma = dma; return td; } static inline void td_free (struct ohci *hc, struct td *td) { - __free (td_cache, td); + pci_pool_free (hc->td_cache, td, td->td_dma); } /* DEV + EDs ... only the EDs need to be consistent */ static inline struct ohci_device * -dev_alloc (struct ohci *hc) +dev_alloc (struct ohci *hc, int mem_flags) { - struct ohci_device *dev = (struct ohci_device *) - __alloc (struct ohci_device, ed_cache); + dma_addr_t dma; + struct ohci_device *dev; + int i, offset; + + dev = pci_pool_alloc (hc->dev_cache, mem_flags, &dma); + if (dev) { + memset (dev, 0, sizeof (*dev)); + dev->dma = dma; + offset = ((char *)&dev->ed) - ((char *)dev); + for (i = 0; i < NUM_EDS; i++, offset += sizeof dev->ed [0]) + dev->ed [i].dma = dma + offset; + } return dev; } static inline void -dev_free (struct ohci_device *dev) +dev_free (struct ohci *hc, struct ohci_device *dev) { - __free (ed_cache, dev); + pci_pool_free (hc->dev_cache, dev, dev->dma); } + --- drivers/usb/usb-ohci-orig.c Wed Mar 14 12:40:36 2001 +++ drivers/usb/usb-ohci.c Wed Mar 21 17:33:06 2001 @@ -12,11 +12,12 @@ * * History: * + * 2001/03/21 td and dev/ed allocation uses new pci_pool API (db) * 2001/03/07 hcca allocation uses pci_alloc_consistent (Steve Longerbeam) * 2000/09/26 fixed races in removing the private portion of the urb * 2000/09/07 disable bulk and control lists when unlinking the last * endpoint descriptor in order to avoid unrecoverable errors on - * the Lucent chips. + * the Lucent chips. (rwc@sgi) * 2000/08/29 use bandwidth claiming hooks (thanks Randy!), fix some * urb unlink probs, indentation fixes * 2000/08/11 various oops fixes mostly affecting iso and cleanup from @@ -65,8 +66,6 @@ #define OHCI_USE_NPS // force NoPowerSwitching mode // #define OHCI_VERBOSE_DEBUG /* not always helpful */ -// #define OHCI_MEM_SLAB -// #define OHCI_MEM_FLAGS SLAB_POISON /* no redzones; see mm/slab.c */ #include "usb-ohci.h" @@ -132,7 +131,7 @@ } } - urb_free_priv ((struct ohci *)urb->dev->bus, urb_priv); + urb_free_priv ((struct ohci *)urb->dev->bus->hcpriv, urb_priv); usb_dec_dev_use (urb->dev); urb->dev = NULL; } @@ -460,6 +459,7 @@ int i, size = 0; unsigned long flags; int bustime = 0; + int mem_flags = ALLOC_FLAGS; if (!urb->dev || !urb->dev->bus) return -ENODEV; @@ -489,7 +489,7 @@ } /* every endpoint has a ed, locate and fill it */ - if (!(ed = ep_add_ed (urb->dev, pipe, urb->interval, 1))) { + if (!(ed = ep_add_ed (urb->dev, pipe, urb->interval, 1, mem_flags))) { usb_dec_dev_use (urb->dev); return -ENOMEM; } @@ -534,8 +534,9 @@ /* allocate the TDs */ for (i = 0; i < size; i++) { - urb_priv->td[i] = td_alloc (ohci); + urb_priv->td[i] = td_alloc (ohci, mem_flags); if (!urb_priv->td[i]) { + urb_priv->length = i; urb_free_priv (ohci, urb_priv); usb_dec_dev_use (urb->dev); return -ENOMEM; @@ -687,18 +688,11 @@ { struct ohci_device * dev; - /* FIXME: ED allocation with pci_consistent memory - * must know the controller ... either pass it in here, - * or decouple ED allocation from dev allocation. - */ - dev = dev_alloc (NULL); + dev = dev_alloc ((struct ohci *) usb_dev->bus->hcpriv, ALLOC_FLAGS); if (!dev) return -ENOMEM; - - memset (dev, 0, sizeof (*dev)); usb_dev->hcpriv = dev; - return 0; } @@ -783,7 +777,7 @@ } /* free device, and associated EDs */ - dev_free (dev); + dev_free (ohci, dev); return 0; } @@ -877,9 +871,9 @@ case PIPE_CONTROL: ed->hwNextED = 0; if (ohci->ed_controltail == NULL) { - writel (virt_to_bus (ed), &ohci->regs->ed_controlhead); + writel (ed->dma, &ohci->regs->ed_controlhead); } else { - ohci->ed_controltail->hwNextED = cpu_to_le32 (virt_to_bus (ed)); + ohci->ed_controltail->hwNextED = cpu_to_le32 (ed->dma); } ed->ed_prev = ohci->ed_controltail; if (!ohci->ed_controltail && !ohci->ed_rm_list[0] && @@ -893,9 +887,9 @@ case PIPE_BULK: ed->hwNextED = 0; if (ohci->ed_bulktail == NULL) { - writel (virt_to_bus (ed), &ohci->regs->ed_bulkhead); + writel (ed->dma, &ohci->regs->ed_bulkhead); } else { - ohci->ed_bulktail->hwNextED = cpu_to_le32 (virt_to_bus (ed)); + ohci->ed_bulktail->hwNextED = cpu_to_le32 (ed->dma); } ed->ed_prev = ohci->ed_bulktail; if (!ohci->ed_bulktail && !ohci->ed_rm_list[0] && @@ -920,7 +914,7 @@ ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED)) inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval); ed->hwNextED = *ed_p; - *ed_p = cpu_to_le32 (virt_to_bus (ed)); + *ed_p = cpu_to_le32 (ed->dma); } #ifdef DEBUG ep_print_int_eds (ohci, "LINK_INT"); @@ -931,7 +925,7 @@ ed->hwNextED = 0; ed->int_interval = 1; if (ohci->ed_isotail != NULL) { - ohci->ed_isotail->hwNextED = cpu_to_le32 (virt_to_bus (ed)); + ohci->ed_isotail->hwNextED = cpu_to_le32 (ed->dma); ed->ed_prev = ohci->ed_isotail; } else { for ( i = 0; i < 32; i += inter) { @@ -940,7 +934,7 @@ *ed_p != 0; ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED)) inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval); - *ed_p = cpu_to_le32 (virt_to_bus (ed)); + *ed_p = cpu_to_le32 (ed->dma); } ed->ed_prev = NULL; } @@ -1066,7 +1060,13 @@ * in all other cases the state is left unchanged * the ed info fields are setted anyway even though most of them should not change */ -static ed_t * ep_add_ed (struct usb_device * usb_dev, unsigned int pipe, int interval, int load) +static ed_t * ep_add_ed ( + struct usb_device * usb_dev, + unsigned int pipe, + int interval, + int load, + int mem_flags +) { ohci_t * ohci = usb_dev->bus->hcpriv; td_t * td; @@ -1089,13 +1089,13 @@ if (ed->state == ED_NEW) { ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP); /* skip ed */ /* dummy td; end of td list for ed */ - td = td_alloc (ohci); + td = td_alloc (ohci, mem_flags); if (!td) { /* out of memory */ spin_unlock_irqrestore (&usb_ed_lock, flags); return NULL; } - ed->hwTailP = cpu_to_le32 (virt_to_bus (td)); + ed->hwTailP = cpu_to_le32 (td->td_dma); ed->hwHeadP = ed->hwTailP; ed->state = ED_UNLINK; ed->type = usb_pipetype (pipe); @@ -1164,7 +1164,7 @@ * TD handling functions *-------------------------------------------------------------------------*/ -/* prepare a TD */ +/* enqueue next TD for this URB (OHCI spec 5.2.8.2) */ static void td_fill (unsigned int info, void * data, int len, urb_t * urb, int index) { @@ -1176,7 +1176,10 @@ return; } + /* use this td as the next dummy */ td_pt = urb_priv->td [index]; + td_pt->hwNextTD = 0; + /* fill the old dummy TD */ td = urb_priv->td [index] = (td_t *) bus_to_virt (le32_to_cpup (&urb_priv->ed->hwTailP) & 0xfffffff0); @@ -1198,9 +1201,11 @@ td->hwBE = cpu_to_le32 ((!data || !len ) ? 0 : virt_to_bus (data + len - 1)); - td->hwNextTD = cpu_to_le32 (virt_to_bus (td_pt)); + td->hwNextTD = cpu_to_le32 (td_pt->td_dma); + td->hwPSW [0] = cpu_to_le16 ((virt_to_bus (data) & 0x0FFF) | 0xE000); - td_pt->hwNextTD = 0; + + /* append to queue */ td->ed->hwTailP = td->hwNextTD; } @@ -1765,9 +1770,6 @@ wIndex = le16_to_cpu (cmd->index); wLength = le16_to_cpu (cmd->length); - dbg ("rh_submit_urb, req = %d(%x) len=%d", bmRType_bReq, - bmRType_bReq, wLength); - switch (bmRType_bReq) { /* Request Destination: without flags: Device, @@ -2199,6 +2201,8 @@ list_del (&ohci->ohci_hcd_list); INIT_LIST_HEAD (&ohci->ohci_hcd_list); + + ohci_mem_cleanup (ohci); /* unmap the IO address space */ iounmap (ohci->regs); @@ -2221,6 +2225,7 @@ ohci_t * ohci; u8 latency, limit; char buf[8], *bufp = buf; + int ret; #ifndef __sparc__ sprintf(buf, "%d", irq); @@ -2235,6 +2240,10 @@ if (!ohci) { return -ENOMEM; } + if ((ret = ohci_mem_init (ohci)) < 0) { + hc_release_ohci (ohci); + return ret; + } /* bad pci latencies can contribute to overruns */ pci_read_config_byte (dev, PCI_LATENCY_TIMER, &latency); @@ -2566,11 +2575,7 @@ { int ret; - if ((ret = ohci_mem_init ()) < 0) - return ret; - if ((ret = pci_module_init (&ohci_pci_driver)) < 0) { - ohci_mem_cleanup (); return ret; } @@ -2588,7 +2593,6 @@ pmu_unregister_sleep_notifier (&ohci_sleep_notifier); #endif pci_unregister_driver (&ohci_pci_driver); - ohci_mem_cleanup (); } module_init (ohci_hcd_init);