2 * ADM5120 HCD (Host Controller Driver) for USB
4 * Copyright (C) 2007-2008 Gabor Juhos <juhosg@openwrt.org>
6 * This file was derived from: drivers/usb/host/ohci-mem.c
7 * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
8 * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published
12 * by the Free Software Foundation.
16 /*-------------------------------------------------------------------------*/
19 * OHCI deals with three types of memory:
20 * - data used only by the HCD ... kmalloc is fine
21 * - async and periodic schedules, shared by HC and HCD ... these
22 * need to use dma_pool or dma_alloc_coherent
23 * - driver buffers, read/written by HC ... the hcd glue or the
24 * device driver provides us with dma addresses
26 * There's also "register" data, which is memory mapped.
27 * No memory seen by this driver (or any HCD) may be paged out.
30 /*-------------------------------------------------------------------------*/
32 static void admhc_hcd_init(struct admhcd
*ahcd
)
34 ahcd
->next_statechange
= jiffies
;
35 spin_lock_init(&ahcd
->lock
);
36 INIT_LIST_HEAD(&ahcd
->pending
);
39 /*-------------------------------------------------------------------------*/
41 static int admhc_mem_init(struct admhcd
*ahcd
)
43 ahcd
->td_cache
= dma_pool_create("admhc_td",
44 admhcd_to_hcd(ahcd
)->self
.controller
,
46 TD_ALIGN
, /* byte alignment */
47 0 /* no page-crossing issues */
52 ahcd
->ed_cache
= dma_pool_create("admhc_ed",
53 admhcd_to_hcd(ahcd
)->self
.controller
,
55 ED_ALIGN
, /* byte alignment */
56 0 /* no page-crossing issues */
64 dma_pool_destroy(ahcd
->td_cache
);
65 ahcd
->td_cache
= NULL
;
70 static void admhc_mem_cleanup(struct admhcd
*ahcd
)
73 dma_pool_destroy(ahcd
->td_cache
);
74 ahcd
->td_cache
= NULL
;
78 dma_pool_destroy(ahcd
->ed_cache
);
79 ahcd
->ed_cache
= NULL
;
83 /*-------------------------------------------------------------------------*/
85 /* ahcd "done list" processing needs this mapping */
86 static inline struct td
*dma_to_td(struct admhcd
*ahcd
, dma_addr_t td_dma
)
91 td
= ahcd
->td_hash
[TD_HASH_FUNC(td_dma
)];
92 while (td
&& td
->td_dma
!= td_dma
)
99 static struct td
*td_alloc(struct admhcd
*ahcd
, gfp_t mem_flags
)
104 td
= dma_pool_alloc(ahcd
->td_cache
, mem_flags
, &dma
);
108 /* in case ahcd fetches it, make it look dead */
109 memset(td
, 0, sizeof *td
);
110 td
->hwNextTD
= cpu_to_hc32(ahcd
, dma
);
112 /* hashed in td_fill */
117 static void td_free(struct admhcd
*ahcd
, struct td
*td
)
119 struct td
**prev
= &ahcd
->td_hash
[TD_HASH_FUNC(td
->td_dma
)];
121 while (*prev
&& *prev
!= td
)
122 prev
= &(*prev
)->td_hash
;
127 else if ((td
->hwINFO
& cpu_to_hc32(ahcd
, TD_DONE
)) != 0)
128 admhc_dbg (ahcd
, "no hash for td %p\n", td
);
130 else if ((td
->flags
& TD_FLAG_DONE
) != 0)
131 admhc_dbg (ahcd
, "no hash for td %p\n", td
);
133 dma_pool_free(ahcd
->td_cache
, td
, td
->td_dma
);
136 /*-------------------------------------------------------------------------*/
139 static struct ed
*ed_alloc(struct admhcd
*ahcd
, gfp_t mem_flags
)
144 ed
= dma_pool_alloc(ahcd
->ed_cache
, mem_flags
, &dma
);
148 memset(ed
, 0, sizeof(*ed
));
151 INIT_LIST_HEAD(&ed
->td_list
);
152 INIT_LIST_HEAD(&ed
->urb_list
);
157 static void ed_free(struct admhcd
*ahcd
, struct ed
*ed
)
159 dma_pool_free(ahcd
->ed_cache
, ed
, ed
->dma
);
162 /*-------------------------------------------------------------------------*/
165 static void urb_priv_free(struct admhcd
*ahcd
, struct urb_priv
*urb_priv
)
169 for (i
= 0; i
< urb_priv
->td_cnt
; i
++)
171 td_free(ahcd
, urb_priv
->td
[i
]);
173 list_del(&urb_priv
->pending
);
177 static struct urb_priv
*urb_priv_alloc(struct admhcd
*ahcd
, int num_tds
,
180 struct urb_priv
*priv
;
182 /* allocate the private part of the URB */
183 priv
= kzalloc(sizeof(*priv
) + sizeof(struct td
) * num_tds
, mem_flags
);
187 /* allocate the TDs (deferring hash chain updates) */
188 for (priv
->td_cnt
= 0; priv
->td_cnt
< num_tds
; priv
->td_cnt
++) {
189 priv
->td
[priv
->td_cnt
] = td_alloc(ahcd
, mem_flags
);
190 if (priv
->td
[priv
->td_cnt
] == NULL
)
194 INIT_LIST_HEAD(&priv
->pending
);
199 urb_priv_free(ahcd
, priv
);
This page took 0.056474 seconds and 5 git commands to generate.