From 14e2198646d92ef52a69d20269580a3fbe7c996b Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Sun, 27 May 2007 13:18:27 +0200 Subject: firewire: fw-sbp2: implement sysfs ieee1394_id MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The attribute /sys/bus/scsi/devices/*:*:*:*/ieee1394_id, as generated by the old sbp2 driver, is typically used to create persistently named links in /dev/disk/by-id. Signed-off-by: Stefan Richter Signed-off-by: Kristian Høgsberg --- drivers/firewire/fw-device.h | 1 + drivers/firewire/fw-sbp2.c | 53 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) (limited to 'drivers/firewire') 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-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 "); -- cgit v1.2.3-70-g09d2 From 2aef469a35a273609beaa7094d5a07c1f6d75285 Mon Sep 17 00:00:00 2001 From: Kristian Høgsberg Date: Wed, 30 May 2007 19:06:35 -0400 Subject: firewire: Implement suspend/resume PCI driver hooks. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's a low-impact design, that just makes suspend/resume look like a bus reset to the upper level drivers, but it should be sufficient. Signed-off-by: Kristian Høgsberg Signed-off-by: Stefan Richter --- drivers/firewire/fw-card.c | 5 -- drivers/firewire/fw-ohci.c | 187 +++++++++++++++++++++++++++++---------------- 2 files changed, 123 insertions(+), 69 deletions(-) (limited to 'drivers/firewire') 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-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 "); -- cgit v1.2.3-70-g09d2 From 1ca31ae7cfed3e2a8e48fbf6ed6cac06495b6158 Mon Sep 17 00:00:00 2001 From: Kristian Høgsberg Date: Thu, 31 May 2007 11:16:43 -0400 Subject: firewire: Change struct fw_cdev_iso_packet to not use bitfields. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The struct is part of the userspace interface and can not use bitfields. This patch replaces the bitfields with a __u32 'control' word and provides access macros to set the bits. Signed-off-by: Kristian Høgsberg Signed-off-by: Stefan Richter --- drivers/firewire/fw-cdev.c | 17 ++++++++++++++++- include/linux/firewire-cdev.h | 14 ++++++++------ 2 files changed, 24 insertions(+), 7 deletions(-) (limited to 'drivers/firewire') 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/include/linux/firewire-cdev.h b/include/linux/firewire-cdev.h index d4455eb2ae3..efbe1fda1a2 100644 --- a/include/linux/firewire-cdev.h +++ b/include/linux/firewire-cdev.h @@ -198,13 +198,15 @@ struct fw_cdev_create_iso_context { __u32 handle; }; +#define FW_CDEV_ISO_PAYLOAD_LENGTH(v) (v) +#define FW_CDEV_ISO_INTERRUPT (1 << 16) +#define FW_CDEV_ISO_SKIP (1 << 17) +#define FW_CDEV_ISO_TAG(v) ((v) << 18) +#define FW_CDEV_ISO_SY(v) ((v) << 20) +#define FW_CDEV_ISO_HEADER_LENGTH(v) ((v) << 24) + struct fw_cdev_iso_packet { - __u16 payload_length; /* Length of indirect payload. */ - __u32 interrupt : 1; /* Generate interrupt on this packet */ - __u32 skip : 1; /* Set to not send packet at all. */ - __u32 tag : 2; - __u32 sy : 4; - __u32 header_length : 8; /* Length of immediate header. */ + __u32 control; __u32 header[0]; }; -- cgit v1.2.3-70-g09d2