summaryrefslogtreecommitdiff
path: root/drivers/firewire
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/firewire')
-rw-r--r--drivers/firewire/Kconfig13
-rw-r--r--drivers/firewire/fw-card.c34
-rw-r--r--drivers/firewire/fw-cdev.c29
-rw-r--r--drivers/firewire/fw-device.c5
-rw-r--r--drivers/firewire/fw-device.h1
-rw-r--r--drivers/firewire/fw-iso.c2
-rw-r--r--drivers/firewire/fw-ohci.c40
-rw-r--r--drivers/firewire/fw-sbp2.c36
-rw-r--r--drivers/firewire/fw-topology.c2
-rw-r--r--drivers/firewire/fw-transaction.c111
-rw-r--r--drivers/firewire/fw-transaction.h34
11 files changed, 187 insertions, 120 deletions
diff --git a/drivers/firewire/Kconfig b/drivers/firewire/Kconfig
index 76f26710fc16..450902438208 100644
--- a/drivers/firewire/Kconfig
+++ b/drivers/firewire/Kconfig
@@ -12,12 +12,17 @@ config FIREWIRE
This is the "Juju" FireWire stack, a new alternative implementation
designed for robustness and simplicity. You can build either this
stack, or the old stack (the ieee1394 driver, ohci1394 etc.) or both.
- Please read http://wiki.linux1394.org/JujuMigration before you
- enable the new stack.
+ Please read http://ieee1394.wiki.kernel.org/index.php/Juju_Migration
+ before you enable the new stack.
To compile this driver as a module, say M here: the module will be
- called firewire-core. It functionally replaces ieee1394, raw1394,
- and video1394.
+ called firewire-core.
+
+ This module functionally replaces ieee1394, raw1394, and video1394.
+ To access it from application programs, you generally need at least
+ libraw1394 version 2. IIDC/DCAM applications also need libdc1394
+ version 2. No libraries are required to access storage devices
+ through the firewire-sbp2 driver.
config FIREWIRE_OHCI
tristate "OHCI-1394 controllers"
diff --git a/drivers/firewire/fw-card.c b/drivers/firewire/fw-card.c
index 5b4c0d9f5173..bbd73a406e53 100644
--- a/drivers/firewire/fw-card.c
+++ b/drivers/firewire/fw-card.c
@@ -16,12 +16,15 @@
* 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"
@@ -396,14 +399,16 @@ fw_card_initialize(struct fw_card *card, const struct fw_card_driver *driver,
{
static atomic_t index = ATOMIC_INIT(-1);
- 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,
@@ -496,7 +501,6 @@ dummy_enable_phys_dma(struct fw_card *card,
}
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,
@@ -507,6 +511,14 @@ static struct fw_card_driver dummy_driver = {
};
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->update_phy_reg(card, 4,
@@ -521,15 +533,13 @@ 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);
}
EXPORT_SYMBOL(fw_core_remove_card);
diff --git a/drivers/firewire/fw-cdev.c b/drivers/firewire/fw-cdev.c
index c639915fc3cb..2e6d5848d217 100644
--- a/drivers/firewire/fw-cdev.c
+++ b/drivers/firewire/fw-cdev.c
@@ -369,22 +369,33 @@ complete_transaction(struct fw_card *card, int rcode,
struct response *response = data;
struct client *client = response->client;
unsigned long flags;
+ struct fw_cdev_event_response *r = &response->response;
- if (length < response->response.length)
- response->response.length = length;
+ if (length < r->length)
+ r->length = length;
if (rcode == RCODE_COMPLETE)
- memcpy(response->response.data, payload,
- response->response.length);
+ memcpy(r->data, payload, r->length);
spin_lock_irqsave(&client->lock, flags);
list_del(&response->resource.link);
spin_unlock_irqrestore(&client->lock, flags);
- response->response.type = FW_CDEV_EVENT_RESPONSE;
- response->response.rcode = rcode;
- queue_event(client, &response->event,
- &response->response, sizeof(response->response),
- response->response.data, response->response.length);
+ r->type = FW_CDEV_EVENT_RESPONSE;
+ r->rcode = rcode;
+
+ /*
+ * In the case that sizeof(*r) doesn't align with the position of the
+ * data, and the read is short, preserve an extra copy of the data
+ * to stay compatible with a pre-2.6.27 bug. Since the bug is harmless
+ * for short reads and some apps depended on it, this is both safe
+ * and prudent for compatibility.
+ */
+ if (r->length <= sizeof(*r) - offsetof(typeof(*r), data))
+ queue_event(client, &response->event, r, sizeof(*r),
+ r->data, r->length);
+ else
+ queue_event(client, &response->event, r, sizeof(*r) + r->length,
+ NULL, 0);
}
static int ioctl_send_request(struct client *client, void *buffer)
diff --git a/drivers/firewire/fw-device.c b/drivers/firewire/fw-device.c
index d9c8daf7ae7d..0855fb5568e8 100644
--- a/drivers/firewire/fw-device.c
+++ b/drivers/firewire/fw-device.c
@@ -168,7 +168,7 @@ static void fw_device_release(struct device *dev)
fw_node_put(device->node);
kfree(device->config_rom);
kfree(device);
- atomic_dec(&card->device_count);
+ fw_card_put(card);
}
int fw_device_enable_phys_dma(struct fw_device *device)
@@ -946,8 +946,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
*/
device_initialize(&device->device);
atomic_set(&device->state, FW_DEVICE_INITIALIZING);
- atomic_inc(&card->device_count);
- device->card = card;
+ device->card = fw_card_get(card);
device->node = fw_node_get(node);
device->node_id = node->node_id;
device->generation = card->generation;
diff --git a/drivers/firewire/fw-device.h b/drivers/firewire/fw-device.h
index 5f131f5129da..42305bbac72f 100644
--- a/drivers/firewire/fw-device.h
+++ b/drivers/firewire/fw-device.h
@@ -62,7 +62,6 @@ struct fw_device {
bool cmc;
struct fw_card *card;
struct device device;
- struct list_head link;
struct list_head client_list;
u32 *config_rom;
size_t config_rom_length;
diff --git a/drivers/firewire/fw-iso.c b/drivers/firewire/fw-iso.c
index bcbe794a3ea5..e14c03dc0065 100644
--- a/drivers/firewire/fw-iso.c
+++ b/drivers/firewire/fw-iso.c
@@ -50,7 +50,7 @@ fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card,
address = dma_map_page(card->device, buffer->pages[i],
0, PAGE_SIZE, direction);
- if (dma_mapping_error(address)) {
+ if (dma_mapping_error(card->device, address)) {
__free_page(buffer->pages[i]);
goto out_pages;
}
diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c
index 0b66306af479..251416f2148f 100644
--- a/drivers/firewire/fw-ohci.c
+++ b/drivers/firewire/fw-ohci.c
@@ -171,7 +171,6 @@ struct iso_context {
struct fw_ohci {
struct fw_card card;
- u32 version;
__iomem char *registers;
dma_addr_t self_id_bus;
__le32 *self_id_cpu;
@@ -180,6 +179,8 @@ struct fw_ohci {
int generation;
int request_generation; /* for timestamping incoming requests */
u32 bus_seconds;
+
+ bool use_dualbuffer;
bool old_uninorth;
bool bus_reset_packet_quirk;
@@ -953,7 +954,7 @@ at_context_queue_packet(struct context *ctx, struct fw_packet *packet)
payload_bus =
dma_map_single(ohci->card.device, packet->payload,
packet->payload_length, DMA_TO_DEVICE);
- if (dma_mapping_error(payload_bus)) {
+ if (dma_mapping_error(ohci->card.device, payload_bus)) {
packet->ack = RCODE_SEND_ERROR;
return -1;
}
@@ -1885,7 +1886,7 @@ ohci_allocate_iso_context(struct fw_card *card, int type, size_t header_size)
} else {
mask = &ohci->ir_context_mask;
list = ohci->ir_context_list;
- if (ohci->version >= OHCI_VERSION_1_1)
+ if (ohci->use_dualbuffer)
callback = handle_ir_dualbuffer_packet;
else
callback = handle_ir_packet_per_buffer;
@@ -1949,7 +1950,7 @@ static int ohci_start_iso(struct fw_iso_context *base,
} else {
index = ctx - ohci->ir_context_list;
control = IR_CONTEXT_ISOCH_HEADER;
- if (ohci->version >= OHCI_VERSION_1_1)
+ if (ohci->use_dualbuffer)
control |= IR_CONTEXT_DUAL_BUFFER_MODE;
match = (tags << 28) | (sync << 8) | ctx->base.channel;
if (cycle >= 0) {
@@ -2279,7 +2280,7 @@ ohci_queue_iso(struct fw_iso_context *base,
spin_lock_irqsave(&ctx->context.ohci->lock, flags);
if (base->type == FW_ISO_CONTEXT_TRANSMIT)
retval = ohci_queue_iso_transmit(base, packet, buffer, payload);
- else if (ctx->context.ohci->version >= OHCI_VERSION_1_1)
+ else if (ctx->context.ohci->use_dualbuffer)
retval = ohci_queue_iso_receive_dualbuffer(base, packet,
buffer, payload);
else
@@ -2292,7 +2293,6 @@ ohci_queue_iso(struct fw_iso_context *base,
}
static const struct fw_card_driver ohci_driver = {
- .name = ohci_driver_name,
.enable = ohci_enable,
.update_phy_reg = ohci_update_phy_reg,
.set_config_rom = ohci_set_config_rom,
@@ -2342,7 +2342,7 @@ static int __devinit
pci_probe(struct pci_dev *dev, const struct pci_device_id *ent)
{
struct fw_ohci *ohci;
- u32 bus_options, max_receive, link_speed;
+ u32 bus_options, max_receive, link_speed, version;
u64 guid;
int err;
size_t size;
@@ -2367,12 +2367,6 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent)
pci_write_config_dword(dev, OHCI1394_PCI_HCI_Control, 0);
pci_set_drvdata(dev, ohci);
-#if defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32)
- ohci->old_uninorth = dev->vendor == PCI_VENDOR_ID_APPLE &&
- dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW;
-#endif
- ohci->bus_reset_packet_quirk = dev->vendor == PCI_VENDOR_ID_TI;
-
spin_lock_init(&ohci->lock);
tasklet_init(&ohci->bus_reset_tasklet,
@@ -2391,6 +2385,23 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent)
goto fail_iomem;
}
+ version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff;
+ ohci->use_dualbuffer = version >= OHCI_VERSION_1_1;
+
+/* x86-32 currently doesn't use highmem for dma_alloc_coherent */
+#if !defined(CONFIG_X86_32)
+ /* dual-buffer mode is broken with descriptor addresses above 2G */
+ if (dev->vendor == PCI_VENDOR_ID_TI &&
+ dev->device == PCI_DEVICE_ID_TI_TSB43AB22)
+ ohci->use_dualbuffer = false;
+#endif
+
+#if defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32)
+ ohci->old_uninorth = dev->vendor == PCI_VENDOR_ID_APPLE &&
+ dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW;
+#endif
+ ohci->bus_reset_packet_quirk = dev->vendor == PCI_VENDOR_ID_TI;
+
ar_context_init(&ohci->ar_request_ctx, ohci,
OHCI1394_AsReqRcvContextControlSet);
@@ -2442,9 +2453,8 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent)
if (err < 0)
goto fail_self_id;
- ohci->version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff;
fw_notify("Added fw-ohci device %s, OHCI version %x.%x\n",
- dev->dev.bus_id, ohci->version >> 16, ohci->version & 0xff);
+ dev->dev.bus_id, version >> 16, version & 0xff);
return 0;
fail_self_id:
diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c
index b2458bb8e9ca..aaff50ebba1d 100644
--- a/drivers/firewire/fw-sbp2.c
+++ b/drivers/firewire/fw-sbp2.c
@@ -86,6 +86,11 @@ MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device "
* - delay inquiry
* Wait extra SBP2_INQUIRY_DELAY seconds after login before SCSI inquiry.
*
+ * - power condition
+ * Set the power condition field in the START STOP UNIT commands sent by
+ * sd_mod on suspend, resume, and shutdown (if manage_start_stop is on).
+ * Some disks need this to spin down or to resume properly.
+ *
* - override internal blacklist
* Instead of adding to the built-in blacklist, use only the workarounds
* specified in the module load parameter.
@@ -97,6 +102,7 @@ MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device "
#define SBP2_WORKAROUND_FIX_CAPACITY 0x8
#define SBP2_WORKAROUND_DELAY_INQUIRY 0x10
#define SBP2_INQUIRY_DELAY 12
+#define SBP2_WORKAROUND_POWER_CONDITION 0x20
#define SBP2_WORKAROUND_OVERRIDE 0x100
static int sbp2_param_workarounds;
@@ -107,6 +113,8 @@ MODULE_PARM_DESC(workarounds, "Work around device bugs (default = 0"
", skip mode page 8 = " __stringify(SBP2_WORKAROUND_MODE_SENSE_8)
", fix capacity = " __stringify(SBP2_WORKAROUND_FIX_CAPACITY)
", delay inquiry = " __stringify(SBP2_WORKAROUND_DELAY_INQUIRY)
+ ", set power condition in start stop unit = "
+ __stringify(SBP2_WORKAROUND_POWER_CONDITION)
", override internal blacklist = " __stringify(SBP2_WORKAROUND_OVERRIDE)
", or a combination)");
@@ -310,18 +318,25 @@ static const struct {
.firmware_revision = 0x002800,
.model = 0x001010,
.workarounds = SBP2_WORKAROUND_INQUIRY_36 |
- SBP2_WORKAROUND_MODE_SENSE_8,
+ SBP2_WORKAROUND_MODE_SENSE_8 |
+ SBP2_WORKAROUND_POWER_CONDITION,
},
/* DViCO Momobay FX-3A with TSB42AA9A bridge */ {
.firmware_revision = 0x002800,
.model = 0x000000,
- .workarounds = SBP2_WORKAROUND_DELAY_INQUIRY,
+ .workarounds = SBP2_WORKAROUND_DELAY_INQUIRY |
+ SBP2_WORKAROUND_POWER_CONDITION,
},
/* Initio bridges, actually only needed for some older ones */ {
.firmware_revision = 0x000200,
.model = ~0,
.workarounds = SBP2_WORKAROUND_INQUIRY_36,
},
+ /* PL-3507 bridge with Prolific firmware */ {
+ .firmware_revision = 0x012800,
+ .model = ~0,
+ .workarounds = SBP2_WORKAROUND_POWER_CONDITION,
+ },
/* Symbios bridge */ {
.firmware_revision = 0xa0b800,
.model = ~0,
@@ -528,7 +543,7 @@ sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id,
orb->response_bus =
dma_map_single(device->card->device, &orb->response,
sizeof(orb->response), DMA_FROM_DEVICE);
- if (dma_mapping_error(orb->response_bus))
+ if (dma_mapping_error(device->card->device, orb->response_bus))
goto fail_mapping_response;
orb->request.response.high = 0;
@@ -562,7 +577,7 @@ sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id,
orb->base.request_bus =
dma_map_single(device->card->device, &orb->request,
sizeof(orb->request), DMA_TO_DEVICE);
- if (dma_mapping_error(orb->base.request_bus))
+ if (dma_mapping_error(device->card->device, orb->base.request_bus))
goto fail_mapping_request;
sbp2_send_orb(&orb->base, lu, node_id, generation,
@@ -1051,7 +1066,8 @@ static int sbp2_scan_unit_dir(struct sbp2_target *tgt, u32 *directory,
break;
case SBP2_CSR_LOGICAL_UNIT_DIRECTORY:
- if (sbp2_scan_logical_unit_dir(tgt, ci.p + value) < 0)
+ /* Adjust for the increment in the iterator */
+ if (sbp2_scan_logical_unit_dir(tgt, ci.p - 1 + value) < 0)
return -ENOMEM;
break;
}
@@ -1408,7 +1424,7 @@ sbp2_map_scatterlist(struct sbp2_command_orb *orb, struct fw_device *device,
orb->page_table_bus =
dma_map_single(device->card->device, orb->page_table,
sizeof(orb->page_table), DMA_TO_DEVICE);
- if (dma_mapping_error(orb->page_table_bus))
+ if (dma_mapping_error(device->card->device, orb->page_table_bus))
goto fail_page_table;
/*
@@ -1493,7 +1509,7 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done)
orb->base.request_bus =
dma_map_single(device->card->device, &orb->request,
sizeof(orb->request), DMA_TO_DEVICE);
- if (dma_mapping_error(orb->base.request_bus))
+ if (dma_mapping_error(device->card->device, orb->base.request_bus))
goto out;
sbp2_send_orb(&orb->base, lu, lu->tgt->node_id, lu->generation,
@@ -1529,6 +1545,9 @@ static int sbp2_scsi_slave_configure(struct scsi_device *sdev)
sdev->use_10_for_rw = 1;
+ if (sbp2_param_exclusive_login)
+ sdev->manage_start_stop = 1;
+
if (sdev->type == TYPE_ROM)
sdev->use_10_for_ms = 1;
@@ -1539,6 +1558,9 @@ static int sbp2_scsi_slave_configure(struct scsi_device *sdev)
if (lu->tgt->workarounds & SBP2_WORKAROUND_FIX_CAPACITY)
sdev->fix_capacity = 1;
+ if (lu->tgt->workarounds & SBP2_WORKAROUND_POWER_CONDITION)
+ sdev->start_stop_pwr_cond = 1;
+
if (lu->tgt->workarounds & SBP2_WORKAROUND_128K_MAX_TRANS)
blk_queue_max_sectors(sdev->request_queue, 128 * 1024 / 512);
diff --git a/drivers/firewire/fw-topology.c b/drivers/firewire/fw-topology.c
index 213b0ff8f3d6..c1b81077c4a8 100644
--- a/drivers/firewire/fw-topology.c
+++ b/drivers/firewire/fw-topology.c
@@ -510,8 +510,6 @@ fw_core_handle_bus_reset(struct fw_card *card,
struct fw_node *local_node;
unsigned long flags;
- fw_flush_transactions(card);
-
spin_lock_irqsave(&card->lock, flags);
/*
diff --git a/drivers/firewire/fw-transaction.c b/drivers/firewire/fw-transaction.c
index 03ae8a77c479..e5d1a0b64fcf 100644
--- a/drivers/firewire/fw-transaction.c
+++ b/drivers/firewire/fw-transaction.c
@@ -22,6 +22,7 @@
#include <linux/kernel.h>
#include <linux/kref.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
@@ -55,6 +56,9 @@
#define HEADER_GET_DATA_LENGTH(q) (((q) >> 16) & 0xffff)
#define HEADER_GET_EXTENDED_TCODE(q) (((q) >> 0) & 0xffff)
+#define HEADER_DESTINATION_IS_BROADCAST(q) \
+ (((q) & HEADER_DESTINATION(0x3f)) == HEADER_DESTINATION(0x3f))
+
#define PHY_CONFIG_GAP_COUNT(gap_count) (((gap_count) << 16) | (1 << 22))
#define PHY_CONFIG_ROOT_ID(node_id) ((((node_id) & 0x3f) << 24) | (1 << 23))
#define PHY_IDENTIFIER(id) ((id) << 30)
@@ -148,7 +152,7 @@ transmit_complete_callback(struct fw_packet *packet,
static void
fw_fill_request(struct fw_packet *packet, int tcode, int tlabel,
- int node_id, int source_id, int generation, int speed,
+ int destination_id, int source_id, int generation, int speed,
unsigned long long offset, void *payload, size_t length)
{
int ext_tcode;
@@ -163,7 +167,7 @@ fw_fill_request(struct fw_packet *packet, int tcode, int tlabel,
HEADER_RETRY(RETRY_X) |
HEADER_TLABEL(tlabel) |
HEADER_TCODE(tcode) |
- HEADER_DESTINATION(node_id);
+ HEADER_DESTINATION(destination_id);
packet->header[1] =
HEADER_OFFSET_HIGH(offset >> 32) | HEADER_SOURCE(source_id);
packet->header[2] =
@@ -249,7 +253,7 @@ fw_send_request(struct fw_card *card, struct fw_transaction *t,
fw_transaction_callback_t callback, void *callback_data)
{
unsigned long flags;
- int tlabel, source;
+ int tlabel;
/*
* Bump the flush timer up 100ms first of all so we
@@ -265,7 +269,6 @@ fw_send_request(struct fw_card *card, struct fw_transaction *t,
spin_lock_irqsave(&card->lock, flags);
- source = card->node_id;
tlabel = card->current_tlabel;
if (card->tlabel_mask & (1 << tlabel)) {
spin_unlock_irqrestore(&card->lock, flags);
@@ -276,77 +279,58 @@ fw_send_request(struct fw_card *card, struct fw_transaction *t,
card->current_tlabel = (card->current_tlabel + 1) & 0x1f;
card->tlabel_mask |= (1 << tlabel);
- list_add_tail(&t->link, &card->transaction_list);
-
- spin_unlock_irqrestore(&card->lock, flags);
-
- /* Initialize rest of transaction, fill out packet and send it. */
t->node_id = node_id;
t->tlabel = tlabel;
t->callback = callback;
t->callback_data = callback_data;
- fw_fill_request(&t->packet, tcode, t->tlabel,
- node_id, source, generation,
- speed, offset, payload, length);
+ fw_fill_request(&t->packet, tcode, t->tlabel, node_id, card->node_id,
+ generation, speed, offset, payload, length);
t->packet.callback = transmit_complete_callback;
+ list_add_tail(&t->link, &card->transaction_list);
+
+ spin_unlock_irqrestore(&card->lock, flags);
+
card->driver->send_request(card, &t->packet);
}
EXPORT_SYMBOL(fw_send_request);
-struct fw_phy_packet {
- struct fw_packet packet;
- struct completion done;
- struct kref kref;
-};
-
-static void phy_packet_release(struct kref *kref)
-{
- struct fw_phy_packet *p =
- container_of(kref, struct fw_phy_packet, kref);
- kfree(p);
-}
+static DEFINE_MUTEX(phy_config_mutex);
+static DECLARE_COMPLETION(phy_config_done);
static void transmit_phy_packet_callback(struct fw_packet *packet,
struct fw_card *card, int status)
{
- struct fw_phy_packet *p =
- container_of(packet, struct fw_phy_packet, packet);
-
- complete(&p->done);
- kref_put(&p->kref, phy_packet_release);
+ complete(&phy_config_done);
}
+static struct fw_packet phy_config_packet = {
+ .header_length = 8,
+ .payload_length = 0,
+ .speed = SCODE_100,
+ .callback = transmit_phy_packet_callback,
+};
+
void fw_send_phy_config(struct fw_card *card,
int node_id, int generation, int gap_count)
{
- struct fw_phy_packet *p;
long timeout = DIV_ROUND_UP(HZ, 10);
u32 data = PHY_IDENTIFIER(PHY_PACKET_CONFIG) |
PHY_CONFIG_ROOT_ID(node_id) |
PHY_CONFIG_GAP_COUNT(gap_count);
- p = kmalloc(sizeof(*p), GFP_KERNEL);
- if (p == NULL)
- return;
+ mutex_lock(&phy_config_mutex);
+
+ phy_config_packet.header[0] = data;
+ phy_config_packet.header[1] = ~data;
+ phy_config_packet.generation = generation;
+ INIT_COMPLETION(phy_config_done);
- p->packet.header[0] = data;
- p->packet.header[1] = ~data;
- p->packet.header_length = 8;
- p->packet.payload_length = 0;
- p->packet.speed = SCODE_100;
- p->packet.generation = generation;
- p->packet.callback = transmit_phy_packet_callback;
- init_completion(&p->done);
- kref_set(&p->kref, 2);
-
- card->driver->send_request(card, &p->packet);
- timeout = wait_for_completion_timeout(&p->done, timeout);
- kref_put(&p->kref, phy_packet_release);
-
- /* will leak p if the callback is never executed */
- WARN_ON(timeout == 0);
+ card->driver->send_request(card, &phy_config_packet);
+ wait_for_completion_timeout(&phy_config_done, timeout);
+
+ mutex_unlock(&phy_config_mutex);
}
void fw_flush_transactions(struct fw_card *card)
@@ -624,12 +608,9 @@ allocate_request(struct fw_packet *p)
void
fw_send_response(struct fw_card *card, struct fw_request *request, int rcode)
{
- /*
- * Broadcast packets are reported as ACK_COMPLETE, so this
- * check is sufficient to ensure we don't send response to
- * broadcast packets or posted writes.
- */
- if (request->ack != ACK_PENDING) {
+ /* unified transaction or broadcast transaction: don't respond */
+ if (request->ack != ACK_PENDING ||
+ HEADER_DESTINATION_IS_BROADCAST(request->request_header[0])) {
kfree(request);
return;
}
@@ -817,12 +798,13 @@ handle_registers(struct fw_card *card, struct fw_request *request,
int reg = offset & ~CSR_REGISTER_BASE;
unsigned long long bus_time;
__be32 *data = payload;
+ int rcode = RCODE_COMPLETE;
switch (reg) {
case CSR_CYCLE_TIME:
case CSR_BUS_TIME:
if (!TCODE_IS_READ_REQUEST(tcode) || length != 4) {
- fw_send_response(card, request, RCODE_TYPE_ERROR);
+ rcode = RCODE_TYPE_ERROR;
break;
}
@@ -831,7 +813,17 @@ handle_registers(struct fw_card *card, struct fw_request *request,
*data = cpu_to_be32(bus_time);
else
*data = cpu_to_be32(bus_time >> 25);
- fw_send_response(card, request, RCODE_COMPLETE);
+ break;
+
+ case CSR_BROADCAST_CHANNEL:
+ if (tcode == TCODE_READ_QUADLET_REQUEST)
+ *data = cpu_to_be32(card->broadcast_channel);
+ else if (tcode == TCODE_WRITE_QUADLET_REQUEST)
+ card->broadcast_channel =
+ (be32_to_cpu(*data) & BROADCAST_CHANNEL_VALID) |
+ BROADCAST_CHANNEL_INITIAL;
+ else
+ rcode = RCODE_TYPE_ERROR;
break;
case CSR_BUS_MANAGER_ID:
@@ -850,10 +842,13 @@ handle_registers(struct fw_card *card, struct fw_request *request,
case CSR_BUSY_TIMEOUT:
/* FIXME: Implement this. */
+
default:
- fw_send_response(card, request, RCODE_ADDRESS_ERROR);
+ rcode = RCODE_ADDRESS_ERROR;
break;
}
+
+ fw_send_response(card, request, rcode);
}
static struct fw_address_handler registers = {
diff --git a/drivers/firewire/fw-transaction.h b/drivers/firewire/fw-transaction.h
index 04d3854f6560..2ae1b0d6cb7b 100644
--- a/drivers/firewire/fw-transaction.h
+++ b/drivers/firewire/fw-transaction.h
@@ -19,14 +19,15 @@
#ifndef __fw_transaction_h
#define __fw_transaction_h
+#include <linux/completion.h>
#include <linux/device.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/fs.h>
#include <linux/dma-mapping.h>
#include <linux/firewire-constants.h>
-#include <asm/atomic.h>
+#include <linux/kref.h>
+#include <linux/list.h>
+#include <linux/spinlock_types.h>
+#include <linux/timer.h>
+#include <linux/workqueue.h>
#define TCODE_IS_READ_REQUEST(tcode) (((tcode) & ~1) == 4)
#define TCODE_IS_BLOCK_PACKET(tcode) (((tcode) & 1) != 0)
@@ -80,6 +81,9 @@
#define CSR_SPEED_MAP 0x2000
#define CSR_SPEED_MAP_END 0x3000
+#define BROADCAST_CHANNEL_INITIAL (1 << 31 | 31)
+#define BROADCAST_CHANNEL_VALID (1 << 30)
+
#define fw_notify(s, args...) printk(KERN_NOTICE KBUILD_MODNAME ": " s, ## args)
#define fw_error(s, args...) printk(KERN_ERR KBUILD_MODNAME ": " s, ## args)
@@ -216,7 +220,8 @@ extern struct bus_type fw_bus_type;
struct fw_card {
const struct fw_card_driver *driver;
struct device *device;
- atomic_t device_count;
+ struct kref kref;
+ struct completion done;
int node_id;
int generation;
@@ -236,6 +241,7 @@ struct fw_card {
*/
int self_id_count;
u32 topology_map[252 + 3];
+ u32 broadcast_channel;
spinlock_t lock; /* Take this lock when handling the lists in
* this struct. */
@@ -256,6 +262,20 @@ struct fw_card {
int bm_generation;
};
+static inline struct fw_card *fw_card_get(struct fw_card *card)
+{
+ kref_get(&card->kref);
+
+ return card;
+}
+
+void fw_card_release(struct kref *kref);
+
+static inline void fw_card_put(struct fw_card *card)
+{
+ kref_put(&card->kref, fw_card_release);
+}
+
/*
* The iso packet format allows for an immediate header/payload part
* stored in 'header' immediately after the packet info plus an
@@ -348,8 +368,6 @@ int
fw_iso_context_stop(struct fw_iso_context *ctx);
struct fw_card_driver {
- const char *name;
-
/*
* Enable the given card with the given initial config rom.
* This function is expected to activate the card, and either