aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJay Fenlason <fenlason@redhat.com>2009-02-23 15:59:34 -0500
committerStefan Richter <stefanr@s5r6.in-berlin.de>2009-03-24 15:56:49 -0400
commit6104ee92d62ea3638b67494fcf061cb4b9b9d518 (patch)
tree899549d281a47f6aaae7a1645b5cb7d882f8e194
parentf8c2287c65f8f72000102fc058232669e4540bc4 (diff)
firewire: broadcast channel support
This patch adds the ISO broadcast channel support that is required of a 1394a IRM. In specific, if the local device the IRM, it allocates ISO channel 31 and sets the broadcast channel register of all devices on the local bus to BROADCAST_CHANNEL_INITIAL | BROADCAST_CHANNEL_VALID to indicate that channel 31 can be use for broadcast messages. One minor complication is that on startup the local device may become IRM before all the devices on the bus have been enumerated by the stack. Therefore we have to keep a "the local device is IRM" flag and possibly set the broadcast channel register of new devices at enumeration time. Signed-off-by: Jay Fenlason <fenlason@redhat.com> Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
-rw-r--r--drivers/firewire/fw-card.c172
-rw-r--r--drivers/firewire/fw-device.c3
-rw-r--r--drivers/firewire/fw-transaction.h8
3 files changed, 177 insertions, 6 deletions
diff --git a/drivers/firewire/fw-card.c b/drivers/firewire/fw-card.c
index 08a7e18526ee..f2b363ea443e 100644
--- a/drivers/firewire/fw-card.c
+++ b/drivers/firewire/fw-card.c
@@ -181,6 +181,147 @@ void fw_core_remove_descriptor(struct fw_descriptor *desc)
181 mutex_unlock(&card_mutex); 181 mutex_unlock(&card_mutex);
182} 182}
183 183
184/* ------------------------------------------------------------------ */
185/* Code to handle 1394a broadcast channel */
186
187#define THIRTY_TWO_CHANNELS (0xFFFFFFFFU)
188#define IRM_RETRIES 2
189
190/*
191 * The abi is set by device_for_each_child(), even though we have no use
192 * for data, nor do we have a meaningful return value.
193 */
194int fw_irm_set_broadcast_channel_register(struct device *dev, void *data)
195{
196 struct fw_device *d;
197 int rcode;
198 int node_id;
199 int max_speed;
200 int retries;
201 int generation;
202 __be32 regval;
203 struct fw_card *card;
204
205 d = fw_device(dev);
206 /* FIXME: do we need locking here? */
207 generation = d->generation;
208 smp_rmb(); /* Ensure generation is at least as old as node_id */
209 node_id = d->node_id;
210 max_speed = d->max_speed;
211 retries = IRM_RETRIES;
212 card = d->card;
213tryagain_r:
214 rcode = fw_run_transaction(card, TCODE_READ_QUADLET_REQUEST,
215 node_id, generation, max_speed,
216 CSR_REGISTER_BASE + CSR_BROADCAST_CHANNEL,
217 &regval, 4);
218 switch (rcode) {
219 case RCODE_BUSY:
220 if (retries--)
221 goto tryagain_r;
222 fw_notify("node %x read broadcast channel busy\n",
223 node_id);
224 return 0;
225
226 default:
227 fw_notify("node %x read broadcast channel failed %x\n",
228 node_id, rcode);
229 return 0;
230
231 case RCODE_COMPLETE:
232 /*
233 * Paranoid reporting of nonstandard broadcast channel
234 * contents goes here
235 */
236 if (regval != cpu_to_be32(BROADCAST_CHANNEL_INITIAL))
237 return 0;
238 break;
239 }
240 retries = IRM_RETRIES;
241 regval = cpu_to_be32(BROADCAST_CHANNEL_INITIAL |
242 BROADCAST_CHANNEL_VALID);
243tryagain_w:
244 rcode = fw_run_transaction(card,
245 TCODE_WRITE_QUADLET_REQUEST, node_id,
246 generation, max_speed,
247 CSR_REGISTER_BASE + CSR_BROADCAST_CHANNEL,
248 &regval, 4);
249 switch (rcode) {
250 case RCODE_BUSY:
251 if (retries--)
252 goto tryagain_w;
253 fw_notify("node %x write broadcast channel busy\n",
254 node_id);
255 return 0;
256
257 default:
258 fw_notify("node %x write broadcast channel failed %x\n",
259 node_id, rcode);
260 return 0;
261
262 case RCODE_COMPLETE:
263 return 0;
264 }
265 return 0;
266}
267
268static void
269irm_allocate_broadcast(struct fw_device *irm_dev, struct device *locald)
270{
271 u32 generation;
272 u32 node_id;
273 u32 max_speed;
274 u32 retries;
275 __be32 old_data;
276 __be32 lock_data[2];
277 int rcode;
278
279 /*
280 * The device we are updating is the IRM, so we must do
281 * some extra work.
282 */
283 retries = IRM_RETRIES;
284 generation = irm_dev->generation;
285 /* FIXME: do we need locking here? */
286 smp_rmb();
287 node_id = irm_dev->node_id;
288 max_speed = irm_dev->max_speed;
289
290 lock_data[0] = cpu_to_be32(THIRTY_TWO_CHANNELS);
291 lock_data[1] = cpu_to_be32(THIRTY_TWO_CHANNELS & ~1);
292tryagain:
293 old_data = lock_data[0];
294 rcode = fw_run_transaction(irm_dev->card, TCODE_LOCK_COMPARE_SWAP,
295 node_id, generation, max_speed,
296 CSR_REGISTER_BASE+CSR_CHANNELS_AVAILABLE_HI,
297 &lock_data[0], 8);
298 switch (rcode) {
299 case RCODE_BUSY:
300 if (retries--)
301 goto tryagain;
302 /* fallthrough */
303 default:
304 fw_error("node %x: allocate broadcast channel failed (%x)\n",
305 node_id, rcode);
306 return;
307
308 case RCODE_COMPLETE:
309 if (lock_data[0] == old_data)
310 break;
311 if (retries--) {
312 lock_data[1] = cpu_to_be32(be32_to_cpu(lock_data[0])&~1);
313 goto tryagain;
314 }
315 fw_error("node %x: allocate broadcast channel failed: too many"
316 " retries\n", node_id);
317 return;
318 }
319 irm_dev->card->is_irm = true;
320 device_for_each_child(locald, NULL, fw_irm_set_broadcast_channel_register);
321}
322/* ------------------------------------------------------------------ */
323
324
184static const char gap_count_table[] = { 325static const char gap_count_table[] = {
185 63, 5, 7, 8, 10, 13, 16, 18, 21, 24, 26, 29, 32, 35, 37, 40 326 63, 5, 7, 8, 10, 13, 16, 18, 21, 24, 26, 29, 32, 35, 37, 40
186}; 327};
@@ -198,8 +339,8 @@ void fw_schedule_bm_work(struct fw_card *card, unsigned long delay)
198static void fw_card_bm_work(struct work_struct *work) 339static void fw_card_bm_work(struct work_struct *work)
199{ 340{
200 struct fw_card *card = container_of(work, struct fw_card, work.work); 341 struct fw_card *card = container_of(work, struct fw_card, work.work);
201 struct fw_device *root_device; 342 struct fw_device *root_device, *irm_device, *local_device;
202 struct fw_node *root_node, *local_node; 343 struct fw_node *root_node, *local_node, *irm_node;
203 unsigned long flags; 344 unsigned long flags;
204 int root_id, new_root_id, irm_id, gap_count, generation, grace, rcode; 345 int root_id, new_root_id, irm_id, gap_count, generation, grace, rcode;
205 bool do_reset = false; 346 bool do_reset = false;
@@ -208,8 +349,10 @@ static void fw_card_bm_work(struct work_struct *work)
208 __be32 lock_data[2]; 349 __be32 lock_data[2];
209 350
210 spin_lock_irqsave(&card->lock, flags); 351 spin_lock_irqsave(&card->lock, flags);
352 card->is_irm = false;
211 local_node = card->local_node; 353 local_node = card->local_node;
212 root_node = card->root_node; 354 root_node = card->root_node;
355 irm_node = card->irm_node;
213 356
214 if (local_node == NULL) { 357 if (local_node == NULL) {
215 spin_unlock_irqrestore(&card->lock, flags); 358 spin_unlock_irqrestore(&card->lock, flags);
@@ -217,6 +360,7 @@ static void fw_card_bm_work(struct work_struct *work)
217 } 360 }
218 fw_node_get(local_node); 361 fw_node_get(local_node);
219 fw_node_get(root_node); 362 fw_node_get(root_node);
363 fw_node_get(irm_node);
220 364
221 generation = card->generation; 365 generation = card->generation;
222 root_device = root_node->data; 366 root_device = root_node->data;
@@ -225,7 +369,8 @@ static void fw_card_bm_work(struct work_struct *work)
225 root_device_is_cmc = root_device && root_device->cmc; 369 root_device_is_cmc = root_device && root_device->cmc;
226 root_id = root_node->node_id; 370 root_id = root_node->node_id;
227 grace = time_after(jiffies, card->reset_jiffies + DIV_ROUND_UP(HZ, 10)); 371 grace = time_after(jiffies, card->reset_jiffies + DIV_ROUND_UP(HZ, 10));
228 372 irm_device = irm_node->data;
373 local_device = local_node->data;
229 if (is_next_generation(generation, card->bm_generation) || 374 if (is_next_generation(generation, card->bm_generation) ||
230 (card->bm_generation != generation && grace)) { 375 (card->bm_generation != generation && grace)) {
231 /* 376 /*
@@ -240,8 +385,8 @@ static void fw_card_bm_work(struct work_struct *work)
240 * next generation. 385 * next generation.
241 */ 386 */
242 387
243 irm_id = card->irm_node->node_id; 388 irm_id = irm_node->node_id;
244 if (!card->irm_node->link_on) { 389 if (!irm_node->link_on) {
245 new_root_id = local_node->node_id; 390 new_root_id = local_node->node_id;
246 fw_notify("IRM has link off, making local node (%02x) root.\n", 391 fw_notify("IRM has link off, making local node (%02x) root.\n",
247 new_root_id); 392 new_root_id);
@@ -263,9 +408,15 @@ static void fw_card_bm_work(struct work_struct *work)
263 goto out; 408 goto out;
264 409
265 if (rcode == RCODE_COMPLETE && 410 if (rcode == RCODE_COMPLETE &&
266 lock_data[0] != cpu_to_be32(0x3f)) 411 lock_data[0] != cpu_to_be32(0x3f)) {
267 /* Somebody else is BM, let them do the work. */ 412 /* Somebody else is BM, let them do the work. */
413 if (irm_id == local_node->node_id) {
414 /* But we are IRM, so do irm-y things */
415 irm_allocate_broadcast(irm_device,
416 card->device);
417 }
268 goto out; 418 goto out;
419 }
269 420
270 spin_lock_irqsave(&card->lock, flags); 421 spin_lock_irqsave(&card->lock, flags);
271 422
@@ -357,10 +508,19 @@ static void fw_card_bm_work(struct work_struct *work)
357 card->index, new_root_id, gap_count); 508 card->index, new_root_id, gap_count);
358 fw_send_phy_config(card, new_root_id, generation, gap_count); 509 fw_send_phy_config(card, new_root_id, generation, gap_count);
359 fw_core_initiate_bus_reset(card, 1); 510 fw_core_initiate_bus_reset(card, 1);
511 } else if (irm_node->node_id == local_node->node_id) {
512 /*
513 * We are IRM, so do irm-y things.
514 * There's no reason to do this if we're doing a reset. . .
515 * We'll be back.
516 */
517 irm_allocate_broadcast(irm_device, card->device);
360 } 518 }
519
361 out: 520 out:
362 fw_node_put(root_node); 521 fw_node_put(root_node);
363 fw_node_put(local_node); 522 fw_node_put(local_node);
523 fw_node_put(irm_node);
364 out_put_card: 524 out_put_card:
365 fw_card_put(card); 525 fw_card_put(card);
366} 526}
diff --git a/drivers/firewire/fw-device.c b/drivers/firewire/fw-device.c
index 633e44de5d1a..a40444e8eb20 100644
--- a/drivers/firewire/fw-device.c
+++ b/drivers/firewire/fw-device.c
@@ -849,6 +849,9 @@ static void fw_device_init(struct work_struct *work)
849 device->config_rom[3], device->config_rom[4], 849 device->config_rom[3], device->config_rom[4],
850 1 << device->max_speed); 850 1 << device->max_speed);
851 device->config_rom_retries = 0; 851 device->config_rom_retries = 0;
852 if (device->card->is_irm)
853 fw_irm_set_broadcast_channel_register(&device->device,
854 NULL);
852 } 855 }
853 856
854 /* 857 /*
diff --git a/drivers/firewire/fw-transaction.h b/drivers/firewire/fw-transaction.h
index eed2e295eb3c..f90f09c05833 100644
--- a/drivers/firewire/fw-transaction.h
+++ b/drivers/firewire/fw-transaction.h
@@ -230,6 +230,11 @@ struct fw_card {
230 u8 color; /* must be u8 to match the definition in struct fw_node */ 230 u8 color; /* must be u8 to match the definition in struct fw_node */
231 int gap_count; 231 int gap_count;
232 bool beta_repeaters_present; 232 bool beta_repeaters_present;
233 /*
234 * Set if the local device is the IRM and the broadcast channel
235 * was allocated.
236 */
237 bool is_irm;
233 238
234 int index; 239 int index;
235 240
@@ -438,4 +443,7 @@ void fw_core_handle_bus_reset(struct fw_card *card, int node_id,
438void fw_core_handle_request(struct fw_card *card, struct fw_packet *request); 443void fw_core_handle_request(struct fw_card *card, struct fw_packet *request);
439void fw_core_handle_response(struct fw_card *card, struct fw_packet *packet); 444void fw_core_handle_response(struct fw_card *card, struct fw_packet *packet);
440 445
446extern int fw_irm_set_broadcast_channel_register(struct device *dev,
447 void *data);
448
441#endif /* __fw_transaction_h */ 449#endif /* __fw_transaction_h */