aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ieee1394
diff options
context:
space:
mode:
authorStefan Richter <stefanr@s5r6.in-berlin.de>2006-07-02 08:17:00 -0400
committerStefan Richter <stefanr@s5r6.in-berlin.de>2006-09-17 13:17:13 -0400
commit9951903e616662e9a5dad5fbd296690e2ebbbc65 (patch)
tree3d0de40aa9100ccebea03a339dc080f7ad80333e /drivers/ieee1394
parent9b4f2e9576658c4e52d95dc8d309f51b2e2db096 (diff)
ieee1394: shrink tlabel pools, remove tpool semaphores
This patch reduces the size of struct hpsb_host and also removes semaphores from ieee1394_transactions.c. On i386, struct hpsb_host shrinks from 10656 bytes to 6688 bytes. This is accomplished by - using a single wait_queue for hpsb_get_tlabel instead of many instances of semaphores, - using a single lock to serialize access to all tlabel pools (the protected code regions are small, i.e. lock contention very low), - omitting the sysfs attribute tlabels_allocations. Drawback: In the rare case that a process needs to sleep because all transaction labels for the node are temporarily exhausted, it is also woken up if a tlabel for a different node became free, checks for an available tlabel, and is put to sleep again. The check is not costly and the situation occurs extremely rarely. (Tlabels are typically only exhausted if there was no context switch to the khpsbpkt thread which recycles tlables.) Therefore the benefit of reduced tpool size outweighs this drawback. The sysfs attributes tlabels_free and tlabels_mask are not compiled anymore unless CONFIG_IEEE1394_VERBOSEDEBUG is set. The by far biggest member of struct hpsb_host, the struct csr_control csr (5272 bytes on i386), is now placed at the end of struct hpsb_host. Note, hpsb_get_tlabel calls the macro wait_event_interruptible with a condition argument which has a side effect (allocation of a tlabel and manipulation of the packet). This side effect happens only if the condition is true. The patch relies on wait_event_interruptible not evaluating the condition again after it became true. Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers/ieee1394')
-rw-r--r--drivers/ieee1394/hosts.c3
-rw-r--r--drivers/ieee1394/hosts.h19
-rw-r--r--drivers/ieee1394/ieee1394_transactions.c108
-rw-r--r--drivers/ieee1394/ieee1394_transactions.h4
-rw-r--r--drivers/ieee1394/ieee1394_types.h23
-rw-r--r--drivers/ieee1394/nodemgr.c43
-rw-r--r--drivers/ieee1394/nodemgr.h1
7 files changed, 102 insertions, 99 deletions
diff --git a/drivers/ieee1394/hosts.c b/drivers/ieee1394/hosts.c
index 59e6f49545bf..d90a3a1898c0 100644
--- a/drivers/ieee1394/hosts.c
+++ b/drivers/ieee1394/hosts.c
@@ -143,9 +143,6 @@ struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra,
143 for (i = 2; i < 16; i++) 143 for (i = 2; i < 16; i++)
144 h->csr.gen_timestamp[i] = jiffies - 60 * HZ; 144 h->csr.gen_timestamp[i] = jiffies - 60 * HZ;
145 145
146 for (i = 0; i < ARRAY_SIZE(h->tpool); i++)
147 HPSB_TPOOL_INIT(&h->tpool[i]);
148
149 atomic_set(&h->generation, 0); 146 atomic_set(&h->generation, 0);
150 147
151 INIT_WORK(&h->delayed_reset, delayed_reset_bus, h); 148 INIT_WORK(&h->delayed_reset, delayed_reset_bus, h);
diff --git a/drivers/ieee1394/hosts.h b/drivers/ieee1394/hosts.h
index 69a7c9ff5ed7..bc6dbfadb891 100644
--- a/drivers/ieee1394/hosts.h
+++ b/drivers/ieee1394/hosts.h
@@ -35,7 +35,6 @@ struct hpsb_host {
35 int node_count; /* number of identified nodes on this bus */ 35 int node_count; /* number of identified nodes on this bus */
36 int selfid_count; /* total number of SelfIDs received */ 36 int selfid_count; /* total number of SelfIDs received */
37 int nodes_active; /* number of nodes with active link layer */ 37 int nodes_active; /* number of nodes with active link layer */
38 u8 speed[ALL_NODES]; /* speed between each node and local node */
39 38
40 nodeid_t node_id; /* node ID of this host */ 39 nodeid_t node_id; /* node ID of this host */
41 nodeid_t irm_id; /* ID of this bus' isochronous resource manager */ 40 nodeid_t irm_id; /* ID of this bus' isochronous resource manager */
@@ -55,31 +54,29 @@ struct hpsb_host {
55 int reset_retries; 54 int reset_retries;
56 quadlet_t *topology_map; 55 quadlet_t *topology_map;
57 u8 *speed_map; 56 u8 *speed_map;
58 struct csr_control csr;
59
60 /* Per node tlabel pool allocation */
61 struct hpsb_tlabel_pool tpool[ALL_NODES];
62 57
58 int id;
63 struct hpsb_host_driver *driver; 59 struct hpsb_host_driver *driver;
64
65 struct pci_dev *pdev; 60 struct pci_dev *pdev;
66
67 int id;
68
69 struct device device; 61 struct device device;
70 struct class_device class_dev; 62 struct class_device class_dev;
71 63
72 int update_config_rom; 64 int update_config_rom;
73 struct work_struct delayed_reset; 65 struct work_struct delayed_reset;
74
75 unsigned int config_roms; 66 unsigned int config_roms;
76 67
77 struct list_head addr_space; 68 struct list_head addr_space;
78 u64 low_addr_space; /* upper bound of physical DMA area */ 69 u64 low_addr_space; /* upper bound of physical DMA area */
79 u64 middle_addr_space; /* upper bound of posted write area */ 70 u64 middle_addr_space; /* upper bound of posted write area */
80};
81 71
72 u8 speed[ALL_NODES]; /* speed between each node and local node */
82 73
74 /* per node tlabel allocation */
75 u8 next_tl[ALL_NODES];
76 struct { DECLARE_BITMAP(map, 64); } tl_pool[ALL_NODES];
77
78 struct csr_control csr;
79};
83 80
84enum devctl_cmd { 81enum devctl_cmd {
85 /* Host is requested to reset its bus and cancel all outstanding async 82 /* Host is requested to reset its bus and cancel all outstanding async
diff --git a/drivers/ieee1394/ieee1394_transactions.c b/drivers/ieee1394/ieee1394_transactions.c
index 751960037e27..0833fc9f50c4 100644
--- a/drivers/ieee1394/ieee1394_transactions.c
+++ b/drivers/ieee1394/ieee1394_transactions.c
@@ -9,10 +9,9 @@
9 * directory of the kernel sources for details. 9 * directory of the kernel sources for details.
10 */ 10 */
11 11
12#include <linux/sched.h>
13#include <linux/bitops.h> 12#include <linux/bitops.h>
14#include <linux/smp_lock.h> 13#include <linux/spinlock.h>
15#include <linux/interrupt.h> 14#include <linux/wait.h>
16 15
17#include <asm/bug.h> 16#include <asm/bug.h>
18#include <asm/errno.h> 17#include <asm/errno.h>
@@ -21,8 +20,6 @@
21#include "ieee1394_types.h" 20#include "ieee1394_types.h"
22#include "hosts.h" 21#include "hosts.h"
23#include "ieee1394_core.h" 22#include "ieee1394_core.h"
24#include "highlevel.h"
25#include "nodemgr.h"
26#include "ieee1394_transactions.h" 23#include "ieee1394_transactions.h"
27 24
28#define PREP_ASYNC_HEAD_ADDRESS(tc) \ 25#define PREP_ASYNC_HEAD_ADDRESS(tc) \
@@ -32,6 +29,13 @@
32 packet->header[1] = (packet->host->node_id << 16) | (addr >> 32); \ 29 packet->header[1] = (packet->host->node_id << 16) | (addr >> 32); \
33 packet->header[2] = addr & 0xffffffff 30 packet->header[2] = addr & 0xffffffff
34 31
32#ifndef HPSB_DEBUG_TLABELS
33static
34#endif
35spinlock_t hpsb_tlabel_lock = SPIN_LOCK_UNLOCKED;
36
37static DECLARE_WAIT_QUEUE_HEAD(tlabel_wq);
38
35static void fill_async_readquad(struct hpsb_packet *packet, u64 addr) 39static void fill_async_readquad(struct hpsb_packet *packet, u64 addr)
36{ 40{
37 PREP_ASYNC_HEAD_ADDRESS(TCODE_READQ); 41 PREP_ASYNC_HEAD_ADDRESS(TCODE_READQ);
@@ -115,9 +119,41 @@ static void fill_async_stream_packet(struct hpsb_packet *packet, int length,
115 packet->tcode = TCODE_ISO_DATA; 119 packet->tcode = TCODE_ISO_DATA;
116} 120}
117 121
122/* same as hpsb_get_tlabel, except that it returns immediately */
123static int hpsb_get_tlabel_atomic(struct hpsb_packet *packet)
124{
125 unsigned long flags, *tp;
126 u8 *next;
127 int tlabel, n = NODEID_TO_NODE(packet->node_id);
128
129 /* Broadcast transactions are complete once the request has been sent.
130 * Use the same transaction label for all broadcast transactions. */
131 if (unlikely(n == ALL_NODES)) {
132 packet->tlabel = 0;
133 return 0;
134 }
135 tp = packet->host->tl_pool[n].map;
136 next = &packet->host->next_tl[n];
137
138 spin_lock_irqsave(&hpsb_tlabel_lock, flags);
139 tlabel = find_next_zero_bit(tp, 64, *next);
140 if (tlabel > 63)
141 tlabel = find_first_zero_bit(tp, 64);
142 if (tlabel > 63) {
143 spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
144 return -EAGAIN;
145 }
146 __set_bit(tlabel, tp);
147 *next = (tlabel + 1) & 63;
148 spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
149
150 packet->tlabel = tlabel;
151 return 0;
152}
153
118/** 154/**
119 * hpsb_get_tlabel - allocate a transaction label 155 * hpsb_get_tlabel - allocate a transaction label
120 * @packet: the packet who's tlabel/tpool we set 156 * @packet: the packet whose tlabel and tl_pool we set
121 * 157 *
122 * Every asynchronous transaction on the 1394 bus needs a transaction 158 * Every asynchronous transaction on the 1394 bus needs a transaction
123 * label to match the response to the request. This label has to be 159 * label to match the response to the request. This label has to be
@@ -131,42 +167,25 @@ static void fill_async_stream_packet(struct hpsb_packet *packet, int length,
131 * Return value: Zero on success, otherwise non-zero. A non-zero return 167 * Return value: Zero on success, otherwise non-zero. A non-zero return
132 * generally means there are no available tlabels. If this is called out 168 * generally means there are no available tlabels. If this is called out
133 * of interrupt or atomic context, then it will sleep until can return a 169 * of interrupt or atomic context, then it will sleep until can return a
134 * tlabel. 170 * tlabel or a signal is received.
135 */ 171 */
136int hpsb_get_tlabel(struct hpsb_packet *packet) 172int hpsb_get_tlabel(struct hpsb_packet *packet)
137{ 173{
138 unsigned long flags; 174 if (irqs_disabled() || in_atomic())
139 struct hpsb_tlabel_pool *tp; 175 return hpsb_get_tlabel_atomic(packet);
140 int n = NODEID_TO_NODE(packet->node_id); 176
141 177 /* NB: The macro wait_event_interruptible() is called with a condition
142 if (unlikely(n == ALL_NODES)) 178 * argument with side effect. This is only possible because the side
143 return 0; 179 * effect does not occur until the condition became true, and
144 tp = &packet->host->tpool[n]; 180 * wait_event_interruptible() won't evaluate the condition again after
145 181 * that. */
146 if (irqs_disabled() || in_atomic()) { 182 return wait_event_interruptible(tlabel_wq,
147 if (down_trylock(&tp->count)) 183 !hpsb_get_tlabel_atomic(packet));
148 return 1;
149 } else {
150 down(&tp->count);
151 }
152
153 spin_lock_irqsave(&tp->lock, flags);
154
155 packet->tlabel = find_next_zero_bit(tp->pool, 64, tp->next);
156 if (packet->tlabel > 63)
157 packet->tlabel = find_first_zero_bit(tp->pool, 64);
158 tp->next = (packet->tlabel + 1) % 64;
159 /* Should _never_ happen */
160 BUG_ON(test_and_set_bit(packet->tlabel, tp->pool));
161 tp->allocations++;
162 spin_unlock_irqrestore(&tp->lock, flags);
163
164 return 0;
165} 184}
166 185
167/** 186/**
168 * hpsb_free_tlabel - free an allocated transaction label 187 * hpsb_free_tlabel - free an allocated transaction label
169 * @packet: packet whos tlabel/tpool needs to be cleared 188 * @packet: packet whose tlabel and tl_pool needs to be cleared
170 * 189 *
171 * Frees the transaction label allocated with hpsb_get_tlabel(). The 190 * Frees the transaction label allocated with hpsb_get_tlabel(). The
172 * tlabel has to be freed after the transaction is complete (i.e. response 191 * tlabel has to be freed after the transaction is complete (i.e. response
@@ -177,21 +196,20 @@ int hpsb_get_tlabel(struct hpsb_packet *packet)
177 */ 196 */
178void hpsb_free_tlabel(struct hpsb_packet *packet) 197void hpsb_free_tlabel(struct hpsb_packet *packet)
179{ 198{
180 unsigned long flags; 199 unsigned long flags, *tp;
181 struct hpsb_tlabel_pool *tp; 200 int tlabel, n = NODEID_TO_NODE(packet->node_id);
182 int n = NODEID_TO_NODE(packet->node_id);
183 201
184 if (unlikely(n == ALL_NODES)) 202 if (unlikely(n == ALL_NODES))
185 return; 203 return;
186 tp = &packet->host->tpool[n]; 204 tp = packet->host->tl_pool[n].map;
187 205 tlabel = packet->tlabel;
188 BUG_ON(packet->tlabel > 63 || packet->tlabel < 0); 206 BUG_ON(tlabel > 63 || tlabel < 0);
189 207
190 spin_lock_irqsave(&tp->lock, flags); 208 spin_lock_irqsave(&hpsb_tlabel_lock, flags);
191 BUG_ON(!test_and_clear_bit(packet->tlabel, tp->pool)); 209 BUG_ON(!__test_and_clear_bit(tlabel, tp));
192 spin_unlock_irqrestore(&tp->lock, flags); 210 spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
193 211
194 up(&tp->count); 212 wake_up_interruptible(&tlabel_wq);
195} 213}
196 214
197int hpsb_packet_success(struct hpsb_packet *packet) 215int hpsb_packet_success(struct hpsb_packet *packet)
diff --git a/drivers/ieee1394/ieee1394_transactions.h b/drivers/ieee1394/ieee1394_transactions.h
index 290d37060b03..c1369c41469b 100644
--- a/drivers/ieee1394/ieee1394_transactions.h
+++ b/drivers/ieee1394/ieee1394_transactions.h
@@ -53,4 +53,8 @@ int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation,
53int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation, 53int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation,
54 u64 addr, quadlet_t *buffer, size_t length); 54 u64 addr, quadlet_t *buffer, size_t length);
55 55
56#ifdef HPSB_DEBUG_TLABELS
57extern spinlock_t hpsb_tlabel_lock;
58#endif
59
56#endif /* _IEEE1394_TRANSACTIONS_H */ 60#endif /* _IEEE1394_TRANSACTIONS_H */
diff --git a/drivers/ieee1394/ieee1394_types.h b/drivers/ieee1394/ieee1394_types.h
index 16fd2d0b5ed2..a8de375e79b7 100644
--- a/drivers/ieee1394/ieee1394_types.h
+++ b/drivers/ieee1394/ieee1394_types.h
@@ -2,31 +2,9 @@
2#define _IEEE1394_TYPES_H 2#define _IEEE1394_TYPES_H
3 3
4#include <linux/kernel.h> 4#include <linux/kernel.h>
5#include <linux/list.h>
6#include <linux/spinlock.h>
7#include <linux/string.h> 5#include <linux/string.h>
8#include <linux/types.h> 6#include <linux/types.h>
9
10#include <asm/byteorder.h> 7#include <asm/byteorder.h>
11#include <asm/semaphore.h>
12
13/* Transaction Label handling */
14struct hpsb_tlabel_pool {
15 DECLARE_BITMAP(pool, 64);
16 spinlock_t lock;
17 u8 next;
18 u32 allocations;
19 struct semaphore count;
20};
21
22#define HPSB_TPOOL_INIT(_tp) \
23do { \
24 bitmap_zero((_tp)->pool, 64); \
25 spin_lock_init(&(_tp)->lock); \
26 (_tp)->next = 0; \
27 (_tp)->allocations = 0; \
28 sema_init(&(_tp)->count, 63); \
29} while (0)
30 8
31typedef u32 quadlet_t; 9typedef u32 quadlet_t;
32typedef u64 octlet_t; 10typedef u64 octlet_t;
@@ -61,6 +39,7 @@ typedef u16 arm_length_t;
61 39
62#ifdef CONFIG_IEEE1394_VERBOSEDEBUG 40#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
63#define HPSB_VERBOSE(fmt, args...) HPSB_PRINT(KERN_DEBUG, fmt , ## args) 41#define HPSB_VERBOSE(fmt, args...) HPSB_PRINT(KERN_DEBUG, fmt , ## args)
42#define HPSB_DEBUG_TLABELS
64#else 43#else
65#define HPSB_VERBOSE(fmt, args...) 44#define HPSB_VERBOSE(fmt, args...)
66#endif 45#endif
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c
index f8f6079cc48c..eabc51b23c0b 100644
--- a/drivers/ieee1394/nodemgr.c
+++ b/drivers/ieee1394/nodemgr.c
@@ -327,34 +327,44 @@ static ssize_t fw_show_ne_bus_options(struct device *dev, struct device_attribut
327static DEVICE_ATTR(bus_options,S_IRUGO,fw_show_ne_bus_options,NULL); 327static DEVICE_ATTR(bus_options,S_IRUGO,fw_show_ne_bus_options,NULL);
328 328
329 329
330/* tlabels_free, tlabels_allocations, tlabels_mask are read non-atomically 330#ifdef HPSB_DEBUG_TLABELS
331 * here, therefore displayed values may be occasionally wrong. */ 331static ssize_t fw_show_ne_tlabels_free(struct device *dev,
332static ssize_t fw_show_ne_tlabels_free(struct device *dev, struct device_attribute *attr, char *buf) 332 struct device_attribute *attr, char *buf)
333{ 333{
334 struct node_entry *ne = container_of(dev, struct node_entry, device); 334 struct node_entry *ne = container_of(dev, struct node_entry, device);
335 return sprintf(buf, "%d\n", 64 - bitmap_weight(ne->tpool->pool, 64)); 335 unsigned long flags;
336} 336 unsigned long *tp = ne->host->tl_pool[NODEID_TO_NODE(ne->nodeid)].map;
337static DEVICE_ATTR(tlabels_free,S_IRUGO,fw_show_ne_tlabels_free,NULL); 337 int tf;
338 338
339 spin_lock_irqsave(&hpsb_tlabel_lock, flags);
340 tf = 64 - bitmap_weight(tp, 64);
341 spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
339 342
340static ssize_t fw_show_ne_tlabels_allocations(struct device *dev, struct device_attribute *attr, char *buf) 343 return sprintf(buf, "%d\n", tf);
341{
342 struct node_entry *ne = container_of(dev, struct node_entry, device);
343 return sprintf(buf, "%u\n", ne->tpool->allocations);
344} 344}
345static DEVICE_ATTR(tlabels_allocations,S_IRUGO,fw_show_ne_tlabels_allocations,NULL); 345static DEVICE_ATTR(tlabels_free,S_IRUGO,fw_show_ne_tlabels_free,NULL);
346 346
347 347
348static ssize_t fw_show_ne_tlabels_mask(struct device *dev, struct device_attribute *attr, char *buf) 348static ssize_t fw_show_ne_tlabels_mask(struct device *dev,
349 struct device_attribute *attr, char *buf)
349{ 350{
350 struct node_entry *ne = container_of(dev, struct node_entry, device); 351 struct node_entry *ne = container_of(dev, struct node_entry, device);
352 unsigned long flags;
353 unsigned long *tp = ne->host->tl_pool[NODEID_TO_NODE(ne->nodeid)].map;
354 u64 tm;
355
356 spin_lock_irqsave(&hpsb_tlabel_lock, flags);
351#if (BITS_PER_LONG <= 32) 357#if (BITS_PER_LONG <= 32)
352 return sprintf(buf, "0x%08lx%08lx\n", ne->tpool->pool[0], ne->tpool->pool[1]); 358 tm = ((u64)tp[0] << 32) + tp[1];
353#else 359#else
354 return sprintf(buf, "0x%016lx\n", ne->tpool->pool[0]); 360 tm = tp[0];
355#endif 361#endif
362 spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
363
364 return sprintf(buf, "0x%016llx\n", tm);
356} 365}
357static DEVICE_ATTR(tlabels_mask, S_IRUGO, fw_show_ne_tlabels_mask, NULL); 366static DEVICE_ATTR(tlabels_mask, S_IRUGO, fw_show_ne_tlabels_mask, NULL);
367#endif /* HPSB_DEBUG_TLABELS */
358 368
359 369
360static ssize_t fw_set_ignore_driver(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) 370static ssize_t fw_set_ignore_driver(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
@@ -461,9 +471,10 @@ static struct device_attribute *const fw_ne_attrs[] = {
461 &dev_attr_ne_vendor_id, 471 &dev_attr_ne_vendor_id,
462 &dev_attr_ne_nodeid, 472 &dev_attr_ne_nodeid,
463 &dev_attr_bus_options, 473 &dev_attr_bus_options,
474#ifdef HPSB_DEBUG_TLABELS
464 &dev_attr_tlabels_free, 475 &dev_attr_tlabels_free,
465 &dev_attr_tlabels_allocations,
466 &dev_attr_tlabels_mask, 476 &dev_attr_tlabels_mask,
477#endif
467}; 478};
468 479
469 480
@@ -782,8 +793,6 @@ static struct node_entry *nodemgr_create_node(octlet_t guid, struct csr1212_csr
782 if (!ne) 793 if (!ne)
783 return NULL; 794 return NULL;
784 795
785 ne->tpool = &host->tpool[nodeid & NODE_MASK];
786
787 ne->host = host; 796 ne->host = host;
788 ne->nodeid = nodeid; 797 ne->nodeid = nodeid;
789 ne->generation = generation; 798 ne->generation = generation;
diff --git a/drivers/ieee1394/nodemgr.h b/drivers/ieee1394/nodemgr.h
index f649c9d321b8..0e1e7d930783 100644
--- a/drivers/ieee1394/nodemgr.h
+++ b/drivers/ieee1394/nodemgr.h
@@ -107,7 +107,6 @@ struct node_entry {
107 const char *vendor_oui; 107 const char *vendor_oui;
108 108
109 u32 capabilities; 109 u32 capabilities;
110 struct hpsb_tlabel_pool *tpool;
111 110
112 struct device device; 111 struct device device;
113 struct class_device class_dev; 112 struct class_device class_dev;