summaryrefslogtreecommitdiffstats
path: root/drivers/firewire
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2007-06-01 08:28:15 -0700
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-06-01 08:28:15 -0700
commitf285e3d329ce68cc355fadf4ab2c8f34d7f264cb (patch)
treea40ae43a277bedeec732fd20eee166990974fb58 /drivers/firewire
parentc1a834dc704763673df10282995257f2de93cbe9 (diff)
parentca9a7af35f1ce4a990c6c3aace65ed36f89d50bf (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6: firewire: Install firewire-constants.h and firewire-cdev.h for userspace. firewire: Change struct fw_cdev_iso_packet to not use bitfields. firewire: Implement suspend/resume PCI driver hooks. firewire: add to MAINTAINERS firewire: fw-sbp2: implement sysfs ieee1394_id ieee1394: sbp2: offer SAM-conforming target port ID in sysfs ieee1394: fix calculation of sysfs attribute "address"
Diffstat (limited to 'drivers/firewire')
-rw-r--r--drivers/firewire/fw-card.c5
-rw-r--r--drivers/firewire/fw-cdev.c17
-rw-r--r--drivers/firewire/fw-device.h1
-rw-r--r--drivers/firewire/fw-ohci.c187
-rw-r--r--drivers/firewire/fw-sbp2.c53
5 files changed, 193 insertions, 70 deletions
diff --git a/drivers/firewire/fw-card.c b/drivers/firewire/fw-card.c
index 636151a64ad..9eb1edacd82 100644
--- a/drivers/firewire/fw-card.c
+++ b/drivers/firewire/fw-card.c
@@ -407,11 +407,6 @@ fw_card_add(struct fw_card *card,
card->link_speed = link_speed;
card->guid = guid;
- /* Activate link_on bit and contender bit in our self ID packets.*/
- if (card->driver->update_phy_reg(card, 4, 0,
- PHY_LINK_ACTIVE | PHY_CONTENDER) < 0)
- return -EIO;
-
/*
* The subsystem grabs a reference when the card is added and
* drops it when the driver calls fw_core_remove_card.
diff --git a/drivers/firewire/fw-cdev.c b/drivers/firewire/fw-cdev.c
index 3ab3585d360..5d402d63799 100644
--- a/drivers/firewire/fw-cdev.c
+++ b/drivers/firewire/fw-cdev.c
@@ -677,12 +677,21 @@ static int ioctl_create_iso_context(struct client *client, void *buffer)
return 0;
}
+/* Macros for decoding the iso packet control header. */
+#define GET_PAYLOAD_LENGTH(v) ((v) & 0xffff)
+#define GET_INTERRUPT(v) (((v) >> 16) & 0x01)
+#define GET_SKIP(v) (((v) >> 17) & 0x01)
+#define GET_TAG(v) (((v) >> 18) & 0x02)
+#define GET_SY(v) (((v) >> 20) & 0x04)
+#define GET_HEADER_LENGTH(v) (((v) >> 24) & 0xff)
+
static int ioctl_queue_iso(struct client *client, void *buffer)
{
struct fw_cdev_queue_iso *request = buffer;
struct fw_cdev_iso_packet __user *p, *end, *next;
struct fw_iso_context *ctx = client->iso_context;
unsigned long payload, buffer_end, header_length;
+ u32 control;
int count;
struct {
struct fw_iso_packet packet;
@@ -717,8 +726,14 @@ static int ioctl_queue_iso(struct client *client, void *buffer)
end = (void __user *)p + request->size;
count = 0;
while (p < end) {
- if (__copy_from_user(&u.packet, p, sizeof(*p)))
+ if (get_user(control, &p->control))
return -EFAULT;
+ u.packet.payload_length = GET_PAYLOAD_LENGTH(control);
+ u.packet.interrupt = GET_INTERRUPT(control);
+ u.packet.skip = GET_SKIP(control);
+ u.packet.tag = GET_TAG(control);
+ u.packet.sy = GET_SY(control);
+ u.packet.header_length = GET_HEADER_LENGTH(control);
if (ctx->type == FW_ISO_CONTEXT_TRANSMIT) {
header_length = u.packet.header_length;
diff --git a/drivers/firewire/fw-device.h b/drivers/firewire/fw-device.h
index 0ba9d64ccf4..af1723eae4b 100644
--- a/drivers/firewire/fw-device.h
+++ b/drivers/firewire/fw-device.h
@@ -99,6 +99,7 @@ fw_unit(struct device *dev)
#define CSR_DEPENDENT_INFO 0x14
#define CSR_MODEL 0x17
#define CSR_INSTANCE 0x18
+#define CSR_DIRECTORY_ID 0x20
#define SBP2_COMMAND_SET_SPECIFIER 0x38
#define SBP2_COMMAND_SET 0x39
diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c
index 2e4cfa57126..0d08bf9b78c 100644
--- a/drivers/firewire/fw-ohci.c
+++ b/drivers/firewire/fw-ohci.c
@@ -417,12 +417,21 @@ ar_context_init(struct ar_context *ctx, struct fw_ohci *ohci, u32 regs)
ctx->current_buffer = ab.next;
ctx->pointer = ctx->current_buffer->data;
- reg_write(ctx->ohci, COMMAND_PTR(ctx->regs),
- le32_to_cpu(ab.descriptor.branch_address));
+ return 0;
+}
+
+static void ar_context_run(struct ar_context *ctx)
+{
+ struct ar_buffer *ab = ctx->current_buffer;
+ dma_addr_t ab_bus;
+ size_t offset;
+
+ offset = offsetof(struct ar_buffer, data);
+ ab_bus = ab->descriptor.data_address - offset;
+
+ reg_write(ctx->ohci, COMMAND_PTR(ctx->regs), ab_bus | 1);
reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_RUN);
flush_writes(ctx->ohci);
-
- return 0;
}
static void context_tasklet(unsigned long data)
@@ -1039,11 +1048,78 @@ static irqreturn_t irq_handler(int irq, void *data)
return IRQ_HANDLED;
}
+static int software_reset(struct fw_ohci *ohci)
+{
+ int i;
+
+ reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_softReset);
+
+ for (i = 0; i < OHCI_LOOP_COUNT; i++) {
+ if ((reg_read(ohci, OHCI1394_HCControlSet) &
+ OHCI1394_HCControl_softReset) == 0)
+ return 0;
+ msleep(1);
+ }
+
+ return -EBUSY;
+}
+
static int ohci_enable(struct fw_card *card, u32 *config_rom, size_t length)
{
struct fw_ohci *ohci = fw_ohci(card);
struct pci_dev *dev = to_pci_dev(card->device);
+ if (software_reset(ohci)) {
+ fw_error("Failed to reset ohci card.\n");
+ return -EBUSY;
+ }
+
+ /*
+ * Now enable LPS, which we need in order to start accessing
+ * most of the registers. In fact, on some cards (ALI M5251),
+ * accessing registers in the SClk domain without LPS enabled
+ * will lock up the machine. Wait 50msec to make sure we have
+ * full link enabled.
+ */
+ reg_write(ohci, OHCI1394_HCControlSet,
+ OHCI1394_HCControl_LPS |
+ OHCI1394_HCControl_postedWriteEnable);
+ flush_writes(ohci);
+ msleep(50);
+
+ reg_write(ohci, OHCI1394_HCControlClear,
+ OHCI1394_HCControl_noByteSwapData);
+
+ reg_write(ohci, OHCI1394_LinkControlSet,
+ OHCI1394_LinkControl_rcvSelfID |
+ OHCI1394_LinkControl_cycleTimerEnable |
+ OHCI1394_LinkControl_cycleMaster);
+
+ reg_write(ohci, OHCI1394_ATRetries,
+ OHCI1394_MAX_AT_REQ_RETRIES |
+ (OHCI1394_MAX_AT_RESP_RETRIES << 4) |
+ (OHCI1394_MAX_PHYS_RESP_RETRIES << 8));
+
+ ar_context_run(&ohci->ar_request_ctx);
+ ar_context_run(&ohci->ar_response_ctx);
+
+ reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->self_id_bus);
+ reg_write(ohci, OHCI1394_PhyUpperBound, 0x00010000);
+ reg_write(ohci, OHCI1394_IntEventClear, ~0);
+ reg_write(ohci, OHCI1394_IntMaskClear, ~0);
+ reg_write(ohci, OHCI1394_IntMaskSet,
+ OHCI1394_selfIDComplete |
+ OHCI1394_RQPkt | OHCI1394_RSPkt |
+ OHCI1394_reqTxComplete | OHCI1394_respTxComplete |
+ OHCI1394_isochRx | OHCI1394_isochTx |
+ OHCI1394_masterIntEnable |
+ OHCI1394_cycle64Seconds);
+
+ /* Activate link_on bit and contender bit in our self ID packets.*/
+ if (ohci_update_phy_reg(card, 4, 0,
+ PHY_LINK_ACTIVE | PHY_CONTENDER) < 0)
+ return -EIO;
+
/*
* When the link is not yet enabled, the atomic config rom
* update mechanism described below in ohci_set_config_rom()
@@ -1701,22 +1777,6 @@ static const struct fw_card_driver ohci_driver = {
.stop_iso = ohci_stop_iso,
};
-static int software_reset(struct fw_ohci *ohci)
-{
- int i;
-
- reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_softReset);
-
- for (i = 0; i < OHCI_LOOP_COUNT; i++) {
- if ((reg_read(ohci, OHCI1394_HCControlSet) &
- OHCI1394_HCControl_softReset) == 0)
- return 0;
- msleep(1);
- }
-
- return -EBUSY;
-}
-
static int __devinit
pci_probe(struct pci_dev *dev, const struct pci_device_id *ent)
{
@@ -1762,33 +1822,6 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent)
goto fail_iomem;
}
- if (software_reset(ohci)) {
- fw_error("Failed to reset ohci card.\n");
- err = -EBUSY;
- goto fail_registers;
- }
-
- /*
- * Now enable LPS, which we need in order to start accessing
- * most of the registers. In fact, on some cards (ALI M5251),
- * accessing registers in the SClk domain without LPS enabled
- * will lock up the machine. Wait 50msec to make sure we have
- * full link enabled.
- */
- reg_write(ohci, OHCI1394_HCControlSet,
- OHCI1394_HCControl_LPS |
- OHCI1394_HCControl_postedWriteEnable);
- flush_writes(ohci);
- msleep(50);
-
- reg_write(ohci, OHCI1394_HCControlClear,
- OHCI1394_HCControl_noByteSwapData);
-
- reg_write(ohci, OHCI1394_LinkControlSet,
- OHCI1394_LinkControl_rcvSelfID |
- OHCI1394_LinkControl_cycleTimerEnable |
- OHCI1394_LinkControl_cycleMaster);
-
ar_context_init(&ohci->ar_request_ctx, ohci,
OHCI1394_AsReqRcvContextControlSet);
@@ -1801,11 +1834,6 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent)
context_init(&ohci->at_response_ctx, ohci, AT_BUFFER_SIZE,
OHCI1394_AsRspTrContextControlSet, handle_at_packet);
- reg_write(ohci, OHCI1394_ATRetries,
- OHCI1394_MAX_AT_REQ_RETRIES |
- (OHCI1394_MAX_AT_RESP_RETRIES << 4) |
- (OHCI1394_MAX_PHYS_RESP_RETRIES << 8));
-
reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, ~0);
ohci->it_context_mask = reg_read(ohci, OHCI1394_IsoRecvIntMaskSet);
reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, ~0);
@@ -1835,18 +1863,6 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent)
goto fail_registers;
}
- reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->self_id_bus);
- reg_write(ohci, OHCI1394_PhyUpperBound, 0x00010000);
- reg_write(ohci, OHCI1394_IntEventClear, ~0);
- reg_write(ohci, OHCI1394_IntMaskClear, ~0);
- reg_write(ohci, OHCI1394_IntMaskSet,
- OHCI1394_selfIDComplete |
- OHCI1394_RQPkt | OHCI1394_RSPkt |
- OHCI1394_reqTxComplete | OHCI1394_respTxComplete |
- OHCI1394_isochRx | OHCI1394_isochTx |
- OHCI1394_masterIntEnable |
- OHCI1394_cycle64Seconds);
-
bus_options = reg_read(ohci, OHCI1394_BusOptions);
max_receive = (bus_options >> 12) & 0xf;
link_speed = bus_options & 0x7;
@@ -1908,6 +1924,45 @@ static void pci_remove(struct pci_dev *dev)
fw_notify("Removed fw-ohci device.\n");
}
+#ifdef CONFIG_PM
+static int pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct fw_ohci *ohci = pci_get_drvdata(pdev);
+ int err;
+
+ software_reset(ohci);
+ free_irq(pdev->irq, ohci);
+ err = pci_save_state(pdev);
+ if (err) {
+ fw_error("pci_save_state failed with %d", err);
+ return err;
+ }
+ err = pci_set_power_state(pdev, pci_choose_state(pdev, state));
+ if (err) {
+ fw_error("pci_set_power_state failed with %d", err);
+ return err;
+ }
+
+ return 0;
+}
+
+static int pci_resume(struct pci_dev *pdev)
+{
+ struct fw_ohci *ohci = pci_get_drvdata(pdev);
+ int err;
+
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+ err = pci_enable_device(pdev);
+ if (err) {
+ fw_error("pci_enable_device failed with %d", err);
+ return err;
+ }
+
+ return ohci_enable(&ohci->card, ohci->config_rom, CONFIG_ROM_SIZE);
+}
+#endif
+
static struct pci_device_id pci_table[] = {
{ PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_FIREWIRE_OHCI, ~0) },
{ }
@@ -1920,6 +1975,10 @@ static struct pci_driver fw_ohci_pci_driver = {
.id_table = pci_table,
.probe = pci_probe,
.remove = pci_remove,
+#ifdef CONFIG_PM
+ .resume = pci_resume,
+ .suspend = pci_suspend,
+#endif
};
MODULE_AUTHOR("Kristian Hoegsberg <krh@bitplanet.net>");
diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c
index 68300414e5f..a98d3915e26 100644
--- a/drivers/firewire/fw-sbp2.c
+++ b/drivers/firewire/fw-sbp2.c
@@ -1108,6 +1108,58 @@ static int sbp2_scsi_abort(struct scsi_cmnd *cmd)
return SUCCESS;
}
+/*
+ * Format of /sys/bus/scsi/devices/.../ieee1394_id:
+ * u64 EUI-64 : u24 directory_ID : u16 LUN (all printed in hexadecimal)
+ *
+ * This is the concatenation of target port identifier and logical unit
+ * identifier as per SAM-2...SAM-4 annex A.
+ */
+static ssize_t
+sbp2_sysfs_ieee1394_id_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ struct sbp2_device *sd;
+ struct fw_unit *unit;
+ struct fw_device *device;
+ u32 directory_id;
+ struct fw_csr_iterator ci;
+ int key, value, lun;
+
+ if (!sdev)
+ return 0;
+ sd = (struct sbp2_device *)sdev->host->hostdata;
+ unit = sd->unit;
+ device = fw_device(unit->device.parent);
+
+ /* implicit directory ID */
+ directory_id = ((unit->directory - device->config_rom) * 4
+ + CSR_CONFIG_ROM) & 0xffffff;
+
+ /* explicit directory ID, overrides implicit ID if present */
+ fw_csr_iterator_init(&ci, unit->directory);
+ while (fw_csr_iterator_next(&ci, &key, &value))
+ if (key == CSR_DIRECTORY_ID) {
+ directory_id = value;
+ break;
+ }
+
+ /* FIXME: Make this work for multi-lun devices. */
+ lun = 0;
+
+ return sprintf(buf, "%08x%08x:%06x:%04x\n",
+ device->config_rom[3], device->config_rom[4],
+ directory_id, lun);
+}
+
+static DEVICE_ATTR(ieee1394_id, S_IRUGO, sbp2_sysfs_ieee1394_id_show, NULL);
+
+static struct device_attribute *sbp2_scsi_sysfs_attrs[] = {
+ &dev_attr_ieee1394_id,
+ NULL
+};
+
static struct scsi_host_template scsi_driver_template = {
.module = THIS_MODULE,
.name = "SBP-2 IEEE-1394",
@@ -1121,6 +1173,7 @@ static struct scsi_host_template scsi_driver_template = {
.use_clustering = ENABLE_CLUSTERING,
.cmd_per_lun = 1,
.can_queue = 1,
+ .sdev_attrs = sbp2_scsi_sysfs_attrs,
};
MODULE_AUTHOR("Kristian Hoegsberg <krh@bitplanet.net>");