From a4b47d62c5018e81e2b8ee9843d8a8268e886d25 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Sun, 27 Jan 2008 22:32:22 +0100 Subject: ieee1394: sbp2: relax SCSI DMA alignment Signed-off-by: Stefan Richter --- drivers/ieee1394/sbp2.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c index f53f72daae34..5f713a01f044 100644 --- a/drivers/ieee1394/sbp2.c +++ b/drivers/ieee1394/sbp2.c @@ -1985,11 +1985,8 @@ static int sbp2scsi_slave_alloc(struct scsi_device *sdev) lu->sdev = sdev; sdev->allow_restart = 1; - /* - * Update the dma alignment (minimum alignment requirements for - * start and end of DMA transfers) to be a sector - */ - blk_queue_update_dma_alignment(sdev->request_queue, 511); + /* SBP-2 requires quadlet alignment of the data buffers. */ + blk_queue_update_dma_alignment(sdev->request_queue, 4 - 1); if (lu->workarounds & SBP2_WORKAROUND_INQUIRY_36) sdev->inquiry_len = 36; -- cgit v1.2.3-58-ga151 From 63995d46506a774f5ddd6b51c017d42c3fbfaedb Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Wed, 13 Feb 2008 00:06:07 +0100 Subject: ieee1394: be*_add_cpu conversion replace all: big_endian_variable = cpu_to_beX(beX_to_cpu(big_endian_variable) + expression_in_cpu_byteorder); with: beX_add_cpu(&big_endian_variable, expression_in_cpu_byteorder); generated with semantic patch Signed-off-by: Marcin Slusarz Signed-off-by: Stefan Richter --- drivers/ieee1394/csr.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/ieee1394/csr.c b/drivers/ieee1394/csr.c index 52ac83e0ebee..c90be4070e40 100644 --- a/drivers/ieee1394/csr.c +++ b/drivers/ieee1394/csr.c @@ -133,8 +133,7 @@ static void host_reset(struct hpsb_host *host) host->csr.state &= ~0x100; } - host->csr.topology_map[1] = - cpu_to_be32(be32_to_cpu(host->csr.topology_map[1]) + 1); + be32_add_cpu(&host->csr.topology_map[1], 1); host->csr.topology_map[2] = cpu_to_be32(host->node_count << 16 | host->selfid_count); host->csr.topology_map[0] = @@ -142,8 +141,7 @@ static void host_reset(struct hpsb_host *host) | csr_crc16(host->csr.topology_map + 1, host->selfid_count + 2)); - host->csr.speed_map[1] = - cpu_to_be32(be32_to_cpu(host->csr.speed_map[1]) + 1); + be32_add_cpu(&host->csr.speed_map[1], 1); host->csr.speed_map[0] = cpu_to_be32(0x3f1 << 16 | csr_crc16(host->csr.speed_map+1, 0x3f1)); -- cgit v1.2.3-58-ga151 From d2ace29fa44589da51fedc06a67b3f05301f3bfd Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Mon, 18 Feb 2008 21:11:07 +0100 Subject: ieee1394: prevent device binding of raw1394, video1394, dv1394 These drivers don't need to match any unit_directory type device. They just need the id_table for module autoloading per module alias. Not binding any of these drivers allows special-purpose drivers with similar or same IDs to bind to devices. This currently only benefits out-of-tree drivers; on the other hand it is in no way detrimental to in-tree drivers. Signed-off-by: Stefan Richter --- drivers/ieee1394/dv1394.c | 3 +-- drivers/ieee1394/nodemgr.c | 6 +++++- drivers/ieee1394/raw1394.c | 1 - drivers/ieee1394/video1394.c | 3 +-- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c index 65722117ab6e..8c72f360f2d5 100644 --- a/drivers/ieee1394/dv1394.c +++ b/drivers/ieee1394/dv1394.c @@ -2179,8 +2179,7 @@ static struct ieee1394_device_id dv1394_id_table[] = { MODULE_DEVICE_TABLE(ieee1394, dv1394_id_table); static struct hpsb_protocol_driver dv1394_driver = { - .name = "dv1394", - .id_table = dv1394_id_table, + .name = "dv1394", }; diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index 511e4321c6b6..70afa3786f3f 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c @@ -701,7 +701,11 @@ static int nodemgr_bus_match(struct device * dev, struct device_driver * drv) return 0; driver = container_of(drv, struct hpsb_protocol_driver, driver); - for (id = driver->id_table; id->match_flags != 0; id++) { + id = driver->id_table; + if (!id) + return 0; + + for (; id->match_flags != 0; id++) { if ((id->match_flags & IEEE1394_MATCH_VENDOR_ID) && id->vendor_id != ud->vendor_id) continue; diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c index 37e7e109af38..3634785d3b4b 100644 --- a/drivers/ieee1394/raw1394.c +++ b/drivers/ieee1394/raw1394.c @@ -2959,7 +2959,6 @@ MODULE_DEVICE_TABLE(ieee1394, raw1394_id_table); static struct hpsb_protocol_driver raw1394_driver = { .name = "raw1394", - .id_table = raw1394_id_table, }; /******************************************************************************/ diff --git a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c index bd28adfd7afc..cc240b2e72d9 100644 --- a/drivers/ieee1394/video1394.c +++ b/drivers/ieee1394/video1394.c @@ -1315,8 +1315,7 @@ static struct ieee1394_device_id video1394_id_table[] = { MODULE_DEVICE_TABLE(ieee1394, video1394_id_table); static struct hpsb_protocol_driver video1394_driver = { - .name = VIDEO1394_DRIVER_NAME, - .id_table = video1394_id_table, + .name = VIDEO1394_DRIVER_NAME, }; -- cgit v1.2.3-58-ga151 From 38275ac36d60882db750d6301ef507881b4c8420 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Sat, 1 Mar 2008 12:36:06 +0100 Subject: ieee1394: ohci1394: switch on bus power after resume on PPC PMac The platform feature calls in the suspend method switched off cable power, but the calls in the resume method did not switch it back on. Add the necessary feature call to .resume. Also add the corresponding call to .suspend to make .suspend's behavior explicitly the same on all PMacs. Signed-off-by: Stefan Richter --- drivers/ieee1394/ohci1394.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c index 969de2a2d633..b4cad9f45862 100644 --- a/drivers/ieee1394/ohci1394.c +++ b/drivers/ieee1394/ohci1394.c @@ -3340,8 +3340,10 @@ static int ohci1394_pci_suspend(struct pci_dev *pdev, pm_message_t state) if (machine_is(powermac)) { struct device_node *ofn = pci_device_to_OF_node(pdev); - if (ofn) + if (ofn) { pmac_call_feature(PMAC_FTR_1394_ENABLE, ofn, 0, 0); + pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, ofn, 0, 0); + } } #endif /* CONFIG_PPC_PMAC */ @@ -3365,8 +3367,10 @@ static int ohci1394_pci_resume(struct pci_dev *pdev) if (machine_is(powermac)) { struct device_node *ofn = pci_device_to_OF_node(pdev); - if (ofn) + if (ofn) { + pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, ofn, 0, 1); pmac_call_feature(PMAC_FTR_1394_ENABLE, ofn, 0, 1); + } } #endif /* CONFIG_PPC_PMAC */ -- cgit v1.2.3-58-ga151 From b25d166616ea30adedee70d99c40ba82d126d7cb Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Sat, 1 Mar 2008 12:36:42 +0100 Subject: ieee1394: ohci1394: refactor probe, remove, suspend, resume Clean up shared code and variable names. Signed-off-by: Stefan Richter --- drivers/ieee1394/ohci1394.c | 113 +++++++++++++++++++------------------------- 1 file changed, 49 insertions(+), 64 deletions(-) diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c index b4cad9f45862..29b891084ca7 100644 --- a/drivers/ieee1394/ohci1394.c +++ b/drivers/ieee1394/ohci1394.c @@ -2993,15 +2993,9 @@ do { \ return err; \ } while (0) -static int __devinit ohci1394_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) -{ - struct hpsb_host *host; - struct ti_ohci *ohci; /* shortcut to currently handled device */ - resource_size_t ohci_base; - #ifdef CONFIG_PPC_PMAC - /* Necessary on some machines if ohci1394 was loaded/ unloaded before */ +static void ohci1394_pmac_on(struct pci_dev *dev) +{ if (machine_is(powermac)) { struct device_node *ofn = pci_device_to_OF_node(dev); @@ -3010,8 +3004,32 @@ static int __devinit ohci1394_pci_probe(struct pci_dev *dev, pmac_call_feature(PMAC_FTR_1394_ENABLE, ofn, 0, 1); } } +} + +static void ohci1394_pmac_off(struct pci_dev *dev) +{ + if (machine_is(powermac)) { + struct device_node *ofn = pci_device_to_OF_node(dev); + + if (ofn) { + pmac_call_feature(PMAC_FTR_1394_ENABLE, ofn, 0, 0); + pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, ofn, 0, 0); + } + } +} +#else +#define ohci1394_pmac_on(dev) +#define ohci1394_pmac_off(dev) #endif /* CONFIG_PPC_PMAC */ +static int __devinit ohci1394_pci_probe(struct pci_dev *dev, + const struct pci_device_id *ent) +{ + struct hpsb_host *host; + struct ti_ohci *ohci; /* shortcut to currently handled device */ + resource_size_t ohci_base; + + ohci1394_pmac_on(dev); if (pci_enable_device(dev)) FAIL(-ENXIO, "Failed to enable OHCI hardware"); pci_set_master(dev); @@ -3203,16 +3221,16 @@ static int __devinit ohci1394_pci_probe(struct pci_dev *dev, #undef FAIL } -static void ohci1394_pci_remove(struct pci_dev *pdev) +static void ohci1394_pci_remove(struct pci_dev *dev) { struct ti_ohci *ohci; - struct device *dev; + struct device *device; - ohci = pci_get_drvdata(pdev); + ohci = pci_get_drvdata(dev); if (!ohci) return; - dev = get_device(&ohci->host->device); + device = get_device(&ohci->host->device); switch (ohci->init_state) { case OHCI_INIT_DONE: @@ -3246,7 +3264,7 @@ static void ohci1394_pci_remove(struct pci_dev *pdev) /* Soft reset before we start - this disables * interrupts and clears linkEnable and LPS. */ ohci_soft_reset(ohci); - free_irq(ohci->dev->irq, ohci); + free_irq(dev->irq, ohci); case OHCI_INIT_HAVE_TXRX_BUFFERS__MAYBE: /* The ohci_soft_reset() stops all DMA contexts, so we @@ -3257,12 +3275,12 @@ static void ohci1394_pci_remove(struct pci_dev *pdev) free_dma_trm_ctx(&ohci->at_resp_context); case OHCI_INIT_HAVE_SELFID_BUFFER: - pci_free_consistent(ohci->dev, OHCI1394_SI_DMA_BUF_SIZE, + pci_free_consistent(dev, OHCI1394_SI_DMA_BUF_SIZE, ohci->selfid_buf_cpu, ohci->selfid_buf_bus); case OHCI_INIT_HAVE_CONFIG_ROM_BUFFER: - pci_free_consistent(ohci->dev, OHCI_CONFIG_ROM_LEN, + pci_free_consistent(dev, OHCI_CONFIG_ROM_LEN, ohci->csr_config_rom_cpu, ohci->csr_config_rom_bus); @@ -3270,35 +3288,24 @@ static void ohci1394_pci_remove(struct pci_dev *pdev) iounmap(ohci->registers); case OHCI_INIT_HAVE_MEM_REGION: - release_mem_region(pci_resource_start(ohci->dev, 0), + release_mem_region(pci_resource_start(dev, 0), OHCI1394_REGISTER_SIZE); -#ifdef CONFIG_PPC_PMAC - /* On UniNorth, power down the cable and turn off the chip clock - * to save power on laptops */ - if (machine_is(powermac)) { - struct device_node* ofn = pci_device_to_OF_node(ohci->dev); - - if (ofn) { - pmac_call_feature(PMAC_FTR_1394_ENABLE, ofn, 0, 0); - pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, ofn, 0, 0); - } - } -#endif /* CONFIG_PPC_PMAC */ + ohci1394_pmac_off(dev); case OHCI_INIT_ALLOC_HOST: - pci_set_drvdata(ohci->dev, NULL); + pci_set_drvdata(dev, NULL); } - if (dev) - put_device(dev); + if (device) + put_device(device); } #ifdef CONFIG_PM -static int ohci1394_pci_suspend(struct pci_dev *pdev, pm_message_t state) +static int ohci1394_pci_suspend(struct pci_dev *dev, pm_message_t state) { int err; - struct ti_ohci *ohci = pci_get_drvdata(pdev); + struct ti_ohci *ohci = pci_get_drvdata(dev); if (!ohci) { printk(KERN_ERR "%s: tried to suspend nonexisting host\n", @@ -3326,34 +3333,23 @@ static int ohci1394_pci_suspend(struct pci_dev *pdev, pm_message_t state) ohci_devctl(ohci->host, RESET_BUS, LONG_RESET_NO_FORCE_ROOT); ohci_soft_reset(ohci); - err = pci_save_state(pdev); + err = pci_save_state(dev); if (err) { PRINT(KERN_ERR, "pci_save_state failed with %d", err); return err; } - err = pci_set_power_state(pdev, pci_choose_state(pdev, state)); + err = pci_set_power_state(dev, pci_choose_state(dev, state)); if (err) DBGMSG("pci_set_power_state failed with %d", err); - -/* PowerMac suspend code comes last */ -#ifdef CONFIG_PPC_PMAC - if (machine_is(powermac)) { - struct device_node *ofn = pci_device_to_OF_node(pdev); - - if (ofn) { - pmac_call_feature(PMAC_FTR_1394_ENABLE, ofn, 0, 0); - pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, ofn, 0, 0); - } - } -#endif /* CONFIG_PPC_PMAC */ + ohci1394_pmac_off(dev); return 0; } -static int ohci1394_pci_resume(struct pci_dev *pdev) +static int ohci1394_pci_resume(struct pci_dev *dev) { int err; - struct ti_ohci *ohci = pci_get_drvdata(pdev); + struct ti_ohci *ohci = pci_get_drvdata(dev); if (!ohci) { printk(KERN_ERR "%s: tried to resume nonexisting host\n", @@ -3362,21 +3358,10 @@ static int ohci1394_pci_resume(struct pci_dev *pdev) } DBGMSG("resume called"); -/* PowerMac resume code comes first */ -#ifdef CONFIG_PPC_PMAC - if (machine_is(powermac)) { - struct device_node *ofn = pci_device_to_OF_node(pdev); - - if (ofn) { - pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, ofn, 0, 1); - pmac_call_feature(PMAC_FTR_1394_ENABLE, ofn, 0, 1); - } - } -#endif /* CONFIG_PPC_PMAC */ - - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - err = pci_enable_device(pdev); + ohci1394_pmac_on(dev); + pci_set_power_state(dev, PCI_D0); + pci_restore_state(dev); + err = pci_enable_device(dev); if (err) { PRINT(KERN_ERR, "pci_enable_device failed with %d", err); return err; -- cgit v1.2.3-58-ga151 From b1ce1fd778997b3313599a2561bcbd42a34bfb56 Mon Sep 17 00:00:00 2001 From: Harvey Harrison Date: Wed, 5 Mar 2008 18:24:54 -0800 Subject: ieee1394: replace remaining __FUNCTION__ occurrences __FUNCTION__ is gcc-specific, use __func__ Signed-off-by: Harvey Harrison Signed-off-by: Andrew Morton Signed-off-by: Stefan Richter --- drivers/ieee1394/highlevel.c | 6 +++--- drivers/ieee1394/ieee1394_core.c | 2 +- drivers/ieee1394/ohci1394.c | 2 +- drivers/ieee1394/pcilynx.c | 12 ++++++------ drivers/ieee1394/sbp2.c | 4 ++-- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/ieee1394/highlevel.c b/drivers/ieee1394/highlevel.c index b6425469b6ee..fa2bfec0fca2 100644 --- a/drivers/ieee1394/highlevel.c +++ b/drivers/ieee1394/highlevel.c @@ -339,7 +339,7 @@ u64 hpsb_allocate_and_register_addrspace(struct hpsb_highlevel *hl, if ((alignment & 3) || (alignment > 0x800000000000ULL) || (hweight64(alignment) != 1)) { HPSB_ERR("%s called with invalid alignment: 0x%048llx", - __FUNCTION__, (unsigned long long)alignment); + __func__, (unsigned long long)alignment); return retval; } @@ -354,7 +354,7 @@ u64 hpsb_allocate_and_register_addrspace(struct hpsb_highlevel *hl, if (((start|end) & ~align_mask) || (start >= end) || (end > CSR1212_ALL_SPACE_END)) { HPSB_ERR("%s called with invalid addresses " - "(start = %012Lx end = %012Lx)", __FUNCTION__, + "(start = %012Lx end = %012Lx)", __func__, (unsigned long long)start,(unsigned long long)end); return retval; } @@ -422,7 +422,7 @@ int hpsb_register_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host, if (((start|end) & 3) || (start >= end) || (end > CSR1212_ALL_SPACE_END)) { - HPSB_ERR("%s called with invalid addresses", __FUNCTION__); + HPSB_ERR("%s called with invalid addresses", __func__); return 0; } diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c index 36c747b277d0..942bf1ff5214 100644 --- a/drivers/ieee1394/ieee1394_core.c +++ b/drivers/ieee1394/ieee1394_core.c @@ -242,7 +242,7 @@ int hpsb_bus_reset(struct hpsb_host *host) { if (host->in_bus_reset) { HPSB_NOTICE("%s called while bus reset already in progress", - __FUNCTION__); + __func__); return 1; } diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c index 29b891084ca7..0808baea7390 100644 --- a/drivers/ieee1394/ohci1394.c +++ b/drivers/ieee1394/ohci1394.c @@ -708,7 +708,7 @@ static void insert_packet(struct ti_ohci *ohci, /* FIXME: do something about it */ PRINT(KERN_ERR, "%s: packet data addr: %p size %Zd bytes " - "cross page boundary", __FUNCTION__, + "cross page boundary", __func__, packet->data, packet->data_size); } #endif diff --git a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c index 8af01ab30cc9..9c35e0d498cb 100644 --- a/drivers/ieee1394/pcilynx.c +++ b/drivers/ieee1394/pcilynx.c @@ -226,7 +226,7 @@ static int get_phy_reg(struct ti_lynx *lynx, int addr) if (addr > 15) { PRINT(KERN_ERR, lynx->id, "%s: PHY register address %d out of range", - __FUNCTION__, addr); + __func__, addr); return -1; } @@ -238,7 +238,7 @@ static int get_phy_reg(struct ti_lynx *lynx, int addr) if (i > 10000) { PRINT(KERN_ERR, lynx->id, "%s: runaway loop, aborting", - __FUNCTION__); + __func__); retval = -1; break; } @@ -261,13 +261,13 @@ static int set_phy_reg(struct ti_lynx *lynx, int addr, int val) if (addr > 15) { PRINT(KERN_ERR, lynx->id, - "%s: PHY register address %d out of range", __FUNCTION__, addr); + "%s: PHY register address %d out of range", __func__, addr); return -1; } if (val > 0xff) { PRINT(KERN_ERR, lynx->id, - "%s: PHY register value %d out of range", __FUNCTION__, val); + "%s: PHY register value %d out of range", __func__, val); return -1; } @@ -287,7 +287,7 @@ static int sel_phy_reg_page(struct ti_lynx *lynx, int page) if (page > 7) { PRINT(KERN_ERR, lynx->id, - "%s: PHY page %d out of range", __FUNCTION__, page); + "%s: PHY page %d out of range", __func__, page); return -1; } @@ -309,7 +309,7 @@ static int sel_phy_reg_port(struct ti_lynx *lynx, int port) if (port > 15) { PRINT(KERN_ERR, lynx->id, - "%s: PHY port %d out of range", __FUNCTION__, port); + "%s: PHY port %d out of range", __func__, port); return -1; } diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c index 5f713a01f044..16b9d0ad154e 100644 --- a/drivers/ieee1394/sbp2.c +++ b/drivers/ieee1394/sbp2.c @@ -615,7 +615,7 @@ static struct sbp2_command_info *sbp2util_allocate_command_orb( cmd->Current_SCpnt = Current_SCpnt; list_add_tail(&cmd->list, &lu->cmd_orb_inuse); } else - SBP2_ERR("%s: no orbs available", __FUNCTION__); + SBP2_ERR("%s: no orbs available", __func__); spin_unlock_irqrestore(&lu->cmd_orb_lock, flags); return cmd; } @@ -1294,7 +1294,7 @@ static int sbp2_set_busy_timeout(struct sbp2_lu *lu) data = cpu_to_be32(SBP2_BUSY_TIMEOUT_VALUE); if (hpsb_node_write(lu->ne, SBP2_BUSY_TIMEOUT_ADDRESS, &data, 4)) - SBP2_ERR("%s error", __FUNCTION__); + SBP2_ERR("%s error", __func__); return 0; } -- cgit v1.2.3-58-ga151 From e351c4d069254b1267b66a3b101ece7547178485 Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Sun, 23 Mar 2008 10:15:28 -0400 Subject: ieee1394: Use shorter list_splice_init() for brevity. Signed-off-by: Robert P. J. Day Signed-off-by: Stefan Richter --- drivers/ieee1394/ohci1394.c | 6 ++---- drivers/ieee1394/pcilynx.c | 3 +-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c index 0808baea7390..4665a6fb07d8 100644 --- a/drivers/ieee1394/ohci1394.c +++ b/drivers/ieee1394/ohci1394.c @@ -2089,10 +2089,8 @@ static void dma_trm_reset(struct dma_trm_ctx *d) spin_lock_irqsave(&d->lock, flags); - list_splice(&d->fifo_list, &packet_list); - list_splice(&d->pending_list, &packet_list); - INIT_LIST_HEAD(&d->fifo_list); - INIT_LIST_HEAD(&d->pending_list); + list_splice_init(&d->fifo_list, &packet_list); + list_splice_init(&d->pending_list, &packet_list); d->branchAddrPtr = NULL; d->sent_ind = d->prg_ind; diff --git a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c index 9c35e0d498cb..7aee1ac97c80 100644 --- a/drivers/ieee1394/pcilynx.c +++ b/drivers/ieee1394/pcilynx.c @@ -738,8 +738,7 @@ static int lynx_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg) spin_lock_irqsave(&lynx->async.queue_lock, flags); reg_write(lynx, DMA_CHAN_CTRL(CHANNEL_ASYNC_SEND), 0); - list_splice(&lynx->async.queue, &packet_list); - INIT_LIST_HEAD(&lynx->async.queue); + list_splice_init(&lynx->async.queue, &packet_list); if (list_empty(&lynx->async.pcl_queue)) { spin_unlock_irqrestore(&lynx->async.queue_lock, flags); -- cgit v1.2.3-58-ga151 From d09c68038306442e3566366b6988a6dd83481251 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Mon, 24 Mar 2008 20:49:01 +0100 Subject: ieee1394: ohci1394: unroll a macro with return We don't want to hide something like return in a preprocessor macro. Unroll the macro and use a goto, which also reduces the size of ohci1394.ko. Signed-off-by: Stefan Richter --- drivers/ieee1394/ohci1394.c | 92 ++++++++++++++++++++++++++------------------- 1 file changed, 54 insertions(+), 38 deletions(-) diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c index 4665a6fb07d8..a660222fc532 100644 --- a/drivers/ieee1394/ohci1394.c +++ b/drivers/ieee1394/ohci1394.c @@ -2984,13 +2984,6 @@ static struct hpsb_host_driver ohci1394_driver = { * PCI Driver Interface functions * ***********************************/ -#define FAIL(err, fmt, args...) \ -do { \ - PRINT_G(KERN_ERR, fmt , ## args); \ - ohci1394_pci_remove(dev); \ - return err; \ -} while (0) - #ifdef CONFIG_PPC_PMAC static void ohci1394_pmac_on(struct pci_dev *dev) { @@ -3026,15 +3019,21 @@ static int __devinit ohci1394_pci_probe(struct pci_dev *dev, struct hpsb_host *host; struct ti_ohci *ohci; /* shortcut to currently handled device */ resource_size_t ohci_base; + int err = -ENOMEM; ohci1394_pmac_on(dev); - if (pci_enable_device(dev)) - FAIL(-ENXIO, "Failed to enable OHCI hardware"); + if (pci_enable_device(dev)) { + PRINT_G(KERN_ERR, "Failed to enable OHCI hardware"); + err = -ENXIO; + goto err; + } pci_set_master(dev); host = hpsb_alloc_host(&ohci1394_driver, sizeof(struct ti_ohci), &dev->dev); - if (!host) FAIL(-ENOMEM, "Failed to allocate host structure"); - + if (!host) { + PRINT_G(KERN_ERR, "Failed to allocate host structure"); + goto err; + } ohci = host->hostdata; ohci->dev = dev; ohci->host = host; @@ -3083,15 +3082,20 @@ static int __devinit ohci1394_pci_probe(struct pci_dev *dev, (unsigned long long)pci_resource_len(dev, 0)); if (!request_mem_region(ohci_base, OHCI1394_REGISTER_SIZE, - OHCI1394_DRIVER_NAME)) - FAIL(-ENOMEM, "MMIO resource (0x%llx - 0x%llx) unavailable", + OHCI1394_DRIVER_NAME)) { + PRINT_G(KERN_ERR, "MMIO resource (0x%llx - 0x%llx) unavailable", (unsigned long long)ohci_base, (unsigned long long)ohci_base + OHCI1394_REGISTER_SIZE); + goto err; + } ohci->init_state = OHCI_INIT_HAVE_MEM_REGION; ohci->registers = ioremap(ohci_base, OHCI1394_REGISTER_SIZE); - if (ohci->registers == NULL) - FAIL(-ENXIO, "Failed to remap registers - card not accessible"); + if (ohci->registers == NULL) { + PRINT_G(KERN_ERR, "Failed to remap registers"); + err = -ENXIO; + goto err; + } ohci->init_state = OHCI_INIT_HAVE_IOMAPPING; DBGMSG("Remapped memory spaces reg 0x%p", ohci->registers); @@ -3099,16 +3103,20 @@ static int __devinit ohci1394_pci_probe(struct pci_dev *dev, ohci->csr_config_rom_cpu = pci_alloc_consistent(ohci->dev, OHCI_CONFIG_ROM_LEN, &ohci->csr_config_rom_bus); - if (ohci->csr_config_rom_cpu == NULL) - FAIL(-ENOMEM, "Failed to allocate buffer config rom"); + if (ohci->csr_config_rom_cpu == NULL) { + PRINT_G(KERN_ERR, "Failed to allocate buffer config rom"); + goto err; + } ohci->init_state = OHCI_INIT_HAVE_CONFIG_ROM_BUFFER; /* self-id dma buffer allocation */ ohci->selfid_buf_cpu = pci_alloc_consistent(ohci->dev, OHCI1394_SI_DMA_BUF_SIZE, &ohci->selfid_buf_bus); - if (ohci->selfid_buf_cpu == NULL) - FAIL(-ENOMEM, "Failed to allocate DMA buffer for self-id packets"); + if (ohci->selfid_buf_cpu == NULL) { + PRINT_G(KERN_ERR, "Failed to allocate self-ID buffer"); + goto err; + } ohci->init_state = OHCI_INIT_HAVE_SELFID_BUFFER; if ((unsigned long)ohci->selfid_buf_cpu & 0x1fff) @@ -3124,28 +3132,32 @@ static int __devinit ohci1394_pci_probe(struct pci_dev *dev, if (alloc_dma_rcv_ctx(ohci, &ohci->ar_req_context, DMA_CTX_ASYNC_REQ, 0, AR_REQ_NUM_DESC, AR_REQ_BUF_SIZE, AR_REQ_SPLIT_BUF_SIZE, - OHCI1394_AsReqRcvContextBase) < 0) - FAIL(-ENOMEM, "Failed to allocate AR Req context"); - + OHCI1394_AsReqRcvContextBase) < 0) { + PRINT_G(KERN_ERR, "Failed to allocate AR Req context"); + goto err; + } /* AR DMA response context allocation */ if (alloc_dma_rcv_ctx(ohci, &ohci->ar_resp_context, DMA_CTX_ASYNC_RESP, 0, AR_RESP_NUM_DESC, AR_RESP_BUF_SIZE, AR_RESP_SPLIT_BUF_SIZE, - OHCI1394_AsRspRcvContextBase) < 0) - FAIL(-ENOMEM, "Failed to allocate AR Resp context"); - + OHCI1394_AsRspRcvContextBase) < 0) { + PRINT_G(KERN_ERR, "Failed to allocate AR Resp context"); + goto err; + } /* AT DMA request context */ if (alloc_dma_trm_ctx(ohci, &ohci->at_req_context, DMA_CTX_ASYNC_REQ, 0, AT_REQ_NUM_DESC, - OHCI1394_AsReqTrContextBase) < 0) - FAIL(-ENOMEM, "Failed to allocate AT Req context"); - + OHCI1394_AsReqTrContextBase) < 0) { + PRINT_G(KERN_ERR, "Failed to allocate AT Req context"); + goto err; + } /* AT DMA response context */ if (alloc_dma_trm_ctx(ohci, &ohci->at_resp_context, DMA_CTX_ASYNC_RESP, 1, AT_RESP_NUM_DESC, - OHCI1394_AsRspTrContextBase) < 0) - FAIL(-ENOMEM, "Failed to allocate AT Resp context"); - + OHCI1394_AsRspTrContextBase) < 0) { + PRINT_G(KERN_ERR, "Failed to allocate AT Resp context"); + goto err; + } /* Start off with a soft reset, to clear everything to a sane * state. */ ohci_soft_reset(ohci); @@ -3188,9 +3200,10 @@ static int __devinit ohci1394_pci_probe(struct pci_dev *dev, * by that point. */ if (request_irq(dev->irq, ohci_irq_handler, IRQF_SHARED, - OHCI1394_DRIVER_NAME, ohci)) - FAIL(-ENOMEM, "Failed to allocate shared interrupt %d", dev->irq); - + OHCI1394_DRIVER_NAME, ohci)) { + PRINT_G(KERN_ERR, "Failed to allocate interrupt %d", dev->irq); + goto err; + } ohci->init_state = OHCI_INIT_HAVE_IRQ; ohci_initialize(ohci); @@ -3210,13 +3223,16 @@ static int __devinit ohci1394_pci_probe(struct pci_dev *dev, host->middle_addr_space = OHCI1394_MIDDLE_ADDRESS_SPACE; /* Tell the highlevel this host is ready */ - if (hpsb_add_host(host)) - FAIL(-ENOMEM, "Failed to register host with highlevel"); - + if (hpsb_add_host(host)) { + PRINT_G(KERN_ERR, "Failed to register host with highlevel"); + goto err; + } ohci->init_state = OHCI_INIT_DONE; return 0; -#undef FAIL +err: + ohci1394_pci_remove(dev); + return err; } static void ohci1394_pci_remove(struct pci_dev *dev) -- cgit v1.2.3-58-ga151 From c4e2e02bc96f0a1605f858df3d6d5ea70fc459fc Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Mon, 24 Mar 2008 20:52:42 +0100 Subject: ieee1394: ohci1394: refactor some printk format strings to reduce the size of ohci1394.ko. Signed-off-by: Stefan Richter --- drivers/ieee1394/ohci1394.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c index a660222fc532..9e304c3cea22 100644 --- a/drivers/ieee1394/ohci1394.c +++ b/drivers/ieee1394/ohci1394.c @@ -149,7 +149,7 @@ printk(level "%s: fw-host%d: " fmt "\n" , OHCI1394_DRIVER_NAME, ohci->host->id , /* Module Parameters */ static int phys_dma = 1; module_param(phys_dma, int, 0444); -MODULE_PARM_DESC(phys_dma, "Enable physical dma (default = 1)."); +MODULE_PARM_DESC(phys_dma, "Enable physical DMA (default = 1)."); static void dma_trm_tasklet(unsigned long data); static void dma_trm_reset(struct dma_trm_ctx *d); @@ -2785,7 +2785,7 @@ alloc_dma_rcv_ctx(struct ti_ohci *ohci, struct dma_rcv_ctx *d, d->buf_bus = kzalloc(d->num_desc * sizeof(*d->buf_bus), GFP_ATOMIC); if (d->buf_cpu == NULL || d->buf_bus == NULL) { - PRINT(KERN_ERR, "Failed to allocate dma buffer"); + PRINT(KERN_ERR, "Failed to allocate %s", "DMA buffer"); free_dma_rcv_ctx(d); return -ENOMEM; } @@ -2794,7 +2794,7 @@ alloc_dma_rcv_ctx(struct ti_ohci *ohci, struct dma_rcv_ctx *d, d->prg_bus = kzalloc(d->num_desc * sizeof(*d->prg_bus), GFP_ATOMIC); if (d->prg_cpu == NULL || d->prg_bus == NULL) { - PRINT(KERN_ERR, "Failed to allocate dma prg"); + PRINT(KERN_ERR, "Failed to allocate %s", "DMA prg"); free_dma_rcv_ctx(d); return -ENOMEM; } @@ -2802,7 +2802,7 @@ alloc_dma_rcv_ctx(struct ti_ohci *ohci, struct dma_rcv_ctx *d, d->spb = kmalloc(d->split_buf_size, GFP_ATOMIC); if (d->spb == NULL) { - PRINT(KERN_ERR, "Failed to allocate split buffer"); + PRINT(KERN_ERR, "Failed to allocate %s", "split buffer"); free_dma_rcv_ctx(d); return -ENOMEM; } @@ -2828,7 +2828,7 @@ alloc_dma_rcv_ctx(struct ti_ohci *ohci, struct dma_rcv_ctx *d, memset(d->buf_cpu[i], 0, d->buf_size); } else { PRINT(KERN_ERR, - "Failed to allocate dma buffer"); + "Failed to allocate %s", "DMA buffer"); free_dma_rcv_ctx(d); return -ENOMEM; } @@ -2839,7 +2839,7 @@ alloc_dma_rcv_ctx(struct ti_ohci *ohci, struct dma_rcv_ctx *d, memset(d->prg_cpu[i], 0, sizeof(struct dma_cmd)); } else { PRINT(KERN_ERR, - "Failed to allocate dma prg"); + "Failed to allocate %s", "DMA prg"); free_dma_rcv_ctx(d); return -ENOMEM; } @@ -2900,7 +2900,7 @@ alloc_dma_trm_ctx(struct ti_ohci *ohci, struct dma_trm_ctx *d, d->prg_bus = kzalloc(d->num_desc * sizeof(*d->prg_bus), GFP_KERNEL); if (d->prg_cpu == NULL || d->prg_bus == NULL) { - PRINT(KERN_ERR, "Failed to allocate at dma prg"); + PRINT(KERN_ERR, "Failed to allocate %s", "AT DMA prg"); free_dma_trm_ctx(d); return -ENOMEM; } @@ -2923,7 +2923,7 @@ alloc_dma_trm_ctx(struct ti_ohci *ohci, struct dma_trm_ctx *d, memset(d->prg_cpu[i], 0, sizeof(struct at_dma_prg)); } else { PRINT(KERN_ERR, - "Failed to allocate at dma prg"); + "Failed to allocate %s", "AT DMA prg"); free_dma_trm_ctx(d); return -ENOMEM; } @@ -3031,7 +3031,7 @@ static int __devinit ohci1394_pci_probe(struct pci_dev *dev, host = hpsb_alloc_host(&ohci1394_driver, sizeof(struct ti_ohci), &dev->dev); if (!host) { - PRINT_G(KERN_ERR, "Failed to allocate host structure"); + PRINT_G(KERN_ERR, "Failed to allocate %s", "host structure"); goto err; } ohci = host->hostdata; @@ -3104,7 +3104,7 @@ static int __devinit ohci1394_pci_probe(struct pci_dev *dev, pci_alloc_consistent(ohci->dev, OHCI_CONFIG_ROM_LEN, &ohci->csr_config_rom_bus); if (ohci->csr_config_rom_cpu == NULL) { - PRINT_G(KERN_ERR, "Failed to allocate buffer config rom"); + PRINT_G(KERN_ERR, "Failed to allocate %s", "buffer config rom"); goto err; } ohci->init_state = OHCI_INIT_HAVE_CONFIG_ROM_BUFFER; @@ -3114,7 +3114,7 @@ static int __devinit ohci1394_pci_probe(struct pci_dev *dev, pci_alloc_consistent(ohci->dev, OHCI1394_SI_DMA_BUF_SIZE, &ohci->selfid_buf_bus); if (ohci->selfid_buf_cpu == NULL) { - PRINT_G(KERN_ERR, "Failed to allocate self-ID buffer"); + PRINT_G(KERN_ERR, "Failed to allocate %s", "self-ID buffer"); goto err; } ohci->init_state = OHCI_INIT_HAVE_SELFID_BUFFER; @@ -3133,7 +3133,7 @@ static int __devinit ohci1394_pci_probe(struct pci_dev *dev, DMA_CTX_ASYNC_REQ, 0, AR_REQ_NUM_DESC, AR_REQ_BUF_SIZE, AR_REQ_SPLIT_BUF_SIZE, OHCI1394_AsReqRcvContextBase) < 0) { - PRINT_G(KERN_ERR, "Failed to allocate AR Req context"); + PRINT_G(KERN_ERR, "Failed to allocate %s", "AR Req context"); goto err; } /* AR DMA response context allocation */ @@ -3141,21 +3141,21 @@ static int __devinit ohci1394_pci_probe(struct pci_dev *dev, DMA_CTX_ASYNC_RESP, 0, AR_RESP_NUM_DESC, AR_RESP_BUF_SIZE, AR_RESP_SPLIT_BUF_SIZE, OHCI1394_AsRspRcvContextBase) < 0) { - PRINT_G(KERN_ERR, "Failed to allocate AR Resp context"); + PRINT_G(KERN_ERR, "Failed to allocate %s", "AR Resp context"); goto err; } /* AT DMA request context */ if (alloc_dma_trm_ctx(ohci, &ohci->at_req_context, DMA_CTX_ASYNC_REQ, 0, AT_REQ_NUM_DESC, OHCI1394_AsReqTrContextBase) < 0) { - PRINT_G(KERN_ERR, "Failed to allocate AT Req context"); + PRINT_G(KERN_ERR, "Failed to allocate %s", "AT Req context"); goto err; } /* AT DMA response context */ if (alloc_dma_trm_ctx(ohci, &ohci->at_resp_context, DMA_CTX_ASYNC_RESP, 1, AT_RESP_NUM_DESC, OHCI1394_AsRspTrContextBase) < 0) { - PRINT_G(KERN_ERR, "Failed to allocate AT Resp context"); + PRINT_G(KERN_ERR, "Failed to allocate %s", "AT Resp context"); goto err; } /* Start off with a soft reset, to clear everything to a sane -- cgit v1.2.3-58-ga151 From 9508c208aa6e0a7501d8250d4a9d35344056d573 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Mon, 24 Mar 2008 20:53:34 +0100 Subject: ieee1394: ohci1394: missing PPC PMac feature calls in failure path The failure path of ohci1394_pci_probe() reuses ohci1394_pci_remove(). Doing so it missed to call ohci1394_pmac_off() in a few unlikely early error cases. Signed-off-by: Stefan Richter --- drivers/ieee1394/ohci1394.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c index 9e304c3cea22..0690469fcecf 100644 --- a/drivers/ieee1394/ohci1394.c +++ b/drivers/ieee1394/ohci1394.c @@ -3242,7 +3242,7 @@ static void ohci1394_pci_remove(struct pci_dev *dev) ohci = pci_get_drvdata(dev); if (!ohci) - return; + goto out; device = get_device(&ohci->host->device); @@ -3305,14 +3305,14 @@ static void ohci1394_pci_remove(struct pci_dev *dev) release_mem_region(pci_resource_start(dev, 0), OHCI1394_REGISTER_SIZE); - ohci1394_pmac_off(dev); - case OHCI_INIT_ALLOC_HOST: pci_set_drvdata(dev, NULL); } if (device) put_device(device); +out: + ohci1394_pmac_off(dev); } #ifdef CONFIG_PM -- cgit v1.2.3-58-ga151 From ee2d91e2b3e422f3f61cd7c6a58bd98a5ec72bd1 Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Thu, 27 Mar 2008 10:48:37 -0400 Subject: ieee1394: Remove superfluous calls to kobject_set_name(). Unless you're adding a kobject to the sysfs hierarchy, there is no point setting its kobject name. Signed-off-by: Robert P. J. Day Signed-off-by: Stefan Richter --- drivers/ieee1394/dv1394.c | 1 - drivers/ieee1394/raw1394.c | 1 - drivers/ieee1394/video1394.c | 1 - 3 files changed, 3 deletions(-) diff --git a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c index 8c72f360f2d5..6228fadacd38 100644 --- a/drivers/ieee1394/dv1394.c +++ b/drivers/ieee1394/dv1394.c @@ -2567,7 +2567,6 @@ static int __init dv1394_init_module(void) cdev_init(&dv1394_cdev, &dv1394_fops); dv1394_cdev.owner = THIS_MODULE; - kobject_set_name(&dv1394_cdev.kobj, "dv1394"); ret = cdev_add(&dv1394_cdev, IEEE1394_DV1394_DEV, 16); if (ret) { printk(KERN_ERR "dv1394: unable to register character device\n"); diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c index 3634785d3b4b..04e96ba56e09 100644 --- a/drivers/ieee1394/raw1394.c +++ b/drivers/ieee1394/raw1394.c @@ -3003,7 +3003,6 @@ static int __init init_raw1394(void) cdev_init(&raw1394_cdev, &raw1394_fops); raw1394_cdev.owner = THIS_MODULE; - kobject_set_name(&raw1394_cdev.kobj, RAW1394_DEVICE_NAME); ret = cdev_add(&raw1394_cdev, IEEE1394_RAW1394_DEV, 1); if (ret) { HPSB_ERR("raw1394 failed to register minor device block"); diff --git a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c index cc240b2e72d9..e03024eeeac1 100644 --- a/drivers/ieee1394/video1394.c +++ b/drivers/ieee1394/video1394.c @@ -1503,7 +1503,6 @@ static int __init video1394_init_module (void) cdev_init(&video1394_cdev, &video1394_fops); video1394_cdev.owner = THIS_MODULE; - kobject_set_name(&video1394_cdev.kobj, VIDEO1394_DRIVER_NAME); ret = cdev_add(&video1394_cdev, IEEE1394_VIDEO1394_DEV, 16); if (ret) { PRINT_G(KERN_ERR, "video1394: unable to get minor device block"); -- cgit v1.2.3-58-ga151 From a6ca4f7081095e3cdeb1a45d66fbe4856eca10d3 Mon Sep 17 00:00:00 2001 From: Philippe De Muyter Date: Fri, 11 Apr 2008 16:27:59 +0200 Subject: ieee1394: limit early node speed to host interface speed The following patch limits the node speed to the host interface speed, before using it. Signed-off-by: Philippe De Muyter It should actually suffice to do this only for the local node's speedcap[]. But there is another bug in the speed calculation: The local node's speed is not correctly propagated to the speeds which are to be used to access remote nodes. http://thread.gmane.org/gmane.linux.kernel.firewire.devel/11772/focus=12024 Signed-off-by: Stefan Richter --- drivers/ieee1394/ieee1394_core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c index 942bf1ff5214..dcdb71a7718d 100644 --- a/drivers/ieee1394/ieee1394_core.c +++ b/drivers/ieee1394/ieee1394_core.c @@ -373,6 +373,8 @@ static void build_speed_map(struct hpsb_host *host, int nodecount) if (sid->port2 == SELFID_PORT_CHILD) cldcnt[n]++; speedcap[n] = sid->speed; + if (speedcap[n] > host->csr.lnk_spd) + speedcap[n] = host->csr.lnk_spd; n--; } } -- cgit v1.2.3-58-ga151 From bd7dee6311156b7cdf884344feb34628909398ad Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Sun, 24 Feb 2008 18:59:55 +0100 Subject: firewire: remove superfluous reference counting The card->kref became obsolete since patch "firewire: fix crash in automatic module unloading" added another counter of card users. Signed-off-by: Stefan Richter Signed-off-by: Jarod Wilson --- drivers/firewire/fw-card.c | 38 -------------------------------------- drivers/firewire/fw-ohci.c | 8 ++++---- drivers/firewire/fw-transaction.h | 4 ---- 3 files changed, 4 insertions(+), 46 deletions(-) diff --git a/drivers/firewire/fw-card.c b/drivers/firewire/fw-card.c index a03462750b95..140b34d477de 100644 --- a/drivers/firewire/fw-card.c +++ b/drivers/firewire/fw-card.c @@ -398,7 +398,6 @@ fw_card_initialize(struct fw_card *card, const struct fw_card_driver *driver, { 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; @@ -429,12 +428,6 @@ fw_card_add(struct fw_card *card, 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); @@ -540,40 +533,9 @@ fw_core_remove_card(struct fw_card *card) cancel_delayed_work_sync(&card->work); fw_flush_transactions(card); 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) { diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c index ca6d51efd8bb..07d6053ff57e 100644 --- a/drivers/firewire/fw-ohci.c +++ b/drivers/firewire/fw-ohci.c @@ -2077,7 +2077,7 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) err = pci_enable_device(dev); if (err) { fw_error("Failed to enable OHCI hardware.\n"); - goto fail_put_card; + goto fail_free; } pci_set_master(dev); @@ -2173,8 +2173,8 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) pci_release_region(dev, 0); fail_disable: pci_disable_device(dev); - fail_put_card: - fw_card_put(&ohci->card); + fail_free: + kfree(&ohci->card); return err; } @@ -2202,7 +2202,7 @@ static void pci_remove(struct pci_dev *dev) pci_iounmap(dev, ohci->registers); pci_release_region(dev, 0); pci_disable_device(dev); - fw_card_put(&ohci->card); + kfree(&ohci->card); #ifdef CONFIG_PPC_PMAC /* On UniNorth, power down the cable and turn off the chip clock diff --git a/drivers/firewire/fw-transaction.h b/drivers/firewire/fw-transaction.h index a43bb22912f9..1a22a23e4596 100644 --- a/drivers/firewire/fw-transaction.h +++ b/drivers/firewire/fw-transaction.h @@ -221,7 +221,6 @@ struct fw_card { const struct fw_card_driver *driver; struct device *device; atomic_t device_count; - struct kref kref; int node_id; int generation; @@ -263,9 +262,6 @@ struct fw_card { int bm_generation; }; -struct fw_card *fw_card_get(struct fw_card *card); -void fw_card_put(struct fw_card *card); - /* * The iso packet format allows for an immediate header/payload part * stored in 'header' immediately after the packet info plus an -- cgit v1.2.3-58-ga151 From 7c1fca336661aaeb70b9094c4b8eaae389027509 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Sun, 24 Feb 2008 19:00:51 +0100 Subject: firewire: fw-sbp2: fix reference counting The reference count of the unit dropped too low in an error path in sbp2_probe. Fixed by moving the _get further up. Signed-off-by: Stefan Richter Signed-off-by: Jarod Wilson --- drivers/firewire/fw-sbp2.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c index 62b4e47d0cc0..8fff18e05000 100644 --- a/drivers/firewire/fw-sbp2.c +++ b/drivers/firewire/fw-sbp2.c @@ -1119,6 +1119,7 @@ static int sbp2_probe(struct device *dev) goto fail_shost_put; fw_device_get(device); + get_device(&unit->device); /* Initialize to values that won't match anything in our table. */ firmware_revision = 0xff000000; @@ -1134,8 +1135,6 @@ static int sbp2_probe(struct device *dev) sbp2_init_workarounds(tgt, model, firmware_revision); - get_device(&unit->device); - /* Do the login in a workqueue so we can easily reschedule retries. */ list_for_each_entry(lu, &tgt->lu_list, link) sbp2_queue_work(lu, 0); -- cgit v1.2.3-58-ga151 From 1dc3bea78b6cd71c2017aa5da076684c049d8b98 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Sun, 24 Feb 2008 19:01:21 +0100 Subject: firewire: refactor fw_unit reference counting Add wrappers for getting and putting a unit. Remove some line breaks. Signed-off-by: Stefan Richter Signed-off-by: Jarod Wilson --- drivers/firewire/fw-device.h | 27 +++++++++++++++++---------- drivers/firewire/fw-sbp2.c | 4 ++-- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/drivers/firewire/fw-device.h b/drivers/firewire/fw-device.h index 78ecd3991b7f..0d771fda86de 100644 --- a/drivers/firewire/fw-device.h +++ b/drivers/firewire/fw-device.h @@ -64,28 +64,24 @@ struct fw_device { struct fw_attribute_group attribute_group; }; -static inline struct fw_device * -fw_device(struct device *dev) +static inline struct fw_device *fw_device(struct device *dev) { return container_of(dev, struct fw_device, device); } -static inline int -fw_device_is_shutdown(struct fw_device *device) +static inline int fw_device_is_shutdown(struct fw_device *device) { return atomic_read(&device->state) == FW_DEVICE_SHUTDOWN; } -static inline struct fw_device * -fw_device_get(struct fw_device *device) +static inline struct fw_device *fw_device_get(struct fw_device *device) { get_device(&device->device); return device; } -static inline void -fw_device_put(struct fw_device *device) +static inline void fw_device_put(struct fw_device *device) { put_device(&device->device); } @@ -104,12 +100,23 @@ struct fw_unit { struct fw_attribute_group attribute_group; }; -static inline struct fw_unit * -fw_unit(struct device *dev) +static inline struct fw_unit *fw_unit(struct device *dev) { return container_of(dev, struct fw_unit, device); } +static inline struct fw_unit *fw_unit_get(struct fw_unit *unit) +{ + get_device(&unit->device); + + return unit; +} + +static inline void fw_unit_put(struct fw_unit *unit) +{ + put_device(&unit->device); +} + #define CSR_OFFSET 0x40 #define CSR_LEAF 0x80 #define CSR_DIRECTORY 0xc0 diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c index 8fff18e05000..c7aba5cff5d2 100644 --- a/drivers/firewire/fw-sbp2.c +++ b/drivers/firewire/fw-sbp2.c @@ -796,7 +796,7 @@ static void sbp2_release_target(struct kref *kref) scsi_remove_host(shost); fw_notify("released %s\n", tgt->bus_id); - put_device(&tgt->unit->device); + fw_unit_put(tgt->unit); scsi_host_put(shost); fw_device_put(device); } @@ -1119,7 +1119,7 @@ static int sbp2_probe(struct device *dev) goto fail_shost_put; fw_device_get(device); - get_device(&unit->device); + fw_unit_get(unit); /* Initialize to values that won't match anything in our table. */ firmware_revision = 0xff000000; -- cgit v1.2.3-58-ga151 From 8ac3a47cab32e5e5a40de4bc210b5b0063bf6e84 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Sun, 27 Jan 2008 22:31:27 +0100 Subject: firewire: fw-sbp2: relax SCSI DMA alignment Signed-off-by: Stefan Richter --- drivers/firewire/fw-sbp2.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c index c7aba5cff5d2..ea62e825a3b6 100644 --- a/drivers/firewire/fw-sbp2.c +++ b/drivers/firewire/fw-sbp2.c @@ -1518,11 +1518,8 @@ static int sbp2_scsi_slave_alloc(struct scsi_device *sdev) sdev->allow_restart = 1; - /* - * Update the dma alignment (minimum alignment requirements for - * start and end of DMA transfers) to be a sector - */ - blk_queue_update_dma_alignment(sdev->request_queue, 511); + /* SBP-2 requires quadlet alignment of the data buffers. */ + blk_queue_update_dma_alignment(sdev->request_queue, 4 - 1); if (lu->tgt->workarounds & SBP2_WORKAROUND_INQUIRY_36) sdev->inquiry_len = 36; -- cgit v1.2.3-58-ga151 From 71ee9f01f2bc2b717dacc69c85f257e1efff12ee Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Thu, 28 Feb 2008 20:51:11 +0100 Subject: firewire: fw-sbp2: remove usages of fw_memcpy_to_be32 Write directly in big endian instead of byte-swapping after the fact. This saves a few conversions, lets gcc use constant endianess conversions where possible, and enables deeper endianess annotation. Signed-off-by: Stefan Richter --- drivers/firewire/fw-sbp2.c | 94 +++++++++++++++++++++------------------------- 1 file changed, 43 insertions(+), 51 deletions(-) diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c index ea62e825a3b6..302160202644 100644 --- a/drivers/firewire/fw-sbp2.c +++ b/drivers/firewire/fw-sbp2.c @@ -224,8 +224,8 @@ struct sbp2_status { }; struct sbp2_pointer { - u32 high; - u32 low; + __be32 high; + __be32 low; }; struct sbp2_orb { @@ -253,8 +253,8 @@ struct sbp2_management_orb { struct { struct sbp2_pointer password; struct sbp2_pointer response; - u32 misc; - u32 length; + __be32 misc; + __be32 length; struct sbp2_pointer status_fifo; } request; __be32 response[4]; @@ -263,13 +263,10 @@ struct sbp2_management_orb { struct sbp2_status status; }; -#define LOGIN_RESPONSE_GET_LOGIN_ID(v) ((v).misc & 0xffff) -#define LOGIN_RESPONSE_GET_LENGTH(v) (((v).misc >> 16) & 0xffff) - struct sbp2_login_response { - u32 misc; + __be32 misc; struct sbp2_pointer command_block_agent; - u32 reconnect_hold; + __be32 reconnect_hold; }; #define COMMAND_ORB_DATA_SIZE(v) ((v)) #define COMMAND_ORB_PAGE_SIZE(v) ((v) << 16) @@ -285,7 +282,7 @@ struct sbp2_command_orb { struct { struct sbp2_pointer next; struct sbp2_pointer data_descriptor; - u32 misc; + __be32 misc; u8 command_block[12]; } request; struct scsi_cmnd *cmd; @@ -459,8 +456,7 @@ sbp2_send_orb(struct sbp2_orb *orb, struct sbp2_logical_unit *lu, unsigned long flags; orb->pointer.high = 0; - orb->pointer.low = orb->request_bus; - fw_memcpy_to_be32(&orb->pointer, &orb->pointer, sizeof(orb->pointer)); + orb->pointer.low = cpu_to_be32(orb->request_bus); spin_lock_irqsave(&device->card->lock, flags); list_add_tail(&orb->link, &lu->orb_list); @@ -536,31 +532,31 @@ sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id, if (dma_mapping_error(orb->response_bus)) goto fail_mapping_response; - orb->request.response.high = 0; - orb->request.response.low = orb->response_bus; + orb->request.response.high = 0; + orb->request.response.low = cpu_to_be32(orb->response_bus); - orb->request.misc = + orb->request.misc = cpu_to_be32( MANAGEMENT_ORB_NOTIFY | MANAGEMENT_ORB_FUNCTION(function) | - MANAGEMENT_ORB_LUN(lun_or_login_id); - orb->request.length = - MANAGEMENT_ORB_RESPONSE_LENGTH(sizeof(orb->response)); + MANAGEMENT_ORB_LUN(lun_or_login_id)); + orb->request.length = cpu_to_be32( + MANAGEMENT_ORB_RESPONSE_LENGTH(sizeof(orb->response))); - orb->request.status_fifo.high = lu->address_handler.offset >> 32; - orb->request.status_fifo.low = lu->address_handler.offset; + orb->request.status_fifo.high = + cpu_to_be32(lu->address_handler.offset >> 32); + orb->request.status_fifo.low = + cpu_to_be32(lu->address_handler.offset); if (function == SBP2_LOGIN_REQUEST) { /* Ask for 2^2 == 4 seconds reconnect grace period */ - orb->request.misc |= + orb->request.misc |= cpu_to_be32( MANAGEMENT_ORB_RECONNECT(2) | - MANAGEMENT_ORB_EXCLUSIVE(sbp2_param_exclusive_login); + MANAGEMENT_ORB_EXCLUSIVE(sbp2_param_exclusive_login)); timeout = lu->tgt->mgt_orb_timeout; } else { timeout = SBP2_ORB_TIMEOUT; } - fw_memcpy_to_be32(&orb->request, &orb->request, sizeof(orb->request)); - init_completion(&orb->done); orb->base.callback = complete_management_orb; @@ -605,8 +601,7 @@ sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id, sizeof(orb->response), DMA_FROM_DEVICE); fail_mapping_response: if (response) - fw_memcpy_from_be32(response, - orb->response, sizeof(orb->response)); + memcpy(response, orb->response, sizeof(orb->response)); kref_put(&orb->base.kref, free_orb); return retval; @@ -885,11 +880,10 @@ static void sbp2_login(struct work_struct *work) tgt->address_high = local_node_id << 16; sbp2_set_generation(lu, generation); - /* Get command block agent offset and login id. */ lu->command_block_agent_address = - ((u64) (response.command_block_agent.high & 0xffff) << 32) | - response.command_block_agent.low; - lu->login_id = LOGIN_RESPONSE_GET_LOGIN_ID(response); + ((u64)(be32_to_cpu(response.command_block_agent.high) & 0xffff) + << 32) | be32_to_cpu(response.command_block_agent.low); + lu->login_id = be32_to_cpu(response.misc) & 0xffff; fw_notify("%s: logged in to LUN %04x (%d retries)\n", tgt->bus_id, lu->lun, lu->retries); @@ -1366,9 +1360,12 @@ sbp2_map_scatterlist(struct sbp2_command_orb *orb, struct fw_device *device, * tables. */ if (count == 1 && sg_dma_len(sg) < SBP2_MAX_SG_ELEMENT_LENGTH) { - orb->request.data_descriptor.high = lu->tgt->address_high; - orb->request.data_descriptor.low = sg_dma_address(sg); - orb->request.misc |= COMMAND_ORB_DATA_SIZE(sg_dma_len(sg)); + orb->request.data_descriptor.high = + cpu_to_be32(lu->tgt->address_high); + orb->request.data_descriptor.low = + cpu_to_be32(sg_dma_address(sg)); + orb->request.misc |= + cpu_to_be32(COMMAND_ORB_DATA_SIZE(sg_dma_len(sg))); return 0; } @@ -1389,16 +1386,14 @@ sbp2_map_scatterlist(struct sbp2_command_orb *orb, struct fw_device *device, goto fail_page_table; } l = min(sg_len, SBP2_MAX_SG_ELEMENT_LENGTH); - orb->page_table[j].low = sg_addr; - orb->page_table[j].high = (l << 16); + orb->page_table[j].low = cpu_to_be32(sg_addr); + orb->page_table[j].high = cpu_to_be32(l << 16); sg_addr += l; sg_len -= l; j++; } } - fw_memcpy_to_be32(orb->page_table, orb->page_table, - sizeof(orb->page_table[0]) * j); orb->page_table_bus = dma_map_single(device->card->device, orb->page_table, sizeof(orb->page_table), DMA_TO_DEVICE); @@ -1412,11 +1407,10 @@ sbp2_map_scatterlist(struct sbp2_command_orb *orb, struct fw_device *device, * initiator (i.e. us), but data_descriptor can refer to data * on other nodes so we need to put our ID in descriptor.high. */ - orb->request.data_descriptor.high = lu->tgt->address_high; - orb->request.data_descriptor.low = orb->page_table_bus; - orb->request.misc |= - COMMAND_ORB_PAGE_TABLE_PRESENT | - COMMAND_ORB_DATA_SIZE(j); + orb->request.data_descriptor.high = cpu_to_be32(lu->tgt->address_high); + orb->request.data_descriptor.low = cpu_to_be32(orb->page_table_bus); + orb->request.misc |= cpu_to_be32(COMMAND_ORB_PAGE_TABLE_PRESENT | + COMMAND_ORB_DATA_SIZE(j)); return 0; @@ -1462,7 +1456,7 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done) orb->done = done; orb->cmd = cmd; - orb->request.next.high = SBP2_ORB_NULL; + orb->request.next.high = cpu_to_be32(SBP2_ORB_NULL); orb->request.next.low = 0x0; /* * At speed 100 we can do 512 bytes per packet, at speed 200, @@ -1472,23 +1466,21 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done) */ max_payload = min(device->max_speed + 7, device->card->max_receive - 1); - orb->request.misc = + orb->request.misc = cpu_to_be32( COMMAND_ORB_MAX_PAYLOAD(max_payload) | COMMAND_ORB_SPEED(device->max_speed) | - COMMAND_ORB_NOTIFY; + COMMAND_ORB_NOTIFY); if (cmd->sc_data_direction == DMA_FROM_DEVICE) - orb->request.misc |= - COMMAND_ORB_DIRECTION(SBP2_DIRECTION_FROM_MEDIA); + orb->request.misc |= cpu_to_be32( + COMMAND_ORB_DIRECTION(SBP2_DIRECTION_FROM_MEDIA)); else if (cmd->sc_data_direction == DMA_TO_DEVICE) - orb->request.misc |= - COMMAND_ORB_DIRECTION(SBP2_DIRECTION_TO_MEDIA); + orb->request.misc |= cpu_to_be32( + COMMAND_ORB_DIRECTION(SBP2_DIRECTION_TO_MEDIA)); if (scsi_sg_count(cmd) && sbp2_map_scatterlist(orb, device, lu) < 0) goto out; - fw_memcpy_to_be32(&orb->request, &orb->request, sizeof(orb->request)); - memset(orb->request.command_block, 0, sizeof(orb->request.command_block)); memcpy(orb->request.command_block, cmd->cmnd, COMMAND_SIZE(*cmd->cmnd)); -- cgit v1.2.3-58-ga151 From 0d7dcbf2a3b6042351948ecf1f171eb3f1d72cd3 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Thu, 28 Feb 2008 20:52:02 +0100 Subject: firewire: fw-sbp2: simplify some macros How hard can it be to switch on one bit? :-) Signed-off-by: Stefan Richter --- drivers/firewire/fw-sbp2.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c index 302160202644..d1bdf1807c4f 100644 --- a/drivers/firewire/fw-sbp2.c +++ b/drivers/firewire/fw-sbp2.c @@ -175,9 +175,6 @@ struct sbp2_target { #define SBP2_MAX_SG_ELEMENT_LENGTH 0xf000 #define SBP2_RETRY_LIMIT 0xf /* 15 retries */ -#define SBP2_DIRECTION_TO_MEDIA 0x0 -#define SBP2_DIRECTION_FROM_MEDIA 0x1 - /* Unit directory keys */ #define SBP2_CSR_UNIT_CHARACTERISTICS 0x3a #define SBP2_CSR_FIRMWARE_REVISION 0x3c @@ -273,7 +270,7 @@ struct sbp2_login_response { #define COMMAND_ORB_PAGE_TABLE_PRESENT ((1) << 19) #define COMMAND_ORB_MAX_PAYLOAD(v) ((v) << 20) #define COMMAND_ORB_SPEED(v) ((v) << 24) -#define COMMAND_ORB_DIRECTION(v) ((v) << 27) +#define COMMAND_ORB_DIRECTION ((1) << 27) #define COMMAND_ORB_REQUEST_FORMAT(v) ((v) << 29) #define COMMAND_ORB_NOTIFY ((1) << 31) @@ -1472,11 +1469,7 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done) COMMAND_ORB_NOTIFY); if (cmd->sc_data_direction == DMA_FROM_DEVICE) - orb->request.misc |= cpu_to_be32( - COMMAND_ORB_DIRECTION(SBP2_DIRECTION_FROM_MEDIA)); - else if (cmd->sc_data_direction == DMA_TO_DEVICE) - orb->request.misc |= cpu_to_be32( - COMMAND_ORB_DIRECTION(SBP2_DIRECTION_TO_MEDIA)); + orb->request.misc |= cpu_to_be32(COMMAND_ORB_DIRECTION); if (scsi_sg_count(cmd) && sbp2_map_scatterlist(orb, device, lu) < 0) goto out; -- cgit v1.2.3-58-ga151 From 6f73100cbbb9728c098bd05e9363d206b9eeab47 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Thu, 28 Feb 2008 20:52:43 +0100 Subject: firewire: fw-sbp2: remove unnecessary memset orb came from kzalloc. Signed-off-by: Stefan Richter --- drivers/firewire/fw-sbp2.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c index d1bdf1807c4f..71146ba01e63 100644 --- a/drivers/firewire/fw-sbp2.c +++ b/drivers/firewire/fw-sbp2.c @@ -1454,7 +1454,6 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done) orb->cmd = cmd; orb->request.next.high = cpu_to_be32(SBP2_ORB_NULL); - orb->request.next.low = 0x0; /* * At speed 100 we can do 512 bytes per packet, at speed 200, * 1024 bytes per packet etc. The SBP-2 max_payload field @@ -1474,8 +1473,6 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done) if (scsi_sg_count(cmd) && sbp2_map_scatterlist(orb, device, lu) < 0) goto out; - memset(orb->request.command_block, - 0, sizeof(orb->request.command_block)); memcpy(orb->request.command_block, cmd->cmnd, COMMAND_SIZE(*cmd->cmnd)); orb->base.callback = complete_command_orb; -- cgit v1.2.3-58-ga151 From a5fd9ec7a29202f388fc011a11cfb0101d9f9a34 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Thu, 28 Feb 2008 20:53:45 +0100 Subject: firewire: fw-sbp2: reduce log noise The block/unblock logic is now sufficiently tested. Signed-off-by: Stefan Richter --- drivers/firewire/fw-sbp2.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c index 71146ba01e63..625518792841 100644 --- a/drivers/firewire/fw-sbp2.c +++ b/drivers/firewire/fw-sbp2.c @@ -693,10 +693,8 @@ static void sbp2_conditionally_block(struct sbp2_logical_unit *lu) if (!tgt->dont_block && !lu->blocked && lu->generation != card->generation) { lu->blocked = true; - if (++tgt->blocked == 1) { + if (++tgt->blocked == 1) scsi_block_requests(shost); - fw_notify("blocked %s\n", lu->tgt->bus_id); - } } spin_unlock_irqrestore(&card->lock, flags); } @@ -723,10 +721,8 @@ static void sbp2_conditionally_unblock(struct sbp2_logical_unit *lu) } spin_unlock_irqrestore(&card->lock, flags); - if (unblock) { + if (unblock) scsi_unblock_requests(shost); - fw_notify("unblocked %s\n", lu->tgt->bus_id); - } } /* -- cgit v1.2.3-58-ga151 From 17cff9ff871bb5081cade4f99a9e9382b9f1c01c Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Fri, 7 Mar 2008 01:43:31 -0500 Subject: firewire: fw-sbp2: set dual-phase cycle_limit Try to write dual-phase retry protocol limits to BUSY_TIMEOUT register. - The dual-phase retry protocol is optional to implement, and if not supported, writes to the dual-phase portion of the register will be ignored. We try to write the original 1394-1995 default here. - In the case of devices that are also SBP-3-compliant, all writes are ignored, as the register is read-only, but contains single-phase retry of 15, which is what we're trying to set for all SBP-2 device anyway, so this write attempt is safe and yields more consistent behavior for all devices. See section 8.3.2.3.5 of the 1394-1995 spec, section 6.2 of the SBP-2 spec, and section 6.4 of the SBP-3 spec for further details. Signed-off-by: Jarod Wilson Signed-off-by: Stefan Richter --- drivers/firewire/fw-sbp2.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c index 625518792841..e99a33fcc923 100644 --- a/drivers/firewire/fw-sbp2.c +++ b/drivers/firewire/fw-sbp2.c @@ -173,7 +173,8 @@ struct sbp2_target { #define SBP2_ORB_TIMEOUT 2000U /* Timeout in ms */ #define SBP2_ORB_NULL 0x80000000 #define SBP2_MAX_SG_ELEMENT_LENGTH 0xf000 -#define SBP2_RETRY_LIMIT 0xf /* 15 retries */ +#define SBP2_RETRY_LIMIT 0xf /* 15 retries */ +#define SBP2_CYCLE_LIMIT (0xc8 << 12) /* 200 125us cycles */ /* Unit directory keys */ #define SBP2_CSR_UNIT_CHARACTERISTICS 0x3a @@ -813,6 +814,22 @@ complete_set_busy_timeout(struct fw_card *card, int rcode, complete(done); } +/* + * Write retransmit retry values into the BUSY_TIMEOUT register. + * - The single-phase retry protocol is supported by all SBP-2 devices, but the + * default retry_limit value is 0 (i.e. never retry transmission). We write a + * saner value after logging into the device. + * - The dual-phase retry protocol is optional to implement, and if not + * supported, writes to the dual-phase portion of the register will be + * ignored. We try to write the original 1394-1995 default here. + * - In the case of devices that are also SBP-3-compliant, all writes are + * ignored, as the register is read-only, but contains single-phase retry of + * 15, which is what we're trying to set for all SBP-2 device anyway, so this + * write attempt is safe and yields more consistent behavior for all devices. + * + * See section 8.3.2.3.5 of the 1394-1995 spec, section 6.2 of the SBP-2 spec, + * and section 6.4 of the SBP-3 spec for further details. + */ static void sbp2_set_busy_timeout(struct sbp2_logical_unit *lu) { struct fw_device *device = fw_device(lu->tgt->unit->device.parent); @@ -820,8 +837,7 @@ static void sbp2_set_busy_timeout(struct sbp2_logical_unit *lu) struct fw_transaction t; static __be32 busy_timeout; - /* FIXME: we should try to set dual-phase cycle_limit too */ - busy_timeout = cpu_to_be32(SBP2_RETRY_LIMIT); + busy_timeout = cpu_to_be32(SBP2_CYCLE_LIMIT | SBP2_RETRY_LIMIT); fw_send_request(device->card, &t, TCODE_WRITE_QUADLET_REQUEST, lu->tgt->node_id, lu->generation, device->max_speed, -- cgit v1.2.3-58-ga151 From 080de8c2c57e3199eee837fe8b6d35a43679f8c1 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Thu, 28 Feb 2008 20:54:43 +0100 Subject: firewire: fw-ohci: add option for remote debugging This way firewire-ohci can be used for remote debugging like ohci1394. Version with amendment from Fri, 11 Apr 2008 00:08:08 +0200. Signed-off-by: Stefan Richter Acked-by: Bernhard Kaindl --- Documentation/debugging-via-ohci1394.txt | 16 ++++++++++------ drivers/firewire/fw-ohci.c | 9 +++++++++ lib/Kconfig.debug | 13 ++++++++++++- 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/Documentation/debugging-via-ohci1394.txt b/Documentation/debugging-via-ohci1394.txt index c360d4e91b48..59a91e5c6909 100644 --- a/Documentation/debugging-via-ohci1394.txt +++ b/Documentation/debugging-via-ohci1394.txt @@ -41,15 +41,19 @@ to a working state and enables physical DMA by default for all remote nodes. This can be turned off by ohci1394's module parameter phys_dma=0. The alternative firewire-ohci driver in drivers/firewire uses filtered physical -DMA, hence is not yet suitable for remote debugging. +DMA by default, which is more secure but not suitable for remote debugging. +Compile the driver with CONFIG_FIREWIRE_OHCI_REMOTE_DMA (Kernel hacking menu: +Remote debugging over FireWire with firewire-ohci) to get unfiltered physical +DMA. -Because ohci1394 depends on the PCI enumeration to be completed, an -initialization routine which runs pretty early (long before console_init() -which makes the printk buffer appear on the console can be called) was written. +Because ohci1394 and firewire-ohci depend on the PCI enumeration to be +completed, an initialization routine which runs pretty early has been +implemented for x86. This routine runs long before console_init() can be +called, i.e. before the printk buffer appears on the console. To activate it, enable CONFIG_PROVIDE_OHCI1394_DMA_INIT (Kernel hacking menu: -Provide code for enabling DMA over FireWire early on boot) and pass the -parameter "ohci1394_dma=early" to the recompiled kernel on boot. +Remote debugging over FireWire early on boot) and pass the parameter +"ohci1394_dma=early" to the recompiled kernel on boot. Tools ----- diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c index 07d6053ff57e..5da7c6715e1e 100644 --- a/drivers/firewire/fw-ohci.c +++ b/drivers/firewire/fw-ohci.c @@ -1097,6 +1097,11 @@ static void bus_reset_tasklet(unsigned long data) reg_write(ohci, OHCI1394_ConfigROMhdr, ohci->next_header); } +#ifdef CONFIG_FIREWIRE_OHCI_REMOTE_DMA + reg_write(ohci, OHCI1394_PhyReqFilterHiSet, ~0); + reg_write(ohci, OHCI1394_PhyReqFilterLoSet, ~0); +#endif + spin_unlock_irqrestore(&ohci->lock, flags); if (free_rom) @@ -1435,6 +1440,9 @@ static int ohci_cancel_packet(struct fw_card *card, struct fw_packet *packet) static int ohci_enable_phys_dma(struct fw_card *card, int node_id, int generation) { +#ifdef CONFIG_FIREWIRE_OHCI_REMOTE_DMA + return 0; +#else struct fw_ohci *ohci = fw_ohci(card); unsigned long flags; int n, retval = 0; @@ -1466,6 +1474,7 @@ ohci_enable_phys_dma(struct fw_card *card, int node_id, int generation) out: spin_unlock_irqrestore(&ohci->lock, flags); return retval; +#endif /* CONFIG_FIREWIRE_OHCI_REMOTE_DMA */ } static u64 diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 0796c1a090c0..78955eb6bd94 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -593,7 +593,7 @@ config LATENCYTOP to find out which userspace is blocking on what kernel operations. config PROVIDE_OHCI1394_DMA_INIT - bool "Provide code for enabling DMA over FireWire early on boot" + bool "Remote debugging over FireWire early on boot" depends on PCI && X86 help If you want to debug problems which hang or crash the kernel early @@ -621,4 +621,15 @@ config PROVIDE_OHCI1394_DMA_INIT See Documentation/debugging-via-ohci1394.txt for more information. +config FIREWIRE_OHCI_REMOTE_DMA + bool "Remote debugging over FireWire with firewire-ohci" + depends on FIREWIRE_OHCI + help + This option lets you use the FireWire bus for remote debugging + with help of the firewire-ohci driver. It enables unfiltered + remote DMA in firewire-ohci. + See Documentation/debugging-via-ohci1394.txt for more information. + + If unsure, say N. + source "samples/Kconfig" -- cgit v1.2.3-58-ga151 From eb5ca72effaa7f691f7df5187c5c5d1268311326 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Sat, 1 Mar 2008 12:34:50 +0100 Subject: firewire: fw-ohci: switch on bus power after resume on PPC PMac The platform feature calls in the suspend method switched off cable power, but the calls in the resume method did not switch it back on. Add the necessary feature call to .resume. Also add the corresponding call to .suspend to make .suspend's behavior explicitly the same on all PMacs. Signed-off-by: Stefan Richter --- drivers/firewire/fw-ohci.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c index 5da7c6715e1e..312182d6d970 100644 --- a/drivers/firewire/fw-ohci.c +++ b/drivers/firewire/fw-ohci.c @@ -2251,8 +2251,10 @@ static int pci_suspend(struct pci_dev *pdev, pm_message_t state) if (machine_is(powermac)) { struct device_node *ofn = pci_device_to_OF_node(pdev); - if (ofn) + if (ofn) { pmac_call_feature(PMAC_FTR_1394_ENABLE, ofn, 0, 0); + pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, ofn, 0, 0); + } } #endif /* CONFIG_PPC_PMAC */ @@ -2269,8 +2271,10 @@ static int pci_resume(struct pci_dev *pdev) if (machine_is(powermac)) { struct device_node *ofn = pci_device_to_OF_node(pdev); - if (ofn) + if (ofn) { + pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, ofn, 0, 1); pmac_call_feature(PMAC_FTR_1394_ENABLE, ofn, 0, 1); + } } #endif /* CONFIG_PPC_PMAC */ -- cgit v1.2.3-58-ga151 From 2ed0f181f0d18d2f565bfbd259fe33d53769f72b Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Sat, 1 Mar 2008 12:35:29 +0100 Subject: firewire: fw-ohci: refactor probe, remove, suspend, resume Clean up shared code and variable names. Signed-off-by: Stefan Richter --- drivers/firewire/fw-ohci.c | 99 ++++++++++++++++++++-------------------------- 1 file changed, 42 insertions(+), 57 deletions(-) diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c index 312182d6d970..92ff38f82d96 100644 --- a/drivers/firewire/fw-ohci.c +++ b/drivers/firewire/fw-ohci.c @@ -2054,17 +2054,9 @@ static const struct fw_card_driver ohci_driver = { .stop_iso = ohci_stop_iso, }; -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; - u64 guid; - int err; - size_t size; - #ifdef CONFIG_PPC_PMAC - /* Necessary on some machines if fw-ohci was loaded/ unloaded before */ +static void ohci_pmac_on(struct pci_dev *dev) +{ if (machine_is(powermac)) { struct device_node *ofn = pci_device_to_OF_node(dev); @@ -2073,8 +2065,35 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) pmac_call_feature(PMAC_FTR_1394_ENABLE, ofn, 0, 1); } } +} + +static void ohci_pmac_off(struct pci_dev *dev) +{ + if (machine_is(powermac)) { + struct device_node *ofn = pci_device_to_OF_node(dev); + + if (ofn) { + pmac_call_feature(PMAC_FTR_1394_ENABLE, ofn, 0, 0); + pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, ofn, 0, 0); + } + } +} +#else +#define ohci_pmac_on(dev) +#define ohci_pmac_off(dev) #endif /* CONFIG_PPC_PMAC */ +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; + u64 guid; + int err; + size_t size; + + ohci_pmac_on(dev); + ohci = kzalloc(sizeof(*ohci), GFP_KERNEL); if (ohci == NULL) { fw_error("Could not malloc fw_ohci data.\n"); @@ -2212,75 +2231,41 @@ static void pci_remove(struct pci_dev *dev) pci_release_region(dev, 0); pci_disable_device(dev); kfree(&ohci->card); - -#ifdef CONFIG_PPC_PMAC - /* On UniNorth, power down the cable and turn off the chip clock - * to save power on laptops */ - if (machine_is(powermac)) { - struct device_node *ofn = pci_device_to_OF_node(dev); - - if (ofn) { - pmac_call_feature(PMAC_FTR_1394_ENABLE, ofn, 0, 0); - pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, ofn, 0, 0); - } - } -#endif /* CONFIG_PPC_PMAC */ + ohci_pmac_off(dev); fw_notify("Removed fw-ohci device.\n"); } #ifdef CONFIG_PM -static int pci_suspend(struct pci_dev *pdev, pm_message_t state) +static int pci_suspend(struct pci_dev *dev, pm_message_t state) { - struct fw_ohci *ohci = pci_get_drvdata(pdev); + struct fw_ohci *ohci = pci_get_drvdata(dev); int err; software_reset(ohci); - free_irq(pdev->irq, ohci); - err = pci_save_state(pdev); + free_irq(dev->irq, ohci); + err = pci_save_state(dev); if (err) { fw_error("pci_save_state failed\n"); return err; } - err = pci_set_power_state(pdev, pci_choose_state(pdev, state)); + err = pci_set_power_state(dev, pci_choose_state(dev, state)); if (err) fw_error("pci_set_power_state failed with %d\n", err); - -/* PowerMac suspend code comes last */ -#ifdef CONFIG_PPC_PMAC - if (machine_is(powermac)) { - struct device_node *ofn = pci_device_to_OF_node(pdev); - - if (ofn) { - pmac_call_feature(PMAC_FTR_1394_ENABLE, ofn, 0, 0); - pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, ofn, 0, 0); - } - } -#endif /* CONFIG_PPC_PMAC */ + ohci_pmac_off(dev); return 0; } -static int pci_resume(struct pci_dev *pdev) +static int pci_resume(struct pci_dev *dev) { - struct fw_ohci *ohci = pci_get_drvdata(pdev); + struct fw_ohci *ohci = pci_get_drvdata(dev); int err; -/* PowerMac resume code comes first */ -#ifdef CONFIG_PPC_PMAC - if (machine_is(powermac)) { - struct device_node *ofn = pci_device_to_OF_node(pdev); - - if (ofn) { - pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, ofn, 0, 1); - pmac_call_feature(PMAC_FTR_1394_ENABLE, ofn, 0, 1); - } - } -#endif /* CONFIG_PPC_PMAC */ - - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - err = pci_enable_device(pdev); + ohci_pmac_on(dev); + pci_set_power_state(dev, PCI_D0); + pci_restore_state(dev); + err = pci_enable_device(dev); if (err) { fw_error("pci_enable_device failed\n"); return err; -- cgit v1.2.3-58-ga151 From c8a9a498e16b2a6c0e4e367b1a01f80fdfd7b6e2 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Wed, 19 Mar 2008 21:40:32 +0100 Subject: firewire: fw-ohci: add self ID error check Discard self ID buffer contents if - the selfIDError flag is set, - any of the self ID packets has bit errors. Signed-off-by: Stefan Richter Signed-off-by: Jarod Wilson --- drivers/firewire/fw-ohci.c | 14 ++++++++++---- drivers/firewire/fw-ohci.h | 1 + 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c index 92ff38f82d96..1f6f15f0dce2 100644 --- a/drivers/firewire/fw-ohci.c +++ b/drivers/firewire/fw-ohci.c @@ -1019,20 +1019,26 @@ static void bus_reset_tasklet(unsigned long data) ohci->node_id = reg & (OHCI1394_NodeID_busNumber | OHCI1394_NodeID_nodeNumber); + reg = reg_read(ohci, OHCI1394_SelfIDCount); + if (reg & OHCI1394_SelfIDCount_selfIDError) { + fw_notify("inconsistent self IDs\n"); + return; + } /* * The count in the SelfIDCount register is the number of * bytes in the self ID receive buffer. Since we also receive * the inverted quadlets and a header quadlet, we shift one * bit extra to get the actual number of self IDs. */ - - self_id_count = (reg_read(ohci, OHCI1394_SelfIDCount) >> 3) & 0x3ff; + self_id_count = (reg >> 3) & 0x3ff; generation = (cond_le32_to_cpu(ohci->self_id_cpu[0]) >> 16) & 0xff; rmb(); for (i = 1, j = 0; j < self_id_count; i += 2, j++) { - if (ohci->self_id_cpu[i] != ~ohci->self_id_cpu[i + 1]) - fw_error("inconsistent self IDs\n"); + if (ohci->self_id_cpu[i] != ~ohci->self_id_cpu[i + 1]) { + fw_notify("inconsistent self IDs\n"); + return; + } ohci->self_id_buffer[j] = cond_le32_to_cpu(ohci->self_id_cpu[i]); } diff --git a/drivers/firewire/fw-ohci.h b/drivers/firewire/fw-ohci.h index dec4f04e6b24..5754c6e9d595 100644 --- a/drivers/firewire/fw-ohci.h +++ b/drivers/firewire/fw-ohci.h @@ -30,6 +30,7 @@ #define OHCI1394_HCControl_softReset 0x00010000 #define OHCI1394_SelfIDBuffer 0x064 #define OHCI1394_SelfIDCount 0x068 +#define OHCI1394_SelfIDCount_selfIDError 0x80000000 #define OHCI1394_IRMultiChanMaskHiSet 0x070 #define OHCI1394_IRMultiChanMaskHiClear 0x074 #define OHCI1394_IRMultiChanMaskLoSet 0x078 -- cgit v1.2.3-58-ga151 From 016bf3dfcf7c7fbad8f02e72b6e01d6773426f9d Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Wed, 19 Mar 2008 22:05:02 +0100 Subject: firewire: fw-ohci: catch self_id_count == 0 fw_core_handle_bus_reset() incorrectly relied on the assumption that self_id_count > 0. We check early in fw-ohci and discard the self ID complete event if self_id_count == 0 because a valid event always has at least one self ID packet in it (the one of the local node). Hence treat self_id_count == 0 like any other kind of invalid self ID buffer. Signed-off-by: Stefan Richter Signed-off-by: Jarod Wilson --- drivers/firewire/fw-ohci.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c index 1f6f15f0dce2..0c4a07f11a59 100644 --- a/drivers/firewire/fw-ohci.c +++ b/drivers/firewire/fw-ohci.c @@ -1031,6 +1031,10 @@ static void bus_reset_tasklet(unsigned long data) * bit extra to get the actual number of self IDs. */ self_id_count = (reg >> 3) & 0x3ff; + if (self_id_count == 0) { + fw_notify("inconsistent self IDs\n"); + return; + } generation = (cond_le32_to_cpu(ohci->self_id_cpu[0]) >> 16) & 0xff; rmb(); -- cgit v1.2.3-58-ga151 From ad3c0fe8b8d1656a56ce2ef05ed5ccba790b4566 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Thu, 20 Mar 2008 22:04:36 +0100 Subject: firewire: debug interrupt events This adds debug printks for asynchronous transmission and reception and for self ID reception. They can be enabled at module load time, and at runtime via /sys/module/firewire_ohci/parameters/debug. Signed-off-by: Jarod Wilson Also added: Logging of interrupt event codes and of cancelled AT packets. The code now depends on a Kconfig variable. This makes it easier to build firewire-ohci without the feature or to make it an option in the future. The variable is currently hidden and always on. This feature inflates firewire-ohci.ko by 7 kB = 27% on x86-64 and by 4 kB = 23% on i686. Signed-off-by: Stefan Richter --- drivers/firewire/Kconfig | 5 ++ drivers/firewire/fw-ohci.c | 182 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 187 insertions(+) diff --git a/drivers/firewire/Kconfig b/drivers/firewire/Kconfig index 25bdc2dd9ce1..fb4d391810b6 100644 --- a/drivers/firewire/Kconfig +++ b/drivers/firewire/Kconfig @@ -54,6 +54,11 @@ config FIREWIRE_OHCI directive, use "install modulename /bin/true" for the modules to be blacklisted. +config FIREWIRE_OHCI_DEBUG + bool + depends on FIREWIRE_OHCI + default y + config FIREWIRE_SBP2 tristate "Support for storage devices (SBP-2 protocol driver)" depends on FIREWIRE && SCSI diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c index 0c4a07f11a59..b564b1aae52f 100644 --- a/drivers/firewire/fw-ohci.c +++ b/drivers/firewire/fw-ohci.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -237,6 +238,179 @@ static inline struct fw_ohci *fw_ohci(struct fw_card *card) static char ohci_driver_name[] = KBUILD_MODNAME; +#ifdef CONFIG_FIREWIRE_OHCI_DEBUG + +#define OHCI_PARAM_DEBUG_IRQS 1 +#define OHCI_PARAM_DEBUG_SELFIDS 2 +#define OHCI_PARAM_DEBUG_AT_AR 4 + +static int param_debug; +module_param_named(debug, param_debug, int, 0644); +MODULE_PARM_DESC(debug, "Verbose logging (default = 0" + ", IRQs = " __stringify(OHCI_PARAM_DEBUG_IRQS) + ", self-IDs = " __stringify(OHCI_PARAM_DEBUG_SELFIDS) + ", AT/AR events = " __stringify(OHCI_PARAM_DEBUG_AT_AR) + ", or a combination, or all = -1)"); + +static void log_irqs(u32 evt) +{ + if (likely(!(param_debug & OHCI_PARAM_DEBUG_IRQS))) + return; + + printk(KERN_DEBUG KBUILD_MODNAME ": IRQ %08x%s%s%s%s%s%s%s%s%s%s%s\n", + evt, + evt & OHCI1394_selfIDComplete ? " selfID" : "", + evt & OHCI1394_RQPkt ? " AR_req" : "", + evt & OHCI1394_RSPkt ? " AR_resp" : "", + evt & OHCI1394_reqTxComplete ? " AT_req" : "", + evt & OHCI1394_respTxComplete ? " AT_resp" : "", + evt & OHCI1394_isochRx ? " IR" : "", + evt & OHCI1394_isochTx ? " IT" : "", + evt & OHCI1394_postedWriteErr ? " postedWriteErr" : "", + evt & OHCI1394_cycleTooLong ? " cycleTooLong" : "", + evt & OHCI1394_cycle64Seconds ? " cycle64Seconds" : "", + evt & ~(OHCI1394_selfIDComplete | OHCI1394_RQPkt | + OHCI1394_RSPkt | OHCI1394_reqTxComplete | + OHCI1394_respTxComplete | OHCI1394_isochRx | + OHCI1394_isochTx | OHCI1394_postedWriteErr | + OHCI1394_cycleTooLong | OHCI1394_cycle64Seconds) + ? " ?" : ""); +} + +static const char *speed[] = { + [0] = "S100", [1] = "S200", [2] = "S400", [3] = "beta", +}; +static const char *power[] = { + [0] = "+0W", [1] = "+15W", [2] = "+30W", [3] = "+45W", + [4] = "-3W", [5] = " ?W", [6] = "-3..-6W", [7] = "-3..-10W", +}; +static const char port[] = { '.', '-', 'p', 'c', }; + +static char _p(u32 *s, int shift) +{ + return port[*s >> shift & 3]; +} + +static void log_selfids(int generation, int self_id_count, u32 *s) +{ + if (likely(!(param_debug & OHCI_PARAM_DEBUG_SELFIDS))) + return; + + printk(KERN_DEBUG KBUILD_MODNAME ": %d selfIDs, generation %d\n", + self_id_count, generation); + + for (; self_id_count--; ++s) + if ((*s & 1 << 23) == 0) + printk(KERN_DEBUG "selfID 0: %08x, phy %d [%c%c%c] " + "%s gc=%d %s %s%s%s\n", + *s, *s >> 24 & 63, _p(s, 6), _p(s, 4), _p(s, 2), + speed[*s >> 14 & 3], *s >> 16 & 63, + power[*s >> 8 & 7], *s >> 22 & 1 ? "L" : "", + *s >> 11 & 1 ? "c" : "", *s & 2 ? "i" : ""); + else + printk(KERN_DEBUG "selfID n: %08x, phy %d " + "[%c%c%c%c%c%c%c%c]\n", + *s, *s >> 24 & 63, + _p(s, 16), _p(s, 14), _p(s, 12), _p(s, 10), + _p(s, 8), _p(s, 6), _p(s, 4), _p(s, 2)); +} + +static const char *evts[] = { + [0x00] = "evt_no_status", [0x01] = "-reserved-", + [0x02] = "evt_long_packet", [0x03] = "evt_missing_ack", + [0x04] = "evt_underrun", [0x05] = "evt_overrun", + [0x06] = "evt_descriptor_read", [0x07] = "evt_data_read", + [0x08] = "evt_data_write", [0x09] = "evt_bus_reset", + [0x0a] = "evt_timeout", [0x0b] = "evt_tcode_err", + [0x0c] = "-reserved-", [0x0d] = "-reserved-", + [0x0e] = "evt_unknown", [0x0f] = "evt_flushed", + [0x10] = "-reserved-", [0x11] = "ack_complete", + [0x12] = "ack_pending ", [0x13] = "-reserved-", + [0x14] = "ack_busy_X", [0x15] = "ack_busy_A", + [0x16] = "ack_busy_B", [0x17] = "-reserved-", + [0x18] = "-reserved-", [0x19] = "-reserved-", + [0x1a] = "-reserved-", [0x1b] = "ack_tardy", + [0x1c] = "-reserved-", [0x1d] = "ack_data_error", + [0x1e] = "ack_type_error", [0x1f] = "-reserved-", + [0x20] = "pending/cancelled", +}; +static const char *tcodes[] = { + [0x0] = "QW req", [0x1] = "BW req", + [0x2] = "W resp", [0x3] = "-reserved-", + [0x4] = "QR req", [0x5] = "BR req", + [0x6] = "QR resp", [0x7] = "BR resp", + [0x8] = "cycle start", [0x9] = "Lk req", + [0xa] = "async stream packet", [0xb] = "Lk resp", + [0xc] = "-reserved-", [0xd] = "-reserved-", + [0xe] = "link internal", [0xf] = "-reserved-", +}; +static const char *phys[] = { + [0x0] = "phy config packet", [0x1] = "link-on packet", + [0x2] = "self-id packet", [0x3] = "-reserved-", +}; + +static void log_ar_at_event(char dir, int speed, u32 *header, int evt) +{ + int tcode = header[0] >> 4 & 0xf; + char specific[12]; + + if (likely(!(param_debug & OHCI_PARAM_DEBUG_AT_AR))) + return; + + if (unlikely(evt >= ARRAY_SIZE(evts))) + evt = 0x1f; + + if (header[0] == ~header[1]) { + printk(KERN_DEBUG "A%c %s, %s, %08x\n", + dir, evts[evt], phys[header[0] >> 30 & 0x3], + header[0]); + return; + } + + switch (tcode) { + case 0x0: case 0x6: case 0x8: + snprintf(specific, sizeof(specific), " = %08x", + be32_to_cpu((__force __be32)header[3])); + break; + case 0x1: case 0x5: case 0x7: case 0x9: case 0xb: + snprintf(specific, sizeof(specific), " %x,%x", + header[3] >> 16, header[3] & 0xffff); + break; + default: + specific[0] = '\0'; + } + + switch (tcode) { + case 0xe: case 0xa: + printk(KERN_DEBUG "A%c %s, %s\n", + dir, evts[evt], tcodes[tcode]); + break; + case 0x0: case 0x1: case 0x4: case 0x5: case 0x9: + printk(KERN_DEBUG "A%c spd %x tl %02x, " + "%04x -> %04x, %s, " + "%s, %04x%08x%s\n", + dir, speed, header[0] >> 10 & 0x3f, + header[1] >> 16, header[0] >> 16, evts[evt], + tcodes[tcode], header[1] & 0xffff, header[2], specific); + break; + default: + printk(KERN_DEBUG "A%c spd %x tl %02x, " + "%04x -> %04x, %s, " + "%s%s\n", + dir, speed, header[0] >> 10 & 0x3f, + header[1] >> 16, header[0] >> 16, evts[evt], + tcodes[tcode], specific); + } +} + +#else + +#define log_irqs(evt) +#define log_selfids(generation, self_id_count, sid) +#define log_ar_at_event(dir, speed, header, evt) + +#endif /* CONFIG_FIREWIRE_OHCI_DEBUG */ + static inline void reg_write(const struct fw_ohci *ohci, int offset, u32 data) { writel(data, ohci->registers + offset); @@ -368,6 +542,8 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer) p.timestamp = status & 0xffff; p.generation = ohci->request_generation; + log_ar_at_event('R', p.speed, p.header, status >> 16 & 0x1f); + /* * The OHCI bus reset handler synthesizes a phy packet with * the new generation number when a bus reset happens (see @@ -817,6 +993,8 @@ static int handle_at_packet(struct context *context, evt = le16_to_cpu(last->transfer_status) & 0x1f; packet->timestamp = le16_to_cpu(last->res_count); + log_ar_at_event('T', packet->speed, packet->header, evt); + switch (evt) { case OHCI1394_evt_timeout: /* Async response transmit timed out. */ @@ -1118,6 +1296,8 @@ static void bus_reset_tasklet(unsigned long data) dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE, free_rom, free_rom_bus); + log_selfids(generation, self_id_count, ohci->self_id_buffer); + fw_core_handle_bus_reset(&ohci->card, ohci->node_id, generation, self_id_count, ohci->self_id_buffer); } @@ -1134,6 +1314,7 @@ static irqreturn_t irq_handler(int irq, void *data) return IRQ_NONE; reg_write(ohci, OHCI1394_IntEventClear, event); + log_irqs(event); if (event & OHCI1394_selfIDComplete) tasklet_schedule(&ohci->bus_reset_tasklet); @@ -1436,6 +1617,7 @@ static int ohci_cancel_packet(struct fw_card *card, struct fw_packet *packet) if (packet->ack != 0) goto out; + log_ar_at_event('T', packet->speed, packet->header, 0x20); driver_data->packet = NULL; packet->ack = RCODE_CANCELLED; packet->callback(packet, &ohci->card, packet->ack); -- cgit v1.2.3-58-ga151 From 43286568adb3ccd4b2f1d0cb7393c355f03e4f39 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Tue, 11 Mar 2008 21:22:26 +0100 Subject: firewire: fw-ohci: untangle a mixed unsigned/signed expression and make another expression more readable. Signed-off-by: Stefan Richter --- drivers/firewire/fw-ohci.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c index b564b1aae52f..533788f227dc 100644 --- a/drivers/firewire/fw-ohci.c +++ b/drivers/firewire/fw-ohci.c @@ -494,6 +494,7 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer) struct fw_ohci *ohci = ctx->ohci; struct fw_packet p; u32 status, length, tcode; + int evt; p.header[0] = cond_le32_to_cpu(buffer[0]); p.header[1] = cond_le32_to_cpu(buffer[1]); @@ -536,13 +537,14 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer) /* FIXME: What to do about evt_* errors? */ length = (p.header_length + p.payload_length + 3) / 4; status = cond_le32_to_cpu(buffer[length]); + evt = (status >> 16) & 0x1f; - p.ack = ((status >> 16) & 0x1f) - 16; + p.ack = evt - 16; p.speed = (status >> 21) & 0x7; p.timestamp = status & 0xffff; p.generation = ohci->request_generation; - log_ar_at_event('R', p.speed, p.header, status >> 16 & 0x1f); + log_ar_at_event('R', p.speed, p.header, evt); /* * The OHCI bus reset handler synthesizes a phy packet with @@ -554,7 +556,7 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer) * request. */ - if (p.ack + 16 == 0x09) + if (evt == OHCI1394_evt_bus_reset) ohci->request_generation = (p.header[2] >> 16) & 0xff; else if (ctx == &ohci->ar_request_ctx) fw_core_handle_request(&ohci->card, &p); -- cgit v1.2.3-58-ga151 From 130d5496e2c9104dcabdaa5c19cd941770e20edc Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Mon, 24 Mar 2008 20:55:28 +0100 Subject: firewire: fw-ohci: missing PPC PMac feature calls in failure path Balance ohci_pmac_on and ohci_pmac_off if pci_driver.probe fails. Signed-off-by: Stefan Richter --- drivers/firewire/fw-ohci.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c index 533788f227dc..973e762efc24 100644 --- a/drivers/firewire/fw-ohci.c +++ b/drivers/firewire/fw-ohci.c @@ -2286,8 +2286,6 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) int err; size_t size; - ohci_pmac_on(dev); - ohci = kzalloc(sizeof(*ohci), GFP_KERNEL); if (ohci == NULL) { fw_error("Could not malloc fw_ohci data.\n"); @@ -2296,6 +2294,8 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) fw_card_initialize(&ohci->card, &ohci_driver, &dev->dev); + ohci_pmac_on(dev); + err = pci_enable_device(dev); if (err) { fw_error("Failed to enable OHCI hardware.\n"); @@ -2397,6 +2397,7 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) pci_disable_device(dev); fail_free: kfree(&ohci->card); + ohci_pmac_off(dev); return err; } -- cgit v1.2.3-58-ga151 From 022147242ff6e4b7ab770f00716063f48c088391 Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Fri, 28 Mar 2008 10:02:50 -0400 Subject: firewire: fw-ohci: make sure HCControl register LPS bit is set I've now witnessed multiple occasions where one of my controllers (a very poorly working JMicron PCIe card) fails to get its registers properly set up in ohci_enable(), apparently due to an occasionally very slow to initiate SClk. The easy fix for this problem is to add a tiny while loop to try again a time or three after initially enabling LPS before we move on (or give up). Of course, the card still isn't fully functional yet, but this gets it at least one tiny step closer... Signed-off-by: Jarod Wilson Signed-off-by: Stefan Richter --- drivers/firewire/fw-ohci.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c index 973e762efc24..e88260b67611 100644 --- a/drivers/firewire/fw-ohci.c +++ b/drivers/firewire/fw-ohci.c @@ -1390,6 +1390,8 @@ 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); + u32 lps; + int i; if (software_reset(ohci)) { fw_error("Failed to reset ohci card.\n"); @@ -1401,13 +1403,24 @@ static int ohci_enable(struct fw_card *card, u32 *config_rom, size_t length) * 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. + * full link enabled. However, with some cards (well, at least + * a JMicron PCIe card), we have to try again sometimes. */ reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_LPS | OHCI1394_HCControl_postedWriteEnable); flush_writes(ohci); - msleep(50); + + for (lps = 0, i = 0; !lps && i < 3; i++) { + msleep(50); + lps = reg_read(ohci, OHCI1394_HCControlSet) & + OHCI1394_HCControl_LPS; + } + + if (!lps) { + fw_error("Failed to set Link Power Status\n"); + return -EIO; + } reg_write(ohci, OHCI1394_HCControlClear, OHCI1394_HCControl_noByteSwapData); -- cgit v1.2.3-58-ga151 From 75f7832e3b032c6e4a83c14b58341abd9f2d81ef Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Thu, 3 Apr 2008 17:18:23 -0400 Subject: firewire: fw-ohci: log regAccessFail events While trying to debug this piece of crap JMicron PCI-e controller in my possession, one thought was that perhaps I was encountering register access failures. I'm not, but logging them would be good, so we can see if they are a real problem we should be taking into account anywhere in the code. Signed-off-by: Jarod Wilson Signed-off-by: Stefan Richter (added list contact) --- drivers/firewire/fw-ohci.c | 13 ++++++++++--- drivers/firewire/fw-ohci.h | 1 + 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c index e88260b67611..ce18bab3f9d5 100644 --- a/drivers/firewire/fw-ohci.c +++ b/drivers/firewire/fw-ohci.c @@ -257,7 +257,7 @@ static void log_irqs(u32 evt) if (likely(!(param_debug & OHCI_PARAM_DEBUG_IRQS))) return; - printk(KERN_DEBUG KBUILD_MODNAME ": IRQ %08x%s%s%s%s%s%s%s%s%s%s%s\n", + printk(KERN_DEBUG KBUILD_MODNAME ": IRQ %08x%s%s%s%s%s%s%s%s%s%s%s%s\n", evt, evt & OHCI1394_selfIDComplete ? " selfID" : "", evt & OHCI1394_RQPkt ? " AR_req" : "", @@ -269,11 +269,13 @@ static void log_irqs(u32 evt) evt & OHCI1394_postedWriteErr ? " postedWriteErr" : "", evt & OHCI1394_cycleTooLong ? " cycleTooLong" : "", evt & OHCI1394_cycle64Seconds ? " cycle64Seconds" : "", + evt & OHCI1394_regAccessFail ? " regAccessFail" : "", evt & ~(OHCI1394_selfIDComplete | OHCI1394_RQPkt | OHCI1394_RSPkt | OHCI1394_reqTxComplete | OHCI1394_respTxComplete | OHCI1394_isochRx | OHCI1394_isochTx | OHCI1394_postedWriteErr | - OHCI1394_cycleTooLong | OHCI1394_cycle64Seconds) + OHCI1394_cycleTooLong | OHCI1394_cycle64Seconds | + OHCI1394_regAccessFail) ? " ?" : ""); } @@ -1351,6 +1353,10 @@ static irqreturn_t irq_handler(int irq, void *data) iso_event &= ~(1 << i); } + if (unlikely(event & OHCI1394_regAccessFail)) + fw_error("Register access failure - " + "please notify linux1394-devel@lists.sf.net\n"); + if (unlikely(event & OHCI1394_postedWriteErr)) fw_error("PCI posted write error\n"); @@ -1448,7 +1454,8 @@ static int ohci_enable(struct fw_card *card, u32 *config_rom, size_t length) OHCI1394_reqTxComplete | OHCI1394_respTxComplete | OHCI1394_isochRx | OHCI1394_isochTx | OHCI1394_postedWriteErr | OHCI1394_cycleTooLong | - OHCI1394_cycle64Seconds | OHCI1394_masterIntEnable); + OHCI1394_cycle64Seconds | OHCI1394_regAccessFail | + OHCI1394_masterIntEnable); /* Activate link_on bit and contender bit in our self ID packets.*/ if (ohci_update_phy_reg(card, 4, 0, diff --git a/drivers/firewire/fw-ohci.h b/drivers/firewire/fw-ohci.h index 5754c6e9d595..a2fbb6240ca7 100644 --- a/drivers/firewire/fw-ohci.h +++ b/drivers/firewire/fw-ohci.h @@ -125,6 +125,7 @@ #define OHCI1394_lockRespErr 0x00000200 #define OHCI1394_selfIDComplete 0x00010000 #define OHCI1394_busReset 0x00020000 +#define OHCI1394_regAccessFail 0x00040000 #define OHCI1394_phy 0x00080000 #define OHCI1394_cycleSynch 0x00100000 #define OHCI1394_cycle64Seconds 0x00200000 -- cgit v1.2.3-58-ga151 From 76f73ca1b291a8d014ff0d2d802c817404dd9887 Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Mon, 7 Apr 2008 22:32:33 +0200 Subject: firewire: fw-ohci: don't append to AT context when it's not active I finally tracked down the issues with this JMicron PCI-e card in my possession to a failure to comply with section 7.2.3.2 of the OHCI 1.1 specification (thanks to Kristian for the pointer to illustrate that it is indeed a flaw in this card, not the driver). The controller should simply flush the packets we've appended to its AT queue if a bus reset occurs before they've been transmitted and we'll try again, but something goes wrong and the controller winds up hung. However, we can avoid the problem by simply checking if the IntEvent.busReset register had been set before we try appending to the AT context. When busReset is set, the AT context is completely halted until busReset is cleared, so there's no point in appending AT packets until the register is cleared. So at_context_queue_packet() now checks for busReset being set, and bails with an RCODE_GENERATION packet ack, which results in us trying to append the packet again after recognizing the fact there has been a bus reset, and clearing busReset. Signed-off-by: Jarod Wilson Signed-off-by: Stefan Richter --- drivers/firewire/fw-ohci.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c index ce18bab3f9d5..4789300b8241 100644 --- a/drivers/firewire/fw-ohci.c +++ b/drivers/firewire/fw-ohci.c @@ -950,8 +950,19 @@ at_context_queue_packet(struct context *ctx, struct fw_packet *packet) DESCRIPTOR_IRQ_ALWAYS | DESCRIPTOR_BRANCH_ALWAYS); - /* FIXME: Document how the locking works. */ - if (ohci->generation != packet->generation) { + /* + * If the controller and packet generations don't match, we need to + * bail out and try again. If IntEvent.busReset is set, the AT context + * is halted, so appending to the context and trying to run it is + * futile. Most controllers do the right thing and just flush the AT + * queue (per section 7.2.3.2 of the OHCI 1.1 specification), but + * some controllers (like a JMicron JMB381 PCI-e) misbehave and wind + * up stalling out. So we just bail out in software and try again + * later, and everyone is happy. + * FIXME: Document how the locking works. + */ + if (ohci->generation != packet->generation || + reg_read(ohci, OHCI1394_IntEventSet) & OHCI1394_busReset) { if (packet->payload_length > 0) dma_unmap_single(ohci->card.device, payload_bus, packet->payload_length, DMA_TO_DEVICE); -- cgit v1.2.3-58-ga151 From a007bb857e0b26f5d8b73c2ff90782d9c0972620 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Mon, 7 Apr 2008 22:33:35 +0200 Subject: firewire: fw-ohci: conditionally log busReset interrupts Add a debug option to watch bus reset interrupt events. Half of this patch is taken from Jarod Wilson's first version of the JMicron fix. BusReset interrupts are only generated if the respective module parameter flag was set before the controller is being initialized. Else we keep this event masked to reduce IRQ load in normal operation and to avoid potential problems with buggy chips. Note, this is unlike the other IRQ events whose logging can be enabled any time after chip initialization. This and the influence on what interrupts the chip generates is why I added an extra flag for it. Also, reorder the debug parameter flags according to their perceived usefulness. Signed-off-by: Stefan Richter Signed-off-by: Jarod Wilson --- drivers/firewire/fw-ohci.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c index 4789300b8241..46660ac0dac5 100644 --- a/drivers/firewire/fw-ohci.c +++ b/drivers/firewire/fw-ohci.c @@ -240,24 +240,32 @@ static char ohci_driver_name[] = KBUILD_MODNAME; #ifdef CONFIG_FIREWIRE_OHCI_DEBUG -#define OHCI_PARAM_DEBUG_IRQS 1 +#define OHCI_PARAM_DEBUG_AT_AR 1 #define OHCI_PARAM_DEBUG_SELFIDS 2 -#define OHCI_PARAM_DEBUG_AT_AR 4 +#define OHCI_PARAM_DEBUG_IRQS 4 +#define OHCI_PARAM_DEBUG_BUSRESETS 8 /* only effective before chip init */ static int param_debug; module_param_named(debug, param_debug, int, 0644); MODULE_PARM_DESC(debug, "Verbose logging (default = 0" - ", IRQs = " __stringify(OHCI_PARAM_DEBUG_IRQS) - ", self-IDs = " __stringify(OHCI_PARAM_DEBUG_SELFIDS) ", AT/AR events = " __stringify(OHCI_PARAM_DEBUG_AT_AR) + ", self-IDs = " __stringify(OHCI_PARAM_DEBUG_SELFIDS) + ", IRQs = " __stringify(OHCI_PARAM_DEBUG_IRQS) + ", busReset events = " __stringify(OHCI_PARAM_DEBUG_BUSRESETS) ", or a combination, or all = -1)"); static void log_irqs(u32 evt) { - if (likely(!(param_debug & OHCI_PARAM_DEBUG_IRQS))) + if (likely(!(param_debug & + (OHCI_PARAM_DEBUG_IRQS | OHCI_PARAM_DEBUG_BUSRESETS)))) + return; + + if (!(param_debug & OHCI_PARAM_DEBUG_IRQS) && + !(evt & OHCI1394_busReset)) return; - printk(KERN_DEBUG KBUILD_MODNAME ": IRQ %08x%s%s%s%s%s%s%s%s%s%s%s%s\n", + printk(KERN_DEBUG KBUILD_MODNAME ": IRQ " + "%08x%s%s%s%s%s%s%s%s%s%s%s%s%s\n", evt, evt & OHCI1394_selfIDComplete ? " selfID" : "", evt & OHCI1394_RQPkt ? " AR_req" : "", @@ -270,12 +278,13 @@ static void log_irqs(u32 evt) evt & OHCI1394_cycleTooLong ? " cycleTooLong" : "", evt & OHCI1394_cycle64Seconds ? " cycle64Seconds" : "", evt & OHCI1394_regAccessFail ? " regAccessFail" : "", + evt & OHCI1394_busReset ? " busReset" : "", evt & ~(OHCI1394_selfIDComplete | OHCI1394_RQPkt | OHCI1394_RSPkt | OHCI1394_reqTxComplete | OHCI1394_respTxComplete | OHCI1394_isochRx | OHCI1394_isochTx | OHCI1394_postedWriteErr | OHCI1394_cycleTooLong | OHCI1394_cycle64Seconds | - OHCI1394_regAccessFail) + OHCI1394_regAccessFail | OHCI1394_busReset) ? " ?" : ""); } @@ -1328,7 +1337,8 @@ static irqreturn_t irq_handler(int irq, void *data) if (!event || !~event) return IRQ_NONE; - reg_write(ohci, OHCI1394_IntEventClear, event); + /* busReset must not be cleared yet, see OHCI 1.1 clause 7.2.3.2 */ + reg_write(ohci, OHCI1394_IntEventClear, event & ~OHCI1394_busReset); log_irqs(event); if (event & OHCI1394_selfIDComplete) @@ -1467,6 +1477,8 @@ static int ohci_enable(struct fw_card *card, u32 *config_rom, size_t length) OHCI1394_postedWriteErr | OHCI1394_cycleTooLong | OHCI1394_cycle64Seconds | OHCI1394_regAccessFail | OHCI1394_masterIntEnable); + if (param_debug & OHCI_PARAM_DEBUG_BUSRESETS) + reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset); /* Activate link_on bit and contender bit in our self ID packets.*/ if (ohci_update_phy_reg(card, 4, 0, -- cgit v1.2.3-58-ga151 From 08ddb2f4c270b5dff063f7dbcd7e9248a52e7c65 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Fri, 11 Apr 2008 00:51:15 +0200 Subject: firewire: fw-ohci: extend logging of bus generations and node ID Extend the logging of "AR evt_bus_reset, link internal" to "AR evt_bus_reset, generation ${selfIDGeneration}". That way we can check whether this generation matches the one seen in self ID complete event logging. See OHCI 1.1 clause 8.4.2.3. Also extend logging of "firewire_ohci: * selfIDs, generation *" by "local node ID ffc*" in self ID logging to make the local node in AT/AR event logs more obvious. Signed-off-by: Stefan Richter Signed-off-by: Jarod Wilson --- drivers/firewire/fw-ohci.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c index 46660ac0dac5..b98d81967f70 100644 --- a/drivers/firewire/fw-ohci.c +++ b/drivers/firewire/fw-ohci.c @@ -302,13 +302,13 @@ static char _p(u32 *s, int shift) return port[*s >> shift & 3]; } -static void log_selfids(int generation, int self_id_count, u32 *s) +static void log_selfids(int node_id, int generation, int self_id_count, u32 *s) { if (likely(!(param_debug & OHCI_PARAM_DEBUG_SELFIDS))) return; - printk(KERN_DEBUG KBUILD_MODNAME ": %d selfIDs, generation %d\n", - self_id_count, generation); + printk(KERN_DEBUG KBUILD_MODNAME ": %d selfIDs, generation %d, " + "local node ID %04x\n", self_id_count, generation, node_id); for (; self_id_count--; ++s) if ((*s & 1 << 23) == 0) @@ -371,6 +371,12 @@ static void log_ar_at_event(char dir, int speed, u32 *header, int evt) if (unlikely(evt >= ARRAY_SIZE(evts))) evt = 0x1f; + if (evt == OHCI1394_evt_bus_reset) { + printk(KERN_DEBUG "A%c evt_bus_reset, generation %d\n", + dir, (header[2] >> 16) & 0xff); + return; + } + if (header[0] == ~header[1]) { printk(KERN_DEBUG "A%c %s, %s, %08x\n", dir, evts[evt], phys[header[0] >> 30 & 0x3], @@ -417,7 +423,7 @@ static void log_ar_at_event(char dir, int speed, u32 *header, int evt) #else #define log_irqs(evt) -#define log_selfids(generation, self_id_count, sid) +#define log_selfids(node_id, generation, self_id_count, sid) #define log_ar_at_event(dir, speed, header, evt) #endif /* CONFIG_FIREWIRE_OHCI_DEBUG */ @@ -1320,7 +1326,8 @@ static void bus_reset_tasklet(unsigned long data) dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE, free_rom, free_rom_bus); - log_selfids(generation, self_id_count, ohci->self_id_buffer); + log_selfids(ohci->node_id, generation, + self_id_count, ohci->self_id_buffer); fw_core_handle_bus_reset(&ohci->card, ohci->node_id, generation, self_id_count, ohci->self_id_buffer); -- cgit v1.2.3-58-ga151 From d34316a4bdcd4fef050da584401c7f4ed22482f2 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Sat, 12 Apr 2008 22:31:25 +0200 Subject: firewire: fw-ohci: work around generation bug in TI controllers (fix AV/C and more) Unlike the ohci1394 driver, fw-ohci uses the selfIDGeneration field of bus reset packets to determine the generation of incoming requests as per OHCI 1.1 clause 8.4.2.3. This is more precise --- provided that the controller inserts the correct generation. Texas Instruments chips often don't. This prevented the transmission of response packets, which for example broke AV/C transactions as used when communicating with miniDV cameras and any other AV/C devices. There is apparently no way to detect and adjust incorrect generations. Therefore we ignore the generation of bus reset packets from TI chips and use the generation of the self ID buffer instead. Alas this is received at a slightly wrong time. In rare cases, this could cause us to not respond to legitimate requests or to respond to expired requests. (The latter is less likely because the bus reset packet AR event is typically handled before the self ID complete event.) Bug reported by Mladen Kuntner, who was extraordinarily patient while dealing with the driver maintainers. Fix confirmed to be required and effective for TSB82AA2 and a TSB43AB22 or TSB43AB22A. https://bugzilla.redhat.com/show_bug.cgi?id=243081 Signed-off-by: Stefan Richter Signed-off-by: Jarod Wilson --- drivers/firewire/fw-ohci.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c index b98d81967f70..d5d8177da6d9 100644 --- a/drivers/firewire/fw-ohci.c +++ b/drivers/firewire/fw-ohci.c @@ -181,6 +181,7 @@ struct fw_ohci { int request_generation; u32 bus_seconds; bool old_uninorth; + bool bus_reset_packet_quirk; /* * Spinlock for accessing fw_ohci data. Never call out of @@ -571,14 +572,19 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer) * generation. We only need this for requests; for responses * we use the unique tlabel for finding the matching * request. + * + * Alas some chips sometimes emit bus reset packets with a + * wrong generation. We set the correct generation for these + * at a slightly incorrect time (in bus_reset_tasklet). */ - - if (evt == OHCI1394_evt_bus_reset) - ohci->request_generation = (p.header[2] >> 16) & 0xff; - else if (ctx == &ohci->ar_request_ctx) + if (evt == OHCI1394_evt_bus_reset) { + if (!ohci->bus_reset_packet_quirk) + ohci->request_generation = (p.header[2] >> 16) & 0xff; + } else if (ctx == &ohci->ar_request_ctx) { fw_core_handle_request(&ohci->card, &p); - else + } else { fw_core_handle_response(&ohci->card, &p); + } return buffer + length + 1; } @@ -1285,6 +1291,9 @@ static void bus_reset_tasklet(unsigned long data) context_stop(&ohci->at_response_ctx); reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset); + if (ohci->bus_reset_packet_quirk) + ohci->request_generation = generation; + /* * This next bit is unrelated to the AT context stuff but we * have to do it under the spinlock also. If a new config rom @@ -2360,6 +2369,8 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) 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, -- cgit v1.2.3-58-ga151 From 1dadff71d6356ebb804c3f4f1d3049247e16111c Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Sun, 2 Mar 2008 19:35:42 +0100 Subject: firewire: replace static ROM cache by allocated cache read_bus_info_block() is repeatedly called by workqueue jobs. These will step on each others toes eventually if there are multiple workqueue threads, and we end up with corrupt config ROM images. Signed-off-by: Stefan Richter --- drivers/firewire/fw-device.c | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/drivers/firewire/fw-device.c b/drivers/firewire/fw-device.c index 870125a3638e..20ac9a5afc37 100644 --- a/drivers/firewire/fw-device.c +++ b/drivers/firewire/fw-device.c @@ -400,6 +400,9 @@ read_rom(struct fw_device *device, int generation, int index, u32 *data) return callback_data.rcode; } +#define READ_BIB_ROM_SIZE 256 +#define READ_BIB_STACK_SIZE 16 + /* * Read the bus info block, perform a speed probe, and read all of the rest of * the config ROM. We do all this with a cached bus generation. If the bus @@ -409,16 +412,23 @@ read_rom(struct fw_device *device, int generation, int index, u32 *data) */ static int read_bus_info_block(struct fw_device *device, int generation) { - static u32 rom[256]; - u32 stack[16], sp, key; - int i, end, length; + u32 *rom, *stack; + u32 sp, key; + int i, end, length, ret = -1; + + rom = kmalloc(sizeof(*rom) * READ_BIB_ROM_SIZE + + sizeof(*stack) * READ_BIB_STACK_SIZE, GFP_KERNEL); + if (rom == NULL) + return -ENOMEM; + + stack = &rom[READ_BIB_ROM_SIZE]; device->max_speed = SCODE_100; /* First read the bus info block. */ for (i = 0; i < 5; i++) { if (read_rom(device, generation, i, &rom[i]) != RCODE_COMPLETE) - return -1; + goto out; /* * As per IEEE1212 7.2, during power-up, devices can * reply with a 0 for the first quadlet of the config @@ -428,7 +438,7 @@ static int read_bus_info_block(struct fw_device *device, int generation) * retry mechanism will try again later. */ if (i == 0 && rom[i] == 0) - return -1; + goto out; } device->max_speed = device->node->max_speed; @@ -478,26 +488,26 @@ static int read_bus_info_block(struct fw_device *device, int generation) */ key = stack[--sp]; i = key & 0xffffff; - if (i >= ARRAY_SIZE(rom)) + if (i >= READ_BIB_ROM_SIZE) /* * The reference points outside the standard * config rom area, something's fishy. */ - return -1; + goto out; /* Read header quadlet for the block to get the length. */ if (read_rom(device, generation, i, &rom[i]) != RCODE_COMPLETE) - return -1; + goto out; end = i + (rom[i] >> 16) + 1; i++; - if (end > ARRAY_SIZE(rom)) + if (end > READ_BIB_ROM_SIZE) /* * This block extends outside standard config * area (and the array we're reading it * into). That's broken, so ignore this * device. */ - return -1; + goto out; /* * Now read in the block. If this is a directory @@ -507,9 +517,9 @@ static int read_bus_info_block(struct fw_device *device, int generation) while (i < end) { if (read_rom(device, generation, i, &rom[i]) != RCODE_COMPLETE) - return -1; + goto out; if ((key >> 30) == 3 && (rom[i] >> 30) > 1 && - sp < ARRAY_SIZE(stack)) + sp < READ_BIB_STACK_SIZE) stack[sp++] = i + rom[i]; i++; } @@ -519,11 +529,14 @@ static int read_bus_info_block(struct fw_device *device, int generation) device->config_rom = kmalloc(length * 4, GFP_KERNEL); if (device->config_rom == NULL) - return -1; + goto out; memcpy(device->config_rom, rom, length * 4); device->config_rom_length = length; + ret = 0; + out: + kfree(rom); - return 0; + return ret; } static void fw_unit_release(struct device *dev) -- cgit v1.2.3-58-ga151 From c9755e14a01987ada4063e8b4c50c2b6738d879e Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Mon, 24 Mar 2008 20:54:28 +0100 Subject: firewire: reread config ROM when device reset the bus When a device changes its configuration ROM, it announces this with a bus reset. firewire-core has to check which node initiated a bus reset and whether any unit directories went away or were added on this node. Tested with an IOI FWB-IDE01AB which has its link-on bit set if bus power is available but does not respond to ROM read requests if self power is off. This implements - recognition of the units if self power is switched on after fw-core gave up the initial attempt to read the config ROM, - shutdown of the units when self power is switched off. Also tested with a second PC running Linux/ieee1394. When the eth1394 driver is inserted and removed on that node, fw-core now notices the addition and removal of the IPv4 unit on the ieee1394 node. Signed-off-by: Stefan Richter --- drivers/firewire/fw-card.c | 2 +- drivers/firewire/fw-cdev.c | 13 ++- drivers/firewire/fw-device.c | 222 ++++++++++++++++++++++++++++++++++------- drivers/firewire/fw-device.h | 11 ++ drivers/firewire/fw-sbp2.c | 8 +- drivers/firewire/fw-topology.c | 3 + drivers/firewire/fw-topology.h | 11 +- 7 files changed, 223 insertions(+), 47 deletions(-) diff --git a/drivers/firewire/fw-card.c b/drivers/firewire/fw-card.c index 140b34d477de..7e4012db6ad2 100644 --- a/drivers/firewire/fw-card.c +++ b/drivers/firewire/fw-card.c @@ -331,7 +331,7 @@ fw_card_bm_work(struct work_struct *work) */ 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 diff --git a/drivers/firewire/fw-cdev.c b/drivers/firewire/fw-cdev.c index 46bc197a047f..4a541921a14a 100644 --- a/drivers/firewire/fw-cdev.c +++ b/drivers/firewire/fw-cdev.c @@ -269,21 +269,28 @@ static int ioctl_get_info(struct client *client, void *buffer) { struct fw_cdev_get_info *get_info = buffer; struct fw_cdev_event_bus_reset bus_reset; + unsigned long ret = 0; client->version = get_info->version; get_info->version = FW_CDEV_VERSION; + down_read(&fw_device_rwsem); + if (get_info->rom != 0) { void __user *uptr = u64_to_uptr(get_info->rom); size_t want = get_info->rom_length; size_t have = client->device->config_rom_length * 4; - if (copy_to_user(uptr, client->device->config_rom, - min(want, have))) - return -EFAULT; + ret = copy_to_user(uptr, client->device->config_rom, + min(want, have)); } get_info->rom_length = client->device->config_rom_length * 4; + up_read(&fw_device_rwsem); + + if (ret != 0) + return -EFAULT; + client->bus_reset_closure = get_info->bus_reset_closure; if (get_info->bus_reset != 0) { void __user *uptr = u64_to_uptr(get_info->bus_reset); diff --git a/drivers/firewire/fw-device.c b/drivers/firewire/fw-device.c index 20ac9a5afc37..75365cd0008a 100644 --- a/drivers/firewire/fw-device.c +++ b/drivers/firewire/fw-device.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include @@ -160,9 +160,9 @@ static void fw_device_release(struct device *dev) * Take the card lock so we don't set this to NULL while a * FW_NODE_UPDATED callback is being handled. */ - spin_lock_irqsave(&device->card->lock, flags); + spin_lock_irqsave(&card->lock, flags); device->node->data = NULL; - spin_unlock_irqrestore(&device->card->lock, flags); + spin_unlock_irqrestore(&card->lock, flags); fw_node_put(device->node); kfree(device->config_rom); @@ -195,7 +195,9 @@ show_immediate(struct device *dev, struct device_attribute *dattr, char *buf) container_of(dattr, struct config_rom_attribute, attr); struct fw_csr_iterator ci; u32 *dir; - int key, value; + int key, value, ret = -ENOENT; + + down_read(&fw_device_rwsem); if (is_fw_unit(dev)) dir = fw_unit(dev)->directory; @@ -204,11 +206,15 @@ show_immediate(struct device *dev, struct device_attribute *dattr, char *buf) fw_csr_iterator_init(&ci, dir); while (fw_csr_iterator_next(&ci, &key, &value)) - if (attr->key == key) - return snprintf(buf, buf ? PAGE_SIZE : 0, - "0x%06x\n", value); + if (attr->key == key) { + ret = snprintf(buf, buf ? PAGE_SIZE : 0, + "0x%06x\n", value); + break; + } + + up_read(&fw_device_rwsem); - return -ENOENT; + return ret; } #define IMMEDIATE_ATTR(name, key) \ @@ -221,9 +227,11 @@ show_text_leaf(struct device *dev, struct device_attribute *dattr, char *buf) container_of(dattr, struct config_rom_attribute, attr); struct fw_csr_iterator ci; u32 *dir, *block = NULL, *p, *end; - int length, key, value, last_key = 0; + int length, key, value, last_key = 0, ret = -ENOENT; char *b; + down_read(&fw_device_rwsem); + if (is_fw_unit(dev)) dir = fw_unit(dev)->directory; else @@ -238,18 +246,20 @@ show_text_leaf(struct device *dev, struct device_attribute *dattr, char *buf) } if (block == NULL) - return -ENOENT; + goto out; length = min(block[0] >> 16, 256U); if (length < 3) - return -ENOENT; + goto out; if (block[1] != 0 || block[2] != 0) /* Unknown encoding. */ - return -ENOENT; + goto out; - if (buf == NULL) - return length * 4; + if (buf == NULL) { + ret = length * 4; + goto out; + } b = buf; end = &block[length + 1]; @@ -259,8 +269,11 @@ show_text_leaf(struct device *dev, struct device_attribute *dattr, char *buf) /* Strip trailing whitespace and add newline. */ while (b--, (isspace(*b) || *b == '\0') && b > buf); strcpy(b + 1, "\n"); + ret = b + 2 - buf; + out: + up_read(&fw_device_rwsem); - return b + 2 - buf; + return ret; } #define TEXT_LEAF_ATTR(name, key) \ @@ -337,19 +350,28 @@ static ssize_t config_rom_show(struct device *dev, struct device_attribute *attr, char *buf) { struct fw_device *device = fw_device(dev); + size_t length; - memcpy(buf, device->config_rom, device->config_rom_length * 4); + down_read(&fw_device_rwsem); + length = device->config_rom_length * 4; + memcpy(buf, device->config_rom, length); + up_read(&fw_device_rwsem); - return device->config_rom_length * 4; + return length; } static ssize_t guid_show(struct device *dev, struct device_attribute *attr, char *buf) { struct fw_device *device = fw_device(dev); + int ret; + + down_read(&fw_device_rwsem); + ret = snprintf(buf, PAGE_SIZE, "0x%08x%08x\n", + device->config_rom[3], device->config_rom[4]); + up_read(&fw_device_rwsem); - return snprintf(buf, PAGE_SIZE, "0x%08x%08x\n", - device->config_rom[3], device->config_rom[4]); + return ret; } static struct device_attribute fw_device_attributes[] = { @@ -412,7 +434,7 @@ read_rom(struct fw_device *device, int generation, int index, u32 *data) */ static int read_bus_info_block(struct fw_device *device, int generation) { - u32 *rom, *stack; + u32 *rom, *stack, *old_rom, *new_rom; u32 sp, key; int i, end, length, ret = -1; @@ -527,12 +549,19 @@ static int read_bus_info_block(struct fw_device *device, int generation) length = i; } - device->config_rom = kmalloc(length * 4, GFP_KERNEL); - if (device->config_rom == NULL) + old_rom = device->config_rom; + new_rom = kmemdup(rom, length * 4, GFP_KERNEL); + if (new_rom == NULL) goto out; - memcpy(device->config_rom, rom, length * 4); + + down_write(&fw_device_rwsem); + device->config_rom = new_rom; device->config_rom_length = length; + up_write(&fw_device_rwsem); + + kfree(old_rom); ret = 0; + device->cmc = rom[2] & 1 << 30; out: kfree(rom); @@ -605,7 +634,14 @@ static int shutdown_unit(struct device *device, void *data) return 0; } -static DECLARE_RWSEM(idr_rwsem); +/* + * fw_device_rwsem acts as dual purpose mutex: + * - serializes accesses to fw_device_idr, + * - serializes accesses to fw_device.config_rom/.config_rom_length and + * fw_unit.directory, unless those accesses happen at safe occasions + */ +DECLARE_RWSEM(fw_device_rwsem); + static DEFINE_IDR(fw_device_idr); int fw_cdev_major; @@ -613,11 +649,11 @@ struct fw_device *fw_device_get_by_devt(dev_t devt) { struct fw_device *device; - down_read(&idr_rwsem); + down_read(&fw_device_rwsem); device = idr_find(&fw_device_idr, MINOR(devt)); if (device) fw_device_get(device); - up_read(&idr_rwsem); + up_read(&fw_device_rwsem); return device; } @@ -632,9 +668,9 @@ static void fw_device_shutdown(struct work_struct *work) device_for_each_child(&device->device, NULL, shutdown_unit); device_unregister(&device->device); - down_write(&idr_rwsem); + down_write(&fw_device_rwsem); idr_remove(&fw_device_idr, minor); - up_write(&idr_rwsem); + up_write(&fw_device_rwsem); fw_device_put(device); } @@ -687,10 +723,10 @@ static void fw_device_init(struct work_struct *work) err = -ENOMEM; fw_device_get(device); - down_write(&idr_rwsem); + down_write(&fw_device_rwsem); if (idr_pre_get(&fw_device_idr, GFP_KERNEL)) err = idr_get_new(&fw_device_idr, device, &minor); - up_write(&idr_rwsem); + up_write(&fw_device_rwsem); if (err < 0) goto error; @@ -724,7 +760,7 @@ static void fw_device_init(struct work_struct *work) if (atomic_cmpxchg(&device->state, FW_DEVICE_INITIALIZING, FW_DEVICE_RUNNING) == FW_DEVICE_SHUTDOWN) { - fw_device_shutdown(&device->work.work); + fw_device_shutdown(work); } else { if (device->config_rom_retries) fw_notify("created device %s: GUID %08x%08x, S%d00, " @@ -738,6 +774,7 @@ static void fw_device_init(struct work_struct *work) device->device.bus_id, device->config_rom[3], device->config_rom[4], 1 << device->max_speed); + device->config_rom_retries = 0; } /* @@ -752,9 +789,9 @@ static void fw_device_init(struct work_struct *work) return; error_with_cdev: - down_write(&idr_rwsem); + down_write(&fw_device_rwsem); idr_remove(&fw_device_idr, minor); - up_write(&idr_rwsem); + up_write(&fw_device_rwsem); error: fw_device_put(device); /* fw_device_idr's reference */ @@ -784,6 +821,106 @@ static void fw_device_update(struct work_struct *work) device_for_each_child(&device->device, NULL, update_unit); } +enum { + REREAD_BIB_ERROR, + REREAD_BIB_GONE, + REREAD_BIB_UNCHANGED, + REREAD_BIB_CHANGED, +}; + +/* Reread and compare bus info block and header of root directory */ +static int reread_bus_info_block(struct fw_device *device, int generation) +{ + u32 q; + int i; + + for (i = 0; i < 6; i++) { + if (read_rom(device, generation, i, &q) != RCODE_COMPLETE) + return REREAD_BIB_ERROR; + + if (i == 0 && q == 0) + return REREAD_BIB_GONE; + + if (i > device->config_rom_length || q != device->config_rom[i]) + return REREAD_BIB_CHANGED; + } + + return REREAD_BIB_UNCHANGED; +} + +static void fw_device_refresh(struct work_struct *work) +{ + struct fw_device *device = + container_of(work, struct fw_device, work.work); + struct fw_card *card = device->card; + int node_id = device->node_id; + + switch (reread_bus_info_block(device, device->generation)) { + case REREAD_BIB_ERROR: + if (device->config_rom_retries < MAX_RETRIES / 2 && + atomic_read(&device->state) == FW_DEVICE_INITIALIZING) { + device->config_rom_retries++; + schedule_delayed_work(&device->work, RETRY_DELAY / 2); + + return; + } + goto give_up; + + case REREAD_BIB_GONE: + goto gone; + + case REREAD_BIB_UNCHANGED: + if (atomic_cmpxchg(&device->state, + FW_DEVICE_INITIALIZING, + FW_DEVICE_RUNNING) == FW_DEVICE_SHUTDOWN) + goto gone; + + fw_device_update(work); + device->config_rom_retries = 0; + goto out; + + case REREAD_BIB_CHANGED: + break; + } + + /* + * Something changed. We keep things simple and don't investigate + * further. We just destroy all previous units and create new ones. + */ + device_for_each_child(&device->device, NULL, shutdown_unit); + + if (read_bus_info_block(device, device->generation) < 0) { + if (device->config_rom_retries < MAX_RETRIES && + atomic_read(&device->state) == FW_DEVICE_INITIALIZING) { + device->config_rom_retries++; + schedule_delayed_work(&device->work, RETRY_DELAY); + + return; + } + goto give_up; + } + + create_units(device); + + if (atomic_cmpxchg(&device->state, + FW_DEVICE_INITIALIZING, + FW_DEVICE_RUNNING) == FW_DEVICE_SHUTDOWN) + goto gone; + + fw_notify("refreshed device %s\n", device->device.bus_id); + device->config_rom_retries = 0; + goto out; + + give_up: + fw_notify("giving up on refresh of device %s\n", device->device.bus_id); + gone: + atomic_set(&device->state, FW_DEVICE_SHUTDOWN); + fw_device_shutdown(work); + out: + if (node_id == card->root_node->node_id) + schedule_delayed_work(&card->work, 0); +} + void fw_node_event(struct fw_card *card, struct fw_node *node, int event) { struct fw_device *device; @@ -793,7 +930,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event) case FW_NODE_LINK_ON: if (!node->link_on) break; - + create: device = kzalloc(sizeof(*device), GFP_ATOMIC); if (device == NULL) break; @@ -832,6 +969,23 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event) schedule_delayed_work(&device->work, INITIAL_DELAY); break; + case FW_NODE_INITIATED_RESET: + device = node->data; + if (device == NULL) + goto create; + + device->node_id = node->node_id; + smp_wmb(); /* update node_id before generation */ + device->generation = card->generation; + if (atomic_cmpxchg(&device->state, + FW_DEVICE_RUNNING, + FW_DEVICE_INITIALIZING) == FW_DEVICE_RUNNING) { + PREPARE_DELAYED_WORK(&device->work, fw_device_refresh); + schedule_delayed_work(&device->work, + node == card->local_node ? 0 : INITIAL_DELAY); + } + break; + case FW_NODE_UPDATED: if (!node->link_on || node->data == NULL) break; diff --git a/drivers/firewire/fw-device.h b/drivers/firewire/fw-device.h index 0d771fda86de..5f131f5129da 100644 --- a/drivers/firewire/fw-device.h +++ b/drivers/firewire/fw-device.h @@ -21,6 +21,7 @@ #include #include +#include #include enum fw_device_state { @@ -46,6 +47,11 @@ struct fw_attribute_group { * fw_device.node_id is guaranteed to be current too. * * The same applies to fw_device.card->node_id vs. fw_device.generation. + * + * fw_device.config_rom and fw_device.config_rom_length may be accessed during + * the lifetime of any fw_unit belonging to the fw_device, before device_del() + * was called on the last fw_unit. Alternatively, they may be accessed while + * holding fw_device_rwsem. */ struct fw_device { atomic_t state; @@ -53,6 +59,7 @@ struct fw_device { int node_id; int generation; unsigned max_speed; + bool cmc; struct fw_card *card; struct device device; struct list_head link; @@ -92,8 +99,12 @@ int fw_device_enable_phys_dma(struct fw_device *device); void fw_device_cdev_update(struct fw_device *device); void fw_device_cdev_remove(struct fw_device *device); +extern struct rw_semaphore fw_device_rwsem; extern int fw_cdev_major; +/* + * fw_unit.directory must not be accessed after device_del(&fw_unit.device). + */ struct fw_unit { struct device device; u32 *directory; diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c index e99a33fcc923..2a999373863e 100644 --- a/drivers/firewire/fw-sbp2.c +++ b/drivers/firewire/fw-sbp2.c @@ -153,6 +153,7 @@ struct sbp2_target { struct list_head lu_list; u64 management_agent_address; + u64 guid; int directory_id; int node_id; int address_high; @@ -1114,6 +1115,7 @@ static int sbp2_probe(struct device *dev) kref_init(&tgt->kref); INIT_LIST_HEAD(&tgt->lu_list); tgt->bus_id = unit->device.bus_id; + tgt->guid = (u64)device->config_rom[3] << 32 | device->config_rom[4]; if (fw_device_enable_phys_dma(device) < 0) goto fail_shost_put; @@ -1571,16 +1573,14 @@ sbp2_sysfs_ieee1394_id_show(struct device *dev, struct device_attribute *attr, { struct scsi_device *sdev = to_scsi_device(dev); struct sbp2_logical_unit *lu; - struct fw_device *device; if (!sdev) return 0; lu = sdev->hostdata; - device = fw_device(lu->tgt->unit->device.parent); - return sprintf(buf, "%08x%08x:%06x:%04x\n", - device->config_rom[3], device->config_rom[4], + return sprintf(buf, "%016llx:%06x:%04x\n", + (unsigned long long)lu->tgt->guid, lu->tgt->directory_id, lu->lun); } diff --git a/drivers/firewire/fw-topology.c b/drivers/firewire/fw-topology.c index d2c7a3d7e1cb..ebdec4c6c689 100644 --- a/drivers/firewire/fw-topology.c +++ b/drivers/firewire/fw-topology.c @@ -108,6 +108,7 @@ static struct fw_node *fw_node_create(u32 sid, int port_count, int color) node->node_id = LOCAL_BUS | SELF_ID_PHY_ID(sid); node->link_on = SELF_ID_LINK_ON(sid); node->phy_speed = SELF_ID_PHY_SPEED(sid); + node->initiated_reset = SELF_ID_PHY_INITIATOR(sid); node->port_count = port_count; atomic_set(&node->ref_count, 1); @@ -431,6 +432,8 @@ update_tree(struct fw_card *card, struct fw_node *root) event = FW_NODE_LINK_OFF; else if (!node0->link_on && node1->link_on) event = FW_NODE_LINK_ON; + else if (node1->initiated_reset && node1->link_on) + event = FW_NODE_INITIATED_RESET; else event = FW_NODE_UPDATED; diff --git a/drivers/firewire/fw-topology.h b/drivers/firewire/fw-topology.h index cedc1ec906e9..addb9f8ea776 100644 --- a/drivers/firewire/fw-topology.h +++ b/drivers/firewire/fw-topology.h @@ -20,11 +20,12 @@ #define __fw_topology_h enum { - FW_NODE_CREATED = 0x00, - FW_NODE_UPDATED = 0x01, - FW_NODE_DESTROYED = 0x02, - FW_NODE_LINK_ON = 0x03, - FW_NODE_LINK_OFF = 0x04, + FW_NODE_CREATED, + FW_NODE_UPDATED, + FW_NODE_DESTROYED, + FW_NODE_LINK_ON, + FW_NODE_LINK_OFF, + FW_NODE_INITIATED_RESET, }; struct fw_node { -- cgit v1.2.3-58-ga151 From cca6097713c62eac43aef27b31e7f1553dde4f94 Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Sat, 8 Mar 2008 12:52:03 -0500 Subject: firewire: replace more hex values with defined csr constants Trivial change to replace more meaningless (to the untrained eye) hex values with defined CSR constants. Signed-off-by: Jarod Wilson Signed-off-by: Stefan Richter --- drivers/firewire/fw-device.c | 2 +- drivers/firewire/fw-transaction.c | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/firewire/fw-device.c b/drivers/firewire/fw-device.c index 75365cd0008a..2d01bc1b9752 100644 --- a/drivers/firewire/fw-device.c +++ b/drivers/firewire/fw-device.c @@ -410,7 +410,7 @@ read_rom(struct fw_device *device, int generation, int index, u32 *data) init_completion(&callback_data.done); - offset = 0xfffff0000400ULL + index * 4; + offset = (CSR_REGISTER_BASE | CSR_CONFIG_ROM) + index * 4; fw_send_request(device->card, &t, TCODE_READ_QUADLET_REQUEST, device->node_id, generation, device->max_speed, offset, NULL, 4, complete_transaction, &callback_data); diff --git a/drivers/firewire/fw-transaction.c b/drivers/firewire/fw-transaction.c index e6f1bda38940..47bfe761250f 100644 --- a/drivers/firewire/fw-transaction.c +++ b/drivers/firewire/fw-transaction.c @@ -396,7 +396,8 @@ const struct fw_address_region fw_high_memory_region = const struct fw_address_region fw_private_region = { .start = 0xffffe0000000ULL, .end = 0xfffff0000000ULL, }; const struct fw_address_region fw_csr_region = - { .start = 0xfffff0000000ULL, .end = 0xfffff0000800ULL, }; + { .start = CSR_REGISTER_BASE, + .end = CSR_REGISTER_BASE | CSR_CONFIG_ROM_END, }; const struct fw_address_region fw_unit_space_region = { .start = 0xfffff0000900ULL, .end = 0x1000000000000ULL, }; EXPORT_SYMBOL(fw_low_memory_region); @@ -747,7 +748,8 @@ fw_core_handle_response(struct fw_card *card, struct fw_packet *p) EXPORT_SYMBOL(fw_core_handle_response); static const struct fw_address_region topology_map_region = - { .start = 0xfffff0001000ull, .end = 0xfffff0001400ull, }; + { .start = CSR_REGISTER_BASE | CSR_TOPOLOGY_MAP, + .end = CSR_REGISTER_BASE | CSR_TOPOLOGY_MAP_END, }; static void handle_topology_map(struct fw_card *card, struct fw_request *request, @@ -785,7 +787,8 @@ static struct fw_address_handler topology_map = { }; static const struct fw_address_region registers_region = - { .start = 0xfffff0000000ull, .end = 0xfffff0000400ull, }; + { .start = CSR_REGISTER_BASE, + .end = CSR_REGISTER_BASE | CSR_CONFIG_ROM, }; static void handle_registers(struct fw_card *card, struct fw_request *request, -- cgit v1.2.3-58-ga151 From 15f0d833f63da2fa49aed81480a37d5e896b5b9b Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Sat, 8 Mar 2008 13:18:58 -0500 Subject: firewire: use bitwise and to get reg in handle_registers for code efficiency. Signed-off-by: Jarod Wilson Signed-off-by: Stefan Richter --- drivers/firewire/fw-transaction.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/firewire/fw-transaction.c b/drivers/firewire/fw-transaction.c index 47bfe761250f..3682e75a09e1 100644 --- a/drivers/firewire/fw-transaction.c +++ b/drivers/firewire/fw-transaction.c @@ -797,7 +797,7 @@ handle_registers(struct fw_card *card, struct fw_request *request, unsigned long long offset, void *payload, size_t length, void *callback_data) { - int reg = offset - CSR_REGISTER_BASE; + int reg = offset & ~CSR_REGISTER_BASE; unsigned long long bus_time; __be32 *data = payload; -- cgit v1.2.3-58-ga151 From e09770db0fa33baf8df21fbc18aa24a080330c3f Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Tue, 11 Mar 2008 02:23:29 +0100 Subject: firewire: remove unused struct member request_generation is internal to fw-ohci and unneeded in fw_card. Signed-off-by: Stefan Richter --- drivers/firewire/fw-ohci.c | 2 +- drivers/firewire/fw-transaction.h | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c index d5d8177da6d9..4f02c55f13e1 100644 --- a/drivers/firewire/fw-ohci.c +++ b/drivers/firewire/fw-ohci.c @@ -178,7 +178,7 @@ struct fw_ohci { struct tasklet_struct bus_reset_tasklet; int node_id; int generation; - int request_generation; + int request_generation; /* for timestamping incoming requests */ u32 bus_seconds; bool old_uninorth; bool bus_reset_packet_quirk; diff --git a/drivers/firewire/fw-transaction.h b/drivers/firewire/fw-transaction.h index 1a22a23e4596..8d1987f9c61e 100644 --- a/drivers/firewire/fw-transaction.h +++ b/drivers/firewire/fw-transaction.h @@ -224,8 +224,6 @@ struct fw_card { int node_id; int generation; - /* This is the generation used for timestamping incoming requests. */ - int request_generation; int current_tlabel, tlabel_mask; struct list_head transaction_list; struct timer_list flush_timer; -- cgit v1.2.3-58-ga151 From 2a0a2590498be7b92e3e76409c9b8ee722e23c8f Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Thu, 20 Mar 2008 23:48:23 +0100 Subject: firewire: wait until PHY configuration packet was transmitted (fix bus reset loop) We now exit fw_send_phy_config /after/ the PHY config packet has been transmitted, instead of before. A subsequent fw_core_initiate_bus_reset will therefore not overlap with the transmission. This is meant to make the send PHY config packet + reset bus routine more deterministic. Fixes bus reset loop and eventual panic with - VIA VT6307 + IOGEAR hub + Unibrain Fire-i camera http://bugzilla.kernel.org/show_bug.cgi?id=10128 - JMicron card Signed-off-by: Stefan Richter Signed-off-by: Jarod Wilson --- drivers/firewire/fw-transaction.c | 51 +++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/drivers/firewire/fw-transaction.c b/drivers/firewire/fw-transaction.c index 3682e75a09e1..051be78deaba 100644 --- a/drivers/firewire/fw-transaction.c +++ b/drivers/firewire/fw-transaction.c @@ -18,6 +18,7 @@ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include #include #include #include @@ -294,42 +295,40 @@ fw_send_request(struct fw_card *card, struct fw_transaction *t, } EXPORT_SYMBOL(fw_send_request); +struct fw_phy_packet { + struct fw_packet packet; + struct completion done; +}; + static void transmit_phy_packet_callback(struct fw_packet *packet, struct fw_card *card, int status) { - kfree(packet); -} - -static void send_phy_packet(struct fw_card *card, u32 data, int generation) -{ - struct fw_packet *packet; + struct fw_phy_packet *p = + container_of(packet, struct fw_phy_packet, packet); - packet = kzalloc(sizeof(*packet), GFP_ATOMIC); - if (packet == NULL) - return; - - packet->header[0] = data; - packet->header[1] = ~data; - packet->header_length = 8; - packet->payload_length = 0; - packet->speed = SCODE_100; - packet->generation = generation; - packet->callback = transmit_phy_packet_callback; - - card->driver->send_request(card, packet); + complete(&p->done); } void fw_send_phy_config(struct fw_card *card, int node_id, int generation, int gap_count) { - u32 q; - - q = PHY_IDENTIFIER(PHY_PACKET_CONFIG) | - PHY_CONFIG_ROOT_ID(node_id) | - PHY_CONFIG_GAP_COUNT(gap_count); - - send_phy_packet(card, q, generation); + struct fw_phy_packet p; + u32 data = PHY_IDENTIFIER(PHY_PACKET_CONFIG) | + PHY_CONFIG_ROOT_ID(node_id) | + PHY_CONFIG_GAP_COUNT(gap_count); + + 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); + + card->driver->send_request(card, &p.packet); + wait_for_completion(&p.done); } void fw_flush_transactions(struct fw_card *card) -- cgit v1.2.3-58-ga151 From 25b1c3d8889f982ebc6c7b996cfc7fa5f1dce533 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Mon, 24 Mar 2008 20:57:12 +0100 Subject: firewire: fix synchronization of gap counts Fix: The fact that nodes had different gap counts would be overlooked if the bus manager code would pick gap count 63 because of beta repeaters or because of very large hop counts. In this case, the bus manager code would miss that it actually has to send the PHY config packet with gap count 63. Related trivial changes: Use bool for an int used as bool, touch up some comments. Signed-off-by: Stefan Richter --- drivers/firewire/fw-card.c | 8 ++++---- drivers/firewire/fw-topology.c | 7 +++---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/firewire/fw-card.c b/drivers/firewire/fw-card.c index 7e4012db6ad2..681bb8d4ef63 100644 --- a/drivers/firewire/fw-card.c +++ b/drivers/firewire/fw-card.c @@ -220,7 +220,7 @@ fw_card_bm_work(struct work_struct *work) struct bm_data bmd; unsigned long flags; int root_id, new_root_id, irm_id, gap_count, generation, grace; - int do_reset = 0; + bool do_reset = false; spin_lock_irqsave(&card->lock, flags); local_node = card->local_node; @@ -360,14 +360,14 @@ fw_card_bm_work(struct work_struct *work) 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); diff --git a/drivers/firewire/fw-topology.c b/drivers/firewire/fw-topology.c index ebdec4c6c689..213b0ff8f3d6 100644 --- a/drivers/firewire/fw-topology.c +++ b/drivers/firewire/fw-topology.c @@ -290,12 +290,11 @@ static struct fw_node *build_tree(struct fw_card *card, beta_repeaters_present = true; /* - * If all PHYs does not report the same gap count - * setting, we fall back to 63 which will force a gap - * count reconfiguration and a reset. + * If PHYs report different gap counts, set an invalid count + * which will force a gap count reconfiguration and a reset. */ if (SELF_ID_GAP_COUNT(q) != gap_count) - gap_count = 63; + gap_count = 0; update_hop_count(node); -- cgit v1.2.3-58-ga151 From db8be076cad4b843aa743ef462c75022cddd9c63 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 31 Mar 2008 02:22:11 +0300 Subject: firewire: cleanups This patch contains the following cleanups: - #if 0 the following unused structs: - fw-transaction.c:fw_low_memory_region - fw-transaction.c:fw_private_region - fw-transaction.c:fw_csr_region - fw-transaction.c:fw_unit_space_region - remove the following unused EXPORT_SYMBOL's: - fw-card.c:fw_core_add_descriptor - fw-card.c:fw_core_remove_descriptor - fw-iso.c:fw_iso_context_create - fw-iso.c:fw_iso_context_destroy - fw-iso.c:fw_iso_context_start - fw-iso.c:fw_iso_context_queue - fw-iso.c:fw_iso_context_stop Signed-off-by: Adrian Bunk Signed-off-by: Stefan Richter --- drivers/firewire/fw-card.c | 2 -- drivers/firewire/fw-iso.c | 5 ----- drivers/firewire/fw-transaction.c | 13 ++++++------- drivers/firewire/fw-transaction.h | 4 ---- 4 files changed, 6 insertions(+), 18 deletions(-) diff --git a/drivers/firewire/fw-card.c b/drivers/firewire/fw-card.c index 681bb8d4ef63..5b4c0d9f5173 100644 --- a/drivers/firewire/fw-card.c +++ b/drivers/firewire/fw-card.c @@ -167,7 +167,6 @@ fw_core_add_descriptor(struct fw_descriptor *desc) return 0; } -EXPORT_SYMBOL(fw_core_add_descriptor); void fw_core_remove_descriptor(struct fw_descriptor *desc) @@ -182,7 +181,6 @@ 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 diff --git a/drivers/firewire/fw-iso.c b/drivers/firewire/fw-iso.c index 2b640e9be6de..bcbe794a3ea5 100644 --- a/drivers/firewire/fw-iso.c +++ b/drivers/firewire/fw-iso.c @@ -126,7 +126,6 @@ fw_iso_context_create(struct fw_card *card, int type, return ctx; } -EXPORT_SYMBOL(fw_iso_context_create); void fw_iso_context_destroy(struct fw_iso_context *ctx) { @@ -134,14 +133,12 @@ void fw_iso_context_destroy(struct fw_iso_context *ctx) card->driver->free_iso_context(ctx); } -EXPORT_SYMBOL(fw_iso_context_destroy); int fw_iso_context_start(struct fw_iso_context *ctx, int cycle, int sync, int tags) { return ctx->card->driver->start_iso(ctx, cycle, sync, tags); } -EXPORT_SYMBOL(fw_iso_context_start); int fw_iso_context_queue(struct fw_iso_context *ctx, @@ -153,11 +150,9 @@ fw_iso_context_queue(struct fw_iso_context *ctx, return card->driver->queue_iso(ctx, packet, buffer, payload); } -EXPORT_SYMBOL(fw_iso_context_queue); int fw_iso_context_stop(struct fw_iso_context *ctx) { return ctx->card->driver->stop_iso(ctx); } -EXPORT_SYMBOL(fw_iso_context_stop); diff --git a/drivers/firewire/fw-transaction.c b/drivers/firewire/fw-transaction.c index 051be78deaba..3a59e9b783b0 100644 --- a/drivers/firewire/fw-transaction.c +++ b/drivers/firewire/fw-transaction.c @@ -388,10 +388,13 @@ lookup_enclosing_address_handler(struct list_head *list, static DEFINE_SPINLOCK(address_handler_lock); static LIST_HEAD(address_handler_list); -const struct fw_address_region fw_low_memory_region = - { .start = 0x000000000000ULL, .end = 0x000100000000ULL, }; const struct fw_address_region fw_high_memory_region = { .start = 0x000100000000ULL, .end = 0xffffe0000000ULL, }; +EXPORT_SYMBOL(fw_high_memory_region); + +#if 0 +const struct fw_address_region fw_low_memory_region = + { .start = 0x000000000000ULL, .end = 0x000100000000ULL, }; const struct fw_address_region fw_private_region = { .start = 0xffffe0000000ULL, .end = 0xfffff0000000ULL, }; const struct fw_address_region fw_csr_region = @@ -399,11 +402,7 @@ const struct fw_address_region fw_csr_region = .end = CSR_REGISTER_BASE | CSR_CONFIG_ROM_END, }; const struct fw_address_region fw_unit_space_region = { .start = 0xfffff0000900ULL, .end = 0x1000000000000ULL, }; -EXPORT_SYMBOL(fw_low_memory_region); -EXPORT_SYMBOL(fw_high_memory_region); -EXPORT_SYMBOL(fw_private_region); -EXPORT_SYMBOL(fw_csr_region); -EXPORT_SYMBOL(fw_unit_space_region); +#endif /* 0 */ /** * Allocate a range of addresses in the node space of the OHCI diff --git a/drivers/firewire/fw-transaction.h b/drivers/firewire/fw-transaction.h index 8d1987f9c61e..04d3854f6560 100644 --- a/drivers/firewire/fw-transaction.h +++ b/drivers/firewire/fw-transaction.h @@ -201,11 +201,7 @@ struct fw_address_region { u64 end; }; -extern const struct fw_address_region fw_low_memory_region; extern const struct fw_address_region fw_high_memory_region; -extern const struct fw_address_region fw_private_region; -extern const struct fw_address_region fw_csr_region; -extern const struct fw_address_region fw_unit_space_region; int fw_core_add_address_handler(struct fw_address_handler *handler, const struct fw_address_region *region); -- cgit v1.2.3-58-ga151