Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 | // SPDX-License-Identifier: GPL-1.0+ /* * OHCI HCD (Host Controller Driver) for USB. * * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net> * * This file is licenced under the GPL. */ /*-------------------------------------------------------------------------*/ /* * OHCI deals with three types of memory: * - data used only by the HCD ... kmalloc is fine * - async and periodic schedules, shared by HC and HCD ... these * need to use dma_pool or dma_alloc_coherent * - driver buffers, read/written by HC ... the hcd glue or the * device driver provides us with dma addresses * * There's also "register" data, which is memory mapped. * No memory seen by this driver (or any HCD) may be paged out. */ /*-------------------------------------------------------------------------*/ static void ohci_hcd_init (struct ohci_hcd *ohci) { ohci->next_statechange = jiffies; spin_lock_init (&ohci->lock); INIT_LIST_HEAD (&ohci->pending); INIT_LIST_HEAD(&ohci->eds_in_use); } /*-------------------------------------------------------------------------*/ static int ohci_mem_init (struct ohci_hcd *ohci) { /* * HCs with local memory allocate from localmem_pool so there's * no need to create the below dma pools. */ if (ohci_to_hcd(ohci)->localmem_pool) return 0; ohci->td_cache = dma_pool_create ("ohci_td", ohci_to_hcd(ohci)->self.controller, sizeof (struct td), 32 /* byte alignment */, 0 /* no page-crossing issues */); if (!ohci->td_cache) return -ENOMEM; ohci->ed_cache = dma_pool_create ("ohci_ed", ohci_to_hcd(ohci)->self.controller, sizeof (struct ed), 16 /* byte alignment */, 0 /* no page-crossing issues */); if (!ohci->ed_cache) { dma_pool_destroy (ohci->td_cache); return -ENOMEM; } return 0; } static void ohci_mem_cleanup (struct ohci_hcd *ohci) { dma_pool_destroy(ohci->td_cache); ohci->td_cache = NULL; dma_pool_destroy(ohci->ed_cache); ohci->ed_cache = NULL; } /*-------------------------------------------------------------------------*/ /* ohci "done list" processing needs this mapping */ static inline struct td * dma_to_td (struct ohci_hcd *hc, dma_addr_t td_dma) { struct td *td; td_dma &= TD_MASK; td = hc->td_hash [TD_HASH_FUNC(td_dma)]; while (td && td->td_dma != td_dma) td = td->td_hash; return td; } /* TDs ... */ static struct td * td_alloc (struct ohci_hcd *hc, gfp_t mem_flags) { dma_addr_t dma; struct td *td; struct usb_hcd *hcd = ohci_to_hcd(hc); if (hcd->localmem_pool) td = gen_pool_dma_zalloc_align(hcd->localmem_pool, sizeof(*td), &dma, 32); else td = dma_pool_zalloc(hc->td_cache, mem_flags, &dma); if (td) { /* in case hc fetches it, make it look dead */ td->hwNextTD = cpu_to_hc32 (hc, dma); td->td_dma = dma; /* hashed in td_fill */ } return td; } static void td_free (struct ohci_hcd *hc, struct td *td) { struct td **prev = &hc->td_hash [TD_HASH_FUNC (td->td_dma)]; struct usb_hcd *hcd = ohci_to_hcd(hc); while (*prev && *prev != td) prev = &(*prev)->td_hash; if (*prev) *prev = td->td_hash; else if ((td->hwINFO & cpu_to_hc32(hc, TD_DONE)) != 0) ohci_dbg (hc, "no hash for td %p\n", td); if (hcd->localmem_pool) gen_pool_free(hcd->localmem_pool, (unsigned long)td, sizeof(*td)); else dma_pool_free(hc->td_cache, td, td->td_dma); } /*-------------------------------------------------------------------------*/ /* EDs ... */ static struct ed * ed_alloc (struct ohci_hcd *hc, gfp_t mem_flags) { dma_addr_t dma; struct ed *ed; struct usb_hcd *hcd = ohci_to_hcd(hc); if (hcd->localmem_pool) ed = gen_pool_dma_zalloc_align(hcd->localmem_pool, sizeof(*ed), &dma, 16); else ed = dma_pool_zalloc(hc->ed_cache, mem_flags, &dma); if (ed) { INIT_LIST_HEAD (&ed->td_list); ed->dma = dma; } return ed; } static void ed_free (struct ohci_hcd *hc, struct ed *ed) { struct usb_hcd *hcd = ohci_to_hcd(hc); if (hcd->localmem_pool) gen_pool_free(hcd->localmem_pool, (unsigned long)ed, sizeof(*ed)); else dma_pool_free(hc->ed_cache, ed, ed->dma); } |