for (i = 2; i < 16; i++)
                h->csr.gen_timestamp[i] = jiffies - 60 * HZ;
 
-       for (i = 0; i < ARRAY_SIZE(h->tpool); i++)
-               HPSB_TPOOL_INIT(&h->tpool[i]);
-
        atomic_set(&h->generation, 0);
 
        INIT_WORK(&h->delayed_reset, delayed_reset_bus, h);
 
        int node_count;      /* number of identified nodes on this bus */
        int selfid_count;    /* total number of SelfIDs received */
        int nodes_active;    /* number of nodes with active link layer */
-       u8 speed[ALL_NODES]; /* speed between each node and local node */
 
        nodeid_t node_id;    /* node ID of this host */
        nodeid_t irm_id;     /* ID of this bus' isochronous resource manager */
        int reset_retries;
        quadlet_t *topology_map;
        u8 *speed_map;
-       struct csr_control csr;
-
-       /* Per node tlabel pool allocation */
-       struct hpsb_tlabel_pool tpool[ALL_NODES];
 
+       int id;
        struct hpsb_host_driver *driver;
-
        struct pci_dev *pdev;
-
-       int id;
-
        struct device device;
        struct class_device class_dev;
 
        int update_config_rom;
        struct work_struct delayed_reset;
-
        unsigned int config_roms;
 
        struct list_head addr_space;
        u64 low_addr_space;     /* upper bound of physical DMA area */
        u64 middle_addr_space;  /* upper bound of posted write area */
-};
 
+       u8 speed[ALL_NODES];    /* speed between each node and local node */
 
