diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/usb/host/ohci-mem.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/usb/host/ohci-mem.c')
-rw-r--r-- | drivers/usb/host/ohci-mem.c | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c new file mode 100644 index 000000000000..e55682b4919d --- /dev/null +++ b/drivers/usb/host/ohci-mem.c | |||
@@ -0,0 +1,139 @@ | |||
1 | /* | ||
2 | * OHCI HCD (Host Controller Driver) for USB. | ||
3 | * | ||
4 | * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> | ||
5 | * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net> | ||
6 | * | ||
7 | * This file is licenced under the GPL. | ||
8 | */ | ||
9 | |||
10 | /*-------------------------------------------------------------------------*/ | ||
11 | |||
12 | /* | ||
13 | * There's basically three types of memory: | ||
14 | * - data used only by the HCD ... kmalloc is fine | ||
15 | * - async and periodic schedules, shared by HC and HCD ... these | ||
16 | * need to use dma_pool or dma_alloc_coherent | ||
17 | * - driver buffers, read/written by HC ... the hcd glue or the | ||
18 | * device driver provides us with dma addresses | ||
19 | * | ||
20 | * There's also PCI "register" data, which is memory mapped. | ||
21 | * No memory seen by this driver is pagable. | ||
22 | */ | ||
23 | |||
24 | /*-------------------------------------------------------------------------*/ | ||
25 | |||
26 | static void ohci_hcd_init (struct ohci_hcd *ohci) | ||
27 | { | ||
28 | ohci->next_statechange = jiffies; | ||
29 | spin_lock_init (&ohci->lock); | ||
30 | INIT_LIST_HEAD (&ohci->pending); | ||
31 | INIT_WORK (&ohci->rh_resume, ohci_rh_resume, ohci_to_hcd(ohci)); | ||
32 | } | ||
33 | |||
34 | /*-------------------------------------------------------------------------*/ | ||
35 | |||
36 | static int ohci_mem_init (struct ohci_hcd *ohci) | ||
37 | { | ||
38 | ohci->td_cache = dma_pool_create ("ohci_td", | ||
39 | ohci_to_hcd(ohci)->self.controller, | ||
40 | sizeof (struct td), | ||
41 | 32 /* byte alignment */, | ||
42 | 0 /* no page-crossing issues */); | ||
43 | if (!ohci->td_cache) | ||
44 | return -ENOMEM; | ||
45 | ohci->ed_cache = dma_pool_create ("ohci_ed", | ||
46 | ohci_to_hcd(ohci)->self.controller, | ||
47 | sizeof (struct ed), | ||
48 | 16 /* byte alignment */, | ||
49 | 0 /* no page-crossing issues */); | ||
50 | if (!ohci->ed_cache) { | ||
51 | dma_pool_destroy (ohci->td_cache); | ||
52 | return -ENOMEM; | ||
53 | } | ||
54 | return 0; | ||
55 | } | ||
56 | |||
57 | static void ohci_mem_cleanup (struct ohci_hcd *ohci) | ||
58 | { | ||
59 | if (ohci->td_cache) { | ||
60 | dma_pool_destroy (ohci->td_cache); | ||
61 | ohci->td_cache = NULL; | ||
62 | } | ||
63 | if (ohci->ed_cache) { | ||
64 | dma_pool_destroy (ohci->ed_cache); | ||
65 | ohci->ed_cache = NULL; | ||
66 | } | ||
67 | } | ||
68 | |||
69 | /*-------------------------------------------------------------------------*/ | ||
70 | |||
71 | /* ohci "done list" processing needs this mapping */ | ||
72 | static inline struct td * | ||
73 | dma_to_td (struct ohci_hcd *hc, dma_addr_t td_dma) | ||
74 | { | ||
75 | struct td *td; | ||
76 | |||
77 | td_dma &= TD_MASK; | ||
78 | td = hc->td_hash [TD_HASH_FUNC(td_dma)]; | ||
79 | while (td && td->td_dma != td_dma) | ||
80 | td = td->td_hash; | ||
81 | return td; | ||
82 | } | ||
83 | |||
84 | /* TDs ... */ | ||
85 | static struct td * | ||
86 | td_alloc (struct ohci_hcd *hc, int mem_flags) | ||
87 | { | ||
88 | dma_addr_t dma; | ||
89 | struct td *td; | ||
90 | |||
91 | td = dma_pool_alloc (hc->td_cache, mem_flags, &dma); | ||
92 | if (td) { | ||
93 | /* in case hc fetches it, make it look dead */ | ||
94 | memset (td, 0, sizeof *td); | ||
95 | td->hwNextTD = cpu_to_hc32 (hc, dma); | ||
96 | td->td_dma = dma; | ||
97 | /* hashed in td_fill */ | ||
98 | } | ||
99 | return td; | ||
100 | } | ||
101 | |||
102 | static void | ||
103 | td_free (struct ohci_hcd *hc, struct td *td) | ||
104 | { | ||
105 | struct td **prev = &hc->td_hash [TD_HASH_FUNC (td->td_dma)]; | ||
106 | |||
107 | while (*prev && *prev != td) | ||
108 | prev = &(*prev)->td_hash; | ||
109 | if (*prev) | ||
110 | *prev = td->td_hash; | ||
111 | else if ((td->hwINFO & cpu_to_hc32(hc, TD_DONE)) != 0) | ||
112 | ohci_dbg (hc, "no hash for td %p\n", td); | ||
113 | dma_pool_free (hc->td_cache, td, td->td_dma); | ||
114 | } | ||
115 | |||
116 | /*-------------------------------------------------------------------------*/ | ||
117 | |||
118 | /* EDs ... */ | ||
119 | static struct ed * | ||
120 | ed_alloc (struct ohci_hcd *hc, int mem_flags) | ||
121 | { | ||
122 | dma_addr_t dma; | ||
123 | struct ed *ed; | ||
124 | |||
125 | ed = dma_pool_alloc (hc->ed_cache, mem_flags, &dma); | ||
126 | if (ed) { | ||
127 | memset (ed, 0, sizeof (*ed)); | ||
128 | INIT_LIST_HEAD (&ed->td_list); | ||
129 | ed->dma = dma; | ||
130 | } | ||
131 | return ed; | ||
132 | } | ||
133 | |||
134 | static void | ||
135 | ed_free (struct ohci_hcd *hc, struct ed *ed) | ||
136 | { | ||
137 | dma_pool_free (hc->ed_cache, ed, ed->dma); | ||
138 | } | ||
139 | |||