* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#include <linux/module.h>
-#include <linux/errno.h>
+#include <linux/completion.h>
+#include <linux/crc-itu-t.h>
#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/kref.h>
+#include <linux/module.h>
#include <linux/mutex.h>
-#include <linux/crc-itu-t.h>
+
#include "fw-transaction.h"
#include "fw-topology.h"
#include "fw-device.h"
return 0;
}
-EXPORT_SYMBOL(fw_core_add_descriptor);
void
fw_core_remove_descriptor(struct fw_descriptor *desc)
mutex_unlock(&card_mutex);
}
-EXPORT_SYMBOL(fw_core_remove_descriptor);
static const char gap_count_table[] = {
63, 5, 7, 8, 10, 13, 16, 18, 21, 24, 26, 29, 32, 35, 37, 40
};
-struct bm_data {
- struct fw_transaction t;
- struct {
- __be32 arg;
- __be32 data;
- } lock;
- u32 old;
- int rcode;
- struct completion done;
-};
-
-static void
-complete_bm_lock(struct fw_card *card, int rcode,
- void *payload, size_t length, void *data)
-{
- struct bm_data *bmd = data;
-
- if (rcode == RCODE_COMPLETE)
- bmd->old = be32_to_cpu(*(__be32 *) payload);
- bmd->rcode = rcode;
- complete(&bmd->done);
-}
-
static void
fw_card_bm_work(struct work_struct *work)
{
struct fw_card *card = container_of(work, struct fw_card, work.work);
struct fw_device *root_device;
struct fw_node *root_node, *local_node;
- struct bm_data bmd;
unsigned long flags;
- int root_id, new_root_id, irm_id, gap_count, generation, grace;
- int do_reset = 0;
+ int root_id, new_root_id, irm_id, gap_count, generation, grace, rcode;
+ bool do_reset = false;
+ __be32 lock_data[2];
spin_lock_irqsave(&card->lock, flags);
local_node = card->local_node;
goto pick_me;
}
- bmd.lock.arg = cpu_to_be32(0x3f);
- bmd.lock.data = cpu_to_be32(local_node->node_id);
+ lock_data[0] = cpu_to_be32(0x3f);
+ lock_data[1] = cpu_to_be32(local_node->node_id);
spin_unlock_irqrestore(&card->lock, flags);
- init_completion(&bmd.done);
- fw_send_request(card, &bmd.t, TCODE_LOCK_COMPARE_SWAP,
- irm_id, generation,
- SCODE_100, CSR_REGISTER_BASE + CSR_BUS_MANAGER_ID,
- &bmd.lock, sizeof(bmd.lock),
- complete_bm_lock, &bmd);
- wait_for_completion(&bmd.done);
+ rcode = fw_run_transaction(card, TCODE_LOCK_COMPARE_SWAP,
+ irm_id, generation, SCODE_100,
+ CSR_REGISTER_BASE + CSR_BUS_MANAGER_ID,
+ lock_data, sizeof(lock_data));
- if (bmd.rcode == RCODE_GENERATION) {
- /*
- * Another bus reset happened. Just return,
- * the BM work has been rescheduled.
- */
+ if (rcode == RCODE_GENERATION)
+ /* Another bus reset, BM work has been rescheduled. */
goto out;
- }
- if (bmd.rcode == RCODE_COMPLETE && bmd.old != 0x3f)
+ if (rcode == RCODE_COMPLETE &&
+ lock_data[0] != cpu_to_be32(0x3f))
/* Somebody else is BM, let them do the work. */
goto out;
spin_lock_irqsave(&card->lock, flags);
- if (bmd.rcode != RCODE_COMPLETE) {
+
+ if (rcode != RCODE_COMPLETE) {
/*
* The lock request failed, maybe the IRM
* isn't really IRM capable after all. Let's
*/
spin_unlock_irqrestore(&card->lock, flags);
goto out;
- } else if (root_device->config_rom[2] & BIB_CMC) {
+ } else if (root_device->cmc) {
/*
* FIXME: I suppose we should set the cmstr bit in the
* STATE_CLEAR register of this node, as described in
gap_count = 63;
/*
- * Finally, figure out if we should do a reset or not. If we've
- * done less that 5 resets with the same physical topology and we
+ * Finally, figure out if we should do a reset or not. If we have
+ * done less than 5 resets with the same physical topology and we
* have either a new root or a new gap count setting, let's do it.
*/
if (card->bm_retries++ < 5 &&
(card->gap_count != gap_count || new_root_id != root_id))
- do_reset = 1;
+ do_reset = true;
spin_unlock_irqrestore(&card->lock, flags);
{
static atomic_t index = ATOMIC_INIT(-1);
- kref_init(&card->kref);
- atomic_set(&card->device_count, 0);
card->index = atomic_inc_return(&index);
card->driver = driver;
card->device = device;
card->current_tlabel = 0;
card->tlabel_mask = 0;
card->color = 0;
+ card->broadcast_channel = BROADCAST_CHANNEL_INITIAL;
+ kref_init(&card->kref);
+ init_completion(&card->done);
INIT_LIST_HEAD(&card->transaction_list);
spin_lock_init(&card->lock);
setup_timer(&card->flush_timer,
card->link_speed = link_speed;
card->guid = guid;
- /*
- * The subsystem grabs a reference when the card is added and
- * drops it when the driver calls fw_core_remove_card.
- */
- fw_card_get(card);
-
mutex_lock(&card_mutex);
config_rom = generate_config_rom(card, &length);
list_add_tail(&card->link, &card_list);
}
static struct fw_card_driver dummy_driver = {
- .name = "dummy",
.enable = dummy_enable,
.update_phy_reg = dummy_update_phy_reg,
.set_config_rom = dummy_set_config_rom,
.enable_phys_dma = dummy_enable_phys_dma,
};
+void
+fw_card_release(struct kref *kref)
+{
+ struct fw_card *card = container_of(kref, struct fw_card, kref);
+
+ complete(&card->done);
+}
+
void
fw_core_remove_card(struct fw_card *card)
{
card->driver = &dummy_driver;
fw_destroy_nodes(card);
- /*
- * Wait for all device workqueue jobs to finish. Otherwise the
- * firewire-core module could be unloaded before the jobs ran.
- */
- while (atomic_read(&card->device_count) > 0)
- msleep(100);
+
+ /* Wait for all users, especially device workqueue jobs, to finish. */
+ fw_card_put(card);
+ wait_for_completion(&card->done);
cancel_delayed_work_sync(&card->work);
- fw_flush_transactions(card);
+ WARN_ON(!list_empty(&card->transaction_list));
del_timer_sync(&card->flush_timer);
-
- fw_card_put(card);
}
EXPORT_SYMBOL(fw_core_remove_card);
-struct fw_card *
-fw_card_get(struct fw_card *card)
-{
- kref_get(&card->kref);
-
- return card;
-}
-EXPORT_SYMBOL(fw_card_get);
-
-static void
-release_card(struct kref *kref)
-{
- struct fw_card *card = container_of(kref, struct fw_card, kref);
-
- kfree(card);
-}
-
-/*
- * An assumption for fw_card_put() is that the card driver allocates
- * the fw_card struct with kalloc and that it has been shut down
- * before the last ref is dropped.
- */
-void
-fw_card_put(struct fw_card *card)
-{
- kref_put(&card->kref, release_card);
-}
-EXPORT_SYMBOL(fw_card_put);
-
int
fw_core_initiate_bus_reset(struct fw_card *card, int short_reset)
{