ChangeSet 1.842.46.3, 2002/11/23 23:34:26-08:00, [EMAIL PROTECTED]
[PATCH] ohci uses less slab memory
When chasing down some of those 'bad entry' diagnostics, I once
got suspicious that the problem was slab corruption coming from
the way the td hashtable code worked. So I put together this
patch, eliminating some kmallocation, and the next times I ran
that test, the oops went away and it worked like a charm. Hmm.
This patch is good because it shrinks memory and code, and gets
rid of some could-fail allocations, so I figured I'd send it on
(low priority) even if I don't think it fixes the root problem.
diff -Nru a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c
--- a/drivers/usb/host/ohci-mem.c Wed Nov 27 12:53:47 2002
+++ b/drivers/usb/host/ohci-mem.c Wed Nov 27 12:53:47 2002
@@ -14,7 +14,8 @@
* - data used only by the HCD ... kmalloc is fine
* - async and periodic schedules, shared by HC and HCD ... these
* need to use pci_pool or pci_alloc_consistent
- * - driver buffers, read/written by HC ... single shot DMA mapped
+ * - driver buffers, read/written by HC ... the hcd glue or the
+ * device driver provides us with dma addresses
*
* There's also PCI "register" data, which is memory mapped.
* No memory seen by this driver is pagable.
@@ -41,95 +42,6 @@
/*-------------------------------------------------------------------------*/
-/* Recover a TD/ED using its collision chain */
-static inline void *
-dma_to_ed_td (struct hash_list_t * entry, dma_addr_t dma)
-{
- struct hash_t * scan = entry->head;
- while (scan && scan->dma != dma)
- scan = scan->next;
- return scan ? scan->virt : 0;
-}
-
-static inline struct td *
-dma_to_td (struct ohci_hcd *hc, dma_addr_t td_dma)
-{
- td_dma &= TD_MASK;
- return (struct td *) dma_to_ed_td(&(hc->td_hash [TD_HASH_FUNC(td_dma)]),
- td_dma);
-}
-
-// FIXME: when updating the hashtables this way, mem_flags is unusable...
-
-/* Add a hash entry for a TD/ED; return true on success */
-static inline int
-hash_add_ed_td (
- struct hash_list_t *entry,
- void *virt,
- dma_addr_t dma,
- int mem_flags
-)
-{
- struct hash_t * scan;
-
- scan = (struct hash_t *) kmalloc (sizeof *scan, mem_flags);
- if (!scan)
- return 0;
-
- if (!entry->tail) {
- entry->head = entry->tail = scan;
- } else {
- entry->tail->next = scan;
- entry->tail = scan;
- }
-
- scan->virt = virt;
- scan->dma = dma;
- scan->next = NULL;
- return 1;
-}
-
-static inline int
-hash_add_td (struct ohci_hcd *hc, struct td *td, int mem_flags)
-{
- return hash_add_ed_td (&(hc->td_hash [TD_HASH_FUNC (td->td_dma)]),
- td, td->td_dma, mem_flags);
-}
-
-
-static inline void
-hash_free_ed_td (struct hash_list_t *entry, void *virt)
-{
- struct hash_t *scan, *prev;
- scan = prev = entry->head;
-
- // Find and unlink hash entry
- while (scan && scan->virt != virt) {
- prev = scan;
- scan = scan->next;
- }
- if (scan) {
- if (scan == entry->head) {
- if (entry->head == entry->tail)
- entry->head = entry->tail = NULL;
- else
- entry->head = scan->next;
- } else if (scan == entry->tail) {
- entry->tail = prev;
- prev->next = NULL;
- } else
- prev->next = scan->next;
- kfree(scan);
- }
-}
-
-static inline void
-hash_free_td (struct ohci_hcd *hc, struct td * td)
-{
- hash_free_ed_td (&(hc->td_hash[TD_HASH_FUNC(td->td_dma)]), td);
-}
-
-
static int ohci_mem_init (struct ohci_hcd *ohci)
{
ohci->td_cache = pci_pool_create ("ohci_td", ohci->hcd.pdev,
@@ -161,6 +73,21 @@
}
}
+/*-------------------------------------------------------------------------*/
+
+/* 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, int mem_flags)
@@ -170,12 +97,17 @@
td = pci_pool_alloc (hc->td_cache, mem_flags, &dma);
if (td) {
+ int hash;
+
+ /* in case hc fetches it, make it look dead */
+ memset (td, 0, sizeof *td);
+ td->hwNextTD = cpu_to_le32 (dma);
td->td_dma = dma;
+
/* hash it for later reverse mapping */
- if (!hash_add_td (hc, td, mem_flags)) {
- pci_pool_free (hc->td_cache, td, dma);
- return NULL;
- }
+ hash = TD_HASH_FUNC (dma);
+ td->td_hash = hc->td_hash [hash];
+ hc->td_hash [hash] = td;
}
return td;
}
@@ -183,10 +115,18 @@
static void
td_free (struct ohci_hcd *hc, struct td *td)
{
- hash_free_td (hc, td);
+ struct td **prev = &hc->td_hash [TD_HASH_FUNC (td->td_dma)];
+
+ while (*prev && *prev != td)
+ prev = &(*prev)->td_hash;
+ if (*prev)
+ *prev = td->td_hash;
+ else
+ dev_dbg (*hc->hcd.controller, "bad hash for td %p\n", td);
pci_pool_free (hc->td_cache, td, td->td_dma);
}
+/*-------------------------------------------------------------------------*/
/* EDs ... */
static struct ed *
diff -Nru a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
--- a/drivers/usb/host/ohci.h Wed Nov 27 12:53:47 2002
+++ b/drivers/usb/host/ohci.h Wed Nov 27 12:53:47 2002
@@ -111,6 +111,7 @@
/* rest are purely for the driver's use */
__u8 index;
struct ed *ed;
+ struct td *td_hash; /* dma-->td hashtable */
struct td *next_dl_td;
struct urb *urb;
@@ -320,23 +321,9 @@
#define URB_DEL 1
-
-/* Hash struct used for TD/ED hashing */
-struct hash_t {
- void *virt;
- dma_addr_t dma;
- struct hash_t *next; // chaining for collision cases
-};
-
-/* List of TD/ED hash entries */
-struct hash_list_t {
- struct hash_t *head;
- struct hash_t *tail;
-};
-
#define TD_HASH_SIZE 64 /* power'o'two */
-
-#define TD_HASH_FUNC(td_dma) ((td_dma ^ (td_dma >> 5)) % TD_HASH_SIZE)
+// sizeof (struct td) ~= 64 == 2^6 ...
+#define TD_HASH_FUNC(td_dma) ((td_dma ^ (td_dma >> 6)) % TD_HASH_SIZE)
/*
@@ -373,7 +360,7 @@
*/
struct pci_pool *td_cache;
struct pci_pool *ed_cache;
- struct hash_list_t td_hash [TD_HASH_SIZE];
+ struct td *td_hash [TD_HASH_SIZE];
/*
* driver state
-------------------------------------------------------
This SF.net email is sponsored by: Get the new Palm Tungsten T
handheld. Power & Color in a compact size!
http://ads.sourceforge.net/cgi-bin/redirect.pl?palm0002en
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel