static struct device *ap_root_device;
 
-DEFINE_SPINLOCK(ap_list_lock);
-LIST_HEAD(ap_card_list);
+/* Hashtable of all queue devices on the AP bus */
+DEFINE_HASHTABLE(ap_queues, 8);
+/* lock used for the ap_queues hashtable */
+DEFINE_SPINLOCK(ap_queues_lock);
 
 /* Default permissions (ioctl, card and domain masking) */
 struct ap_perms ap_perms;
  */
 static void ap_tasklet_fn(unsigned long dummy)
 {
-       struct ap_card *ac;
+       int bkt;
        struct ap_queue *aq;
        enum ap_wait wait = AP_WAIT_NONE;
 
        if (ap_using_interrupts())
                xchg(ap_airq.lsi_ptr, 0);
 
-       spin_lock_bh(&ap_list_lock);
-       for_each_ap_card(ac) {
-               for_each_ap_queue(aq, ac) {
-                       spin_lock_bh(&aq->lock);
-                       wait = min(wait, ap_sm_event_loop(aq, AP_EVENT_POLL));
-                       spin_unlock_bh(&aq->lock);
-               }
+       spin_lock_bh(&ap_queues_lock);
+       hash_for_each(ap_queues, bkt, aq, hnode) {
+               spin_lock_bh(&aq->lock);
+               wait = min(wait, ap_sm_event_loop(aq, AP_EVENT_POLL));
+               spin_unlock_bh(&aq->lock);
        }
-       spin_unlock_bh(&ap_list_lock);
+       spin_unlock_bh(&ap_queues_lock);
 
        ap_wait(wait);
 }
 
 static int ap_pending_requests(void)
 {
-       struct ap_card *ac;
+       int bkt;
        struct ap_queue *aq;
 
-       spin_lock_bh(&ap_list_lock);
-       for_each_ap_card(ac) {
-               for_each_ap_queue(aq, ac) {
-                       if (aq->queue_count == 0)
-                               continue;
-                       spin_unlock_bh(&ap_list_lock);
-                       return 1;
-               }
+       spin_lock_bh(&ap_queues_lock);
+       hash_for_each(ap_queues, bkt, aq, hnode) {
+               if (aq->queue_count == 0)
+                       continue;
+               spin_unlock_bh(&ap_queues_lock);
+               return 1;
        }
-       spin_unlock_bh(&ap_list_lock);
+       spin_unlock_bh(&ap_queues_lock);
        return 0;
 }
 
        }
 
        /* Add queue/card to list of active queues/cards */
-       spin_lock_bh(&ap_list_lock);
-       if (is_card_dev(dev))
-               list_add(&to_ap_card(dev)->list, &ap_card_list);
-       else
-               list_add(&to_ap_queue(dev)->list,
-                        &to_ap_queue(dev)->card->queues);
-       spin_unlock_bh(&ap_list_lock);
+       spin_lock_bh(&ap_queues_lock);
+       if (is_queue_dev(dev))
+               hash_add(ap_queues, &to_ap_queue(dev)->hnode,
+                        to_ap_queue(dev)->qid);
+       spin_unlock_bh(&ap_queues_lock);
 
        ap_dev->drv = ap_drv;
        rc = ap_drv->probe ? ap_drv->probe(ap_dev) : -ENODEV;
 
        if (rc) {
-               spin_lock_bh(&ap_list_lock);
-               if (is_card_dev(dev))
-                       list_del_init(&to_ap_card(dev)->list);
-               else
-                       list_del_init(&to_ap_queue(dev)->list);
-               spin_unlock_bh(&ap_list_lock);
+               spin_lock_bh(&ap_queues_lock);
+               if (is_queue_dev(dev))
+                       hash_del(&to_ap_queue(dev)->hnode);
+               spin_unlock_bh(&ap_queues_lock);
                ap_dev->drv = NULL;
        }
 
                ap_queue_remove(to_ap_queue(dev));
 
        /* Remove queue/card from list of active queues/cards */
-       spin_lock_bh(&ap_list_lock);
-       if (is_card_dev(dev))
-               list_del_init(&to_ap_card(dev)->list);
-       else
-               list_del_init(&to_ap_queue(dev)->list);
-       spin_unlock_bh(&ap_list_lock);
+       spin_lock_bh(&ap_queues_lock);
+       if (is_queue_dev(dev))
+               hash_del(&to_ap_queue(dev)->hnode);
+       spin_unlock_bh(&ap_queues_lock);
 
        return 0;
 }
 
+struct ap_queue *ap_get_qdev(ap_qid_t qid)
+{
+       int bkt;
+       struct ap_queue *aq;
+
+       spin_lock_bh(&ap_queues_lock);
+       hash_for_each(ap_queues, bkt, aq, hnode) {
+               if (aq->qid == qid) {
+                       get_device(&aq->ap_dev.device);
+                       spin_unlock_bh(&ap_queues_lock);
+                       return aq;
+               }
+       }
+       spin_unlock_bh(&ap_queues_lock);
+
+       return NULL;
+}
+EXPORT_SYMBOL(ap_get_qdev);
+
 int ap_driver_register(struct ap_driver *ap_drv, struct module *owner,
                       char *name)
 {
                return -ENODEV;
        }
 
+       /* init ap_queue hashtable */
+       hash_init(ap_queues);
+
        /* set up the AP permissions (ioctls, ap and aq masks) */
        ap_perms_init();
 
 
 
 #include <linux/device.h>
 #include <linux/types.h>
+#include <linux/hashtable.h>
 #include <asm/isc.h>
 #include <asm/ap.h>
 
 
 extern int ap_domain_index;
 
-extern spinlock_t ap_list_lock;
-extern struct list_head ap_card_list;
+extern DECLARE_HASHTABLE(ap_queues, 8);
+extern spinlock_t ap_queues_lock;
 
 static inline int ap_test_bit(unsigned int *ptr, unsigned int nr)
 {
 
 struct ap_card {
        struct ap_device ap_dev;
-       struct list_head list;          /* Private list of AP cards. */
-       struct list_head queues;        /* List of assoc. AP queues */
        void *private;                  /* ap driver private pointer. */
        int raw_hwtype;                 /* AP raw hardware type. */
        unsigned int functions;         /* AP device function bitfield. */
 
 struct ap_queue {
        struct ap_device ap_dev;
-       struct list_head list;          /* Private list of AP queues. */
+       struct hlist_node hnode;        /* Node for the ap_queues hashtable */
        struct ap_card *card;           /* Ptr to assoc. AP card. */
        spinlock_t lock;                /* Per device lock. */
        void *private;                  /* ap driver private pointer. */
        kzfree(ap_msg->private);
 }
 
-#define for_each_ap_card(_ac) \
-       list_for_each_entry(_ac, &ap_card_list, list)
-
-#define for_each_ap_queue(_aq, _ac) \
-       list_for_each_entry(_aq, &(_ac)->queues, list)
-
 /*
  * Note: don't use ap_send/ap_recv after using ap_queue_message
  * for the first time. Otherwise the ap message queue will get
 extern struct ap_perms ap_perms;
 extern struct mutex ap_perms_mutex;
 
+/*
+ * Get ap_queue device for this qid.
+ * Returns ptr to the struct ap_queue device or NULL if there
+ * was no ap_queue device with this qid found. When something is
+ * found, the reference count of the embedded device is increased.
+ * So the caller has to decrease the reference count after use
+ * with a call to put_device(&aq->ap_dev.device).
+ */
+struct ap_queue *ap_get_qdev(ap_qid_t qid);
+
 /*
  * check APQN for owned/reserved by ap bus and default driver(s).
  * Checks if this APQN is or will be in use by the ap bus
 
        u64 req_cnt;
 
        req_cnt = 0;
-       spin_lock_bh(&ap_list_lock);
+       spin_lock_bh(&ap_queues_lock);
        req_cnt = atomic64_read(&ac->total_request_count);
-       spin_unlock_bh(&ap_list_lock);
+       spin_unlock_bh(&ap_queues_lock);
        return scnprintf(buf, PAGE_SIZE, "%llu\n", req_cnt);
 }
 
                                   struct device_attribute *attr,
                                   const char *buf, size_t count)
 {
-       struct ap_card *ac = to_ap_card(dev);
+       int bkt;
        struct ap_queue *aq;
+       struct ap_card *ac = to_ap_card(dev);
 
-       spin_lock_bh(&ap_list_lock);
-       for_each_ap_queue(aq, ac)
-               aq->total_request_count = 0;
-       spin_unlock_bh(&ap_list_lock);
+       spin_lock_bh(&ap_queues_lock);
+       hash_for_each(ap_queues, bkt, aq, hnode)
+               if (ac == aq->card)
+                       aq->total_request_count = 0;
+       spin_unlock_bh(&ap_queues_lock);
        atomic64_set(&ac->total_request_count, 0);
 
        return count;
 static ssize_t requestq_count_show(struct device *dev,
                                   struct device_attribute *attr, char *buf)
 {
-       struct ap_card *ac = to_ap_card(dev);
+       int bkt;
        struct ap_queue *aq;
        unsigned int reqq_cnt;
+       struct ap_card *ac = to_ap_card(dev);
 
        reqq_cnt = 0;
-       spin_lock_bh(&ap_list_lock);
-       for_each_ap_queue(aq, ac)
-               reqq_cnt += aq->requestq_count;
-       spin_unlock_bh(&ap_list_lock);
+       spin_lock_bh(&ap_queues_lock);
+       hash_for_each(ap_queues, bkt, aq, hnode)
+               if (ac == aq->card)
+                       reqq_cnt += aq->requestq_count;
+       spin_unlock_bh(&ap_queues_lock);
        return scnprintf(buf, PAGE_SIZE, "%d\n", reqq_cnt);
 }
 
 static ssize_t pendingq_count_show(struct device *dev,
                                   struct device_attribute *attr, char *buf)
 {
-       struct ap_card *ac = to_ap_card(dev);
+       int bkt;
        struct ap_queue *aq;
        unsigned int penq_cnt;
+       struct ap_card *ac = to_ap_card(dev);
 
        penq_cnt = 0;
-       spin_lock_bh(&ap_list_lock);
-       for_each_ap_queue(aq, ac)
-               penq_cnt += aq->pendingq_count;
-       spin_unlock_bh(&ap_list_lock);
+       spin_lock_bh(&ap_queues_lock);
+       hash_for_each(ap_queues, bkt, aq, hnode)
+               if (ac == aq->card)
+                       penq_cnt += aq->pendingq_count;
+       spin_unlock_bh(&ap_queues_lock);
        return scnprintf(buf, PAGE_SIZE, "%d\n", penq_cnt);
 }
 
 {
        struct ap_card *ac = to_ap_card(dev);
 
-       if (!list_empty(&ac->list)) {
-               spin_lock_bh(&ap_list_lock);
-               list_del_init(&ac->list);
-               spin_unlock_bh(&ap_list_lock);
-       }
        kfree(ac);
 }
 
        ac = kzalloc(sizeof(*ac), GFP_KERNEL);
        if (!ac)
                return NULL;
-       INIT_LIST_HEAD(&ac->list);
-       INIT_LIST_HEAD(&ac->queues);
        ac->ap_dev.device.release = ap_card_device_release;
        ac->ap_dev.device.type = &ap_card_type;
        ac->ap_dev.device_type = comp_type;
 
 {
        struct ap_queue *aq = to_ap_queue(dev);
 
-       if (!list_empty(&aq->list)) {
-               spin_lock_bh(&ap_list_lock);
-               list_del_init(&aq->list);
-               spin_unlock_bh(&ap_list_lock);
-       }
+       spin_lock_bh(&ap_queues_lock);
+       hash_del(&aq->hnode);
+       spin_unlock_bh(&ap_queues_lock);
+
        kfree(aq);
 }
 
        aq->state = AP_STATE_UNBOUND;
        aq->interrupt = AP_INTR_DISABLED;
        spin_lock_init(&aq->lock);
-       INIT_LIST_HEAD(&aq->list);
        INIT_LIST_HEAD(&aq->pendingq);
        INIT_LIST_HEAD(&aq->requestq);
        timer_setup(&aq->timeout, ap_request_timeout, 0);