+       /* per node tlabel allocation */
+       u8 next_tl[ALL_NODES];
+       struct { DECLARE_BITMAP(map, 64); } tl_pool[ALL_NODES];
+
+       struct csr_control csr;
+};
 
 enum devctl_cmd {
        /* Host is requested to reset its bus and cancel all outstanding async
 
  * directory of the kernel sources for details.
  */
 
-#include <linux/sched.h>
 #include <linux/bitops.h>
-#include <linux/smp_lock.h>
-#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
 
 #include <asm/bug.h>
 #include <asm/errno.h>
 #include "ieee1394_types.h"
 #include "hosts.h"
 #include "ieee1394_core.h"
-#include "highlevel.h"
-#include "nodemgr.h"
 #include "ieee1394_transactions.h"
 
 #define PREP_ASYNC_HEAD_ADDRESS(tc) \
         packet->header[1] = (packet->host->node_id << 16) | (addr >> 32); \
         packet->header[2] = addr & 0xffffffff
 
+#ifndef HPSB_DEBUG_TLABELS
+static
+#endif
+spinlock_t hpsb_tlabel_lock = SPIN_LOCK_UNLOCKED;
+
+static DECLARE_WAIT_QUEUE_HEAD(tlabel_wq);
+
 static void fill_async_readquad(struct hpsb_packet *packet, u64 addr)
 {
        PREP_ASYNC_HEAD_ADDRESS(TCODE_READQ);
        packet->tcode = TCODE_ISO_DATA;
 }
 
+/* same as hpsb_get_tlabel, except that it returns immediately */
+static int hpsb_get_tlabel_atomic(struct hpsb_packet *packet)
+{
+       unsigned long flags, *tp;
+       u8 *next;
+       int tlabel, n = NODEID_TO_NODE(packet->node_id);
+
+       /* Broadcast transactions are complete once the request has been sent.
+        * Use the same transaction label for all broadcast transactions. */
+       if (unlikely(n == ALL_NODES)) {
+               packet->tlabel = 0;
+               return 0;
+       }
+       tp = packet->host->tl_pool[n].map;
+       next = &packet->host->next_tl[n];
+
+       spin_lock_irqsave(&hpsb_tlabel_lock, flags);
+       tlabel = find_next_zero_bit(tp, 64, *next);
+       if (tlabel > 63)
+               tlabel = find_first_zero_bit(tp, 64);
+       if (tlabel > 63) {
+               spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
+               return -EAGAIN;
+       }
+       __set_bit(tlabel, tp);
+       *next = (tlabel + 1) & 63;
+       spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
+
+       packet->tlabel = tlabel;
+       return 0;
+}
+
 /**
  * hpsb_get_tlabel - allocate a transaction label
- * @packet: the packet who's tlabel/tpool we set
+ * @packet: the packet whose tlabel and tl_pool we set
  *
  * Every asynchronous transaction on the 1394 bus needs a transaction
  * label to match the response to the request.  This label has to be
  * Return value: Zero on success, otherwise non-zero. A non-zero return
  * generally means there are no available tlabels. If this is called out
  * of interrupt or atomic context, then it will sleep until can return a
- * tlabel.
+ * tlabel or a signal is received.
  */
 int hpsb_get_tlabel(struct hpsb_packet *packet)
 {
-       unsigned long flags;
-       struct hpsb_tlabel_pool *tp;
-       int n = NODEID_TO_NODE(packet->node_id);
-
-       if (unlikely(n == ALL_NODES))
-               return 0;
-       tp = &packet->host->tpool[n];
-
-       if (irqs_disabled() || in_atomic()) {
-               if (down_trylock(&tp->count))
-                       return 1;
-       } else {
-               down(&tp->count);
-       }
-
-       spin_lock_irqsave(&tp->lock, flags);
-
-       packet->tlabel = find_next_zero_bit(tp->pool, 64, tp->next);
-       if (packet->tlabel > 63)
-               packet->tlabel = find_first_zero_bit(tp->pool, 64);
-       tp->next = (packet->tlabel + 1) % 64;
-       /* Should _never_ happen */
-       BUG_ON(test_and_set_bit(packet->tlabel, tp->pool));
-       tp->allocations++;
-       spin_unlock_irqrestore(&tp->lock, flags);
-
-       return 0;
+       if (irqs_disabled() || in_atomic())
+               return hpsb_get_tlabel_atomic(packet);
+
+       /* NB: The macro wait_event_interruptible() is called with a condition
+        * argument with side effect.  This is only possible because the side
+        * effect does not occur until the condition became true, and
+        * wait_event_interruptible() won't evaluate the condition again after
+        * that. */
+       return wait_event_interruptible(tlabel_wq,
+                                       !hpsb_get_tlabel_atomic(packet));
 }
 
 /**
  * hpsb_free_tlabel - free an allocated transaction label
- * @packet: packet whos tlabel/tpool needs to be cleared
+ * @packet: packet whose tlabel and tl_pool needs to be cleared
  *
  * Frees the transaction label allocated with hpsb_get_tlabel().  The
  * tlabel has to be freed after the transaction is complete (i.e. response
  */
 void hpsb_free_tlabel(struct hpsb_packet *packet)
 {
-       unsigned long flags;
-       struct hpsb_tlabel_pool *tp;
-       int n = NODEID_TO_NODE(packet->node_id);
+       unsigned long flags, *tp;
+       int tlabel, n = NODEID_TO_NODE(packet->node_id);
 
        if (unlikely(n == ALL_NODES))
                return;
-       tp = &packet->host->tpool[n];
-
-       BUG_ON(packet->tlabel > 63 || packet->tlabel < 0);
+       tp = packet->host->tl_pool[n].map;
+       tlabel = packet->tlabel;
+       BUG_ON(tlabel > 63 || tlabel < 0);
 
-       spin_lock_irqsave(&tp->lock, flags);
-       BUG_ON(!test_and_clear_bit(packet->tlabel, tp->pool));
-       spin_unlock_irqrestore(&tp->lock, flags);
+       spin_lock_irqsave(&hpsb_tlabel_lock, flags);
+       BUG_ON(!__test_and_clear_bit(tlabel, tp));
+       spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
 
-       up(&tp->count);
+       wake_up_interruptible(&tlabel_wq);
 }
 
 int hpsb_packet_success(struct hpsb_packet *packet)
 
 int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation,
               u64 addr, quadlet_t *buffer, size_t length);
 
+#ifdef HPSB_DEBUG_TLABELS
+extern spinlock_t hpsb_tlabel_lock;
+#endif
+
 #endif /* _IEEE1394_TRANSACTIONS_H */
 
 #define _IEEE1394_TYPES_H
 
 #include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/spinlock.h>
 #include <linux/string.h>
 #include <linux/types.h>
-
 #include <asm/byteorder.h>
-#include <asm/semaphore.h>
-
-/* Transaction Label handling */
-struct hpsb_tlabel_pool {
-       DECLARE_BITMAP(pool, 64);
-       spinlock_t lock;
-       u8 next;
-       u32 allocations;
-       struct semaphore count;
-};
-
-#define HPSB_TPOOL_INIT(_tp)                   \
-do {                                           \
-       bitmap_zero((_tp)->pool, 64);           \
-       spin_lock_init(&(_tp)->lock);           \
-       (_tp)->next = 0;                        \
-       (_tp)->allocations = 0;                 \
-       sema_init(&(_tp)->count, 63);           \
-} while (0)
 
 typedef u32 quadlet_t;
 typedef u64 octlet_t;
 
 #ifdef CONFIG_IEEE1394_VERBOSEDEBUG
 #define HPSB_VERBOSE(fmt, args...)     HPSB_PRINT(KERN_DEBUG, fmt , ## args)
+#define HPSB_DEBUG_TLABELS
 #else
 #define HPSB_VERBOSE(fmt, args...)
 #endif
 
 static DEVICE_ATTR(bus_options,S_IRUGO,fw_show_ne_bus_options,NULL);
 
 
-/* tlabels_free, tlabels_allocations, tlabels_mask are read non-atomically
- * here, therefore displayed values may be occasionally wrong. */
-static ssize_t fw_show_ne_tlabels_free(struct device *dev, struct device_attribute *attr, char *buf)
+#ifdef HPSB_DEBUG_TLABELS
+static ssize_t fw_show_ne_tlabels_free(struct device *dev,
+                                      struct device_attribute *attr, char *buf)
 {
        struct node_entry *ne = container_of(dev, struct node_entry, device);
-       return sprintf(buf, "%d\n", 64 - bitmap_weight(ne->tpool->pool, 64));
-}
-static DEVICE_ATTR(tlabels_free,S_IRUGO,fw_show_ne_tlabels_free,NULL);
+       unsigned long flags;
+       unsigned long *tp = ne->host->tl_pool[NODEID_TO_NODE(ne->nodeid)].map;
+       int tf;
 
+       spin_lock_irqsave(&hpsb_tlabel_lock, flags);
+       tf = 64 - bitmap_weight(tp, 64);
+       spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
 
-static ssize_t fw_show_ne_tlabels_allocations(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct node_entry *ne = container_of(dev, struct node_entry, device);
-       return sprintf(buf, "%u\n", ne->tpool->allocations);
+       return sprintf(buf, "%d\n", tf);
 }
-static DEVICE_ATTR(tlabels_allocations,S_IRUGO,fw_show_ne_tlabels_allocations,NULL);
+static DEVICE_ATTR(tlabels_free,S_IRUGO,fw_show_ne_tlabels_free,NULL);
 
 
-static ssize_t fw_show_ne_tlabels_mask(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t fw_show_ne_tlabels_mask(struct device *dev,
+                                      struct device_attribute *attr, char *buf)
 {
        struct node_entry *ne = container_of(dev, struct node_entry, device);
+       unsigned long flags;
+       unsigned long *tp = ne->host->tl_pool[NODEID_TO_NODE(ne->nodeid)].map;
+       u64 tm;
+
+       spin_lock_irqsave(&hpsb_tlabel_lock, flags);
 #if (BITS_PER_LONG <= 32)
-       return sprintf(buf, "0x%08lx%08lx\n", ne->tpool->pool[0], ne->tpool->pool[1]);
+       tm = ((u64)tp[0] << 32) + tp[1];
 #else
-       return sprintf(buf, "0x%016lx\n", ne->tpool->pool[0]);
+       tm = tp[0];
 #endif
+       spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
+
+       return sprintf(buf, "0x%016llx\n", tm);
 }
 static DEVICE_ATTR(tlabels_mask, S_IRUGO, fw_show_ne_tlabels_mask, NULL);
+#endif /* HPSB_DEBUG_TLABELS */
 
 
 static ssize_t fw_set_ignore_driver(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
        &dev_attr_ne_vendor_id,
        &dev_attr_ne_nodeid,
        &dev_attr_bus_options,
+#ifdef HPSB_DEBUG_TLABELS
        &dev_attr_tlabels_free,
-       &dev_attr_tlabels_allocations,
        &dev_attr_tlabels_mask,
+#endif
 };
 
 
        if (!ne)
                return NULL;
 
-       ne->tpool = &host->tpool[nodeid & NODE_MASK];
-
        ne->host = host;
        ne->nodeid = nodeid;
        ne->generation = generation;
 
        const char *vendor_oui;
 
        u32 capabilities;
-       struct hpsb_tlabel_pool *tpool;
 
        struct device device;
        struct class_device class_dev;