Skip to content

Commit

Permalink
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/ieee1394/linux1394-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6:
  ieee1394: sbp2: add workarounds for 2nd and 3rd generation iPods
  firewire: sbp2: add workarounds for 2nd and 3rd generation iPods
  firewire: sbp2: fix DMA mapping leak on the failure path
  firewire: sbp2: define some magic numbers as macros
  firewire: sbp2: fix payload limit at S1600 and S3200
  ieee1394: sbp2: don't assume zero model_id or firmware_revision if there is none
  ieee1394: sbp2: fix payload limit at S1600 and S3200
  ieee1394: sbp2: update a help string
  ieee1394: support for speeds greater than S800
  firewire: core: optimize card shutdown
  ieee1394: ohci1394: increase AT req. retries, fix ack_busy_X from Panasonic camcorders and others
  firewire: ohci: increase AT req. retries, fix ack_busy_X from Panasonic camcorders and others
  firewire: ohci: change "context_stop: still active" log message
  firewire: keep highlevel drivers attached during brief connection loss
  firewire: unnecessary BM delay after generation rollover
  firewire: insist on successive self ID complete events
  • Loading branch information
Linus Torvalds committed Jan 30, 2009
2 parents 726a669 + 1448d7c commit ceb5eb0
Show file tree
Hide file tree
Showing 11 changed files with 221 additions and 99 deletions.
4 changes: 2 additions & 2 deletions drivers/firewire/fw-card.c
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ fw_card_bm_work(struct work_struct *work)
root_id = root_node->node_id;
grace = time_after(jiffies, card->reset_jiffies + DIV_ROUND_UP(HZ, 10));

if (card->bm_generation + 1 == generation ||
if (is_next_generation(generation, card->bm_generation) ||
(card->bm_generation != generation && grace)) {
/*
* This first step is to figure out who is IRM and
Expand Down Expand Up @@ -512,7 +512,7 @@ fw_core_remove_card(struct fw_card *card)
fw_core_initiate_bus_reset(card, 1);

mutex_lock(&card_mutex);
list_del(&card->link);
list_del_init(&card->link);
mutex_unlock(&card_mutex);

/* Set up the dummy driver. */
Expand Down
123 changes: 101 additions & 22 deletions drivers/firewire/fw-device.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/idr.h>
#include <linux/jiffies.h>
#include <linux/string.h>
#include <linux/rwsem.h>
#include <linux/semaphore.h>
Expand Down Expand Up @@ -634,45 +635,111 @@ struct fw_device *fw_device_get_by_devt(dev_t devt)
return device;
}

/*
* These defines control the retry behavior for reading the config
* rom. It shouldn't be necessary to tweak these; if the device
* doesn't respond to a config rom read within 10 seconds, it's not
* going to respond at all. As for the initial delay, a lot of
* devices will be able to respond within half a second after bus
* reset. On the other hand, it's not really worth being more
* aggressive than that, since it scales pretty well; if 10 devices
* are plugged in, they're all getting read within one second.
*/

#define MAX_RETRIES 10
#define RETRY_DELAY (3 * HZ)
#define INITIAL_DELAY (HZ / 2)
#define SHUTDOWN_DELAY (2 * HZ)

static void fw_device_shutdown(struct work_struct *work)
{
struct fw_device *device =
container_of(work, struct fw_device, work.work);
int minor = MINOR(device->device.devt);

if (time_is_after_jiffies(device->card->reset_jiffies + SHUTDOWN_DELAY)
&& !list_empty(&device->card->link)) {
schedule_delayed_work(&device->work, SHUTDOWN_DELAY);
return;
}

if (atomic_cmpxchg(&device->state,
FW_DEVICE_GONE,
FW_DEVICE_SHUTDOWN) != FW_DEVICE_GONE)
return;

fw_device_cdev_remove(device);
device_for_each_child(&device->device, NULL, shutdown_unit);
device_unregister(&device->device);

down_write(&fw_device_rwsem);
idr_remove(&fw_device_idr, minor);
up_write(&fw_device_rwsem);

fw_device_put(device);
}

static struct device_type fw_device_type = {
.release = fw_device_release,
};

static void fw_device_update(struct work_struct *work);

/*
* These defines control the retry behavior for reading the config
* rom. It shouldn't be necessary to tweak these; if the device
* doesn't respond to a config rom read within 10 seconds, it's not
* going to respond at all. As for the initial delay, a lot of
* devices will be able to respond within half a second after bus
* reset. On the other hand, it's not really worth being more
* aggressive than that, since it scales pretty well; if 10 devices
* are plugged in, they're all getting read within one second.
* If a device was pending for deletion because its node went away but its
* bus info block and root directory header matches that of a newly discovered
* device, revive the existing fw_device.
* The newly allocated fw_device becomes obsolete instead.
*/
static int lookup_existing_device(struct device *dev, void *data)
{
struct fw_device *old = fw_device(dev);
struct fw_device *new = data;
struct fw_card *card = new->card;
int match = 0;

down_read(&fw_device_rwsem); /* serialize config_rom access */
spin_lock_irq(&card->lock); /* serialize node access */

if (memcmp(old->config_rom, new->config_rom, 6 * 4) == 0 &&
atomic_cmpxchg(&old->state,
FW_DEVICE_GONE,
FW_DEVICE_RUNNING) == FW_DEVICE_GONE) {
struct fw_node *current_node = new->node;
struct fw_node *obsolete_node = old->node;

new->node = obsolete_node;
new->node->data = new;
old->node = current_node;
old->node->data = old;

old->max_speed = new->max_speed;
old->node_id = current_node->node_id;
smp_wmb(); /* update node_id before generation */
old->generation = card->generation;
old->config_rom_retries = 0;
fw_notify("rediscovered device %s\n", dev_name(dev));

#define MAX_RETRIES 10
#define RETRY_DELAY (3 * HZ)
#define INITIAL_DELAY (HZ / 2)
PREPARE_DELAYED_WORK(&old->work, fw_device_update);
schedule_delayed_work(&old->work, 0);

if (current_node == card->root_node)
fw_schedule_bm_work(card, 0);

match = 1;
}

spin_unlock_irq(&card->lock);
up_read(&fw_device_rwsem);

return match;
}

static void fw_device_init(struct work_struct *work)
{
struct fw_device *device =
container_of(work, struct fw_device, work.work);
struct device *revived_dev;
int minor, err;

/*
Expand All @@ -696,6 +763,15 @@ static void fw_device_init(struct work_struct *work)
return;
}

revived_dev = device_find_child(device->card->device,
device, lookup_existing_device);
if (revived_dev) {
put_device(revived_dev);
fw_device_release(&device->device);

return;
}

device_initialize(&device->device);

fw_device_get(device);
Expand Down Expand Up @@ -734,9 +810,10 @@ static void fw_device_init(struct work_struct *work)
* fw_node_event().
*/
if (atomic_cmpxchg(&device->state,
FW_DEVICE_INITIALIZING,
FW_DEVICE_RUNNING) == FW_DEVICE_SHUTDOWN) {
fw_device_shutdown(work);
FW_DEVICE_INITIALIZING,
FW_DEVICE_RUNNING) == FW_DEVICE_GONE) {
PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown);
schedule_delayed_work(&device->work, SHUTDOWN_DELAY);
} else {
if (device->config_rom_retries)
fw_notify("created device %s: GUID %08x%08x, S%d00, "
Expand Down Expand Up @@ -847,8 +924,8 @@ static void fw_device_refresh(struct work_struct *work)

case REREAD_BIB_UNCHANGED:
if (atomic_cmpxchg(&device->state,
FW_DEVICE_INITIALIZING,
FW_DEVICE_RUNNING) == FW_DEVICE_SHUTDOWN)
FW_DEVICE_INITIALIZING,
FW_DEVICE_RUNNING) == FW_DEVICE_GONE)
goto gone;

fw_device_update(work);
Expand Down Expand Up @@ -879,8 +956,8 @@ static void fw_device_refresh(struct work_struct *work)
create_units(device);

if (atomic_cmpxchg(&device->state,
FW_DEVICE_INITIALIZING,
FW_DEVICE_RUNNING) == FW_DEVICE_SHUTDOWN)
FW_DEVICE_INITIALIZING,
FW_DEVICE_RUNNING) == FW_DEVICE_GONE)
goto gone;

fw_notify("refreshed device %s\n", dev_name(&device->device));
Expand All @@ -890,8 +967,9 @@ static void fw_device_refresh(struct work_struct *work)
give_up:
fw_notify("giving up on refresh of device %s\n", dev_name(&device->device));
gone:
atomic_set(&device->state, FW_DEVICE_SHUTDOWN);
fw_device_shutdown(work);
atomic_set(&device->state, FW_DEVICE_GONE);
PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown);
schedule_delayed_work(&device->work, SHUTDOWN_DELAY);
out:
if (node_id == card->root_node->node_id)
fw_schedule_bm_work(card, 0);
Expand Down Expand Up @@ -995,9 +1073,10 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
*/
device = node->data;
if (atomic_xchg(&device->state,
FW_DEVICE_SHUTDOWN) == FW_DEVICE_RUNNING) {
FW_DEVICE_GONE) == FW_DEVICE_RUNNING) {
PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown);
schedule_delayed_work(&device->work, 0);
schedule_delayed_work(&device->work,
list_empty(&card->link) ? 0 : SHUTDOWN_DELAY);
}
break;
}
Expand Down
1 change: 1 addition & 0 deletions drivers/firewire/fw-device.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
enum fw_device_state {
FW_DEVICE_INITIALIZING,
FW_DEVICE_RUNNING,
FW_DEVICE_GONE,
FW_DEVICE_SHUTDOWN,
};

Expand Down
6 changes: 3 additions & 3 deletions drivers/firewire/fw-ohci.c
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ static inline struct fw_ohci *fw_ohci(struct fw_card *card)
#define CONTEXT_DEAD 0x0800
#define CONTEXT_ACTIVE 0x0400

#define OHCI1394_MAX_AT_REQ_RETRIES 0x2
#define OHCI1394_MAX_AT_REQ_RETRIES 0xf
#define OHCI1394_MAX_AT_RESP_RETRIES 0x2
#define OHCI1394_MAX_PHYS_RESP_RETRIES 0x8

Expand Down Expand Up @@ -896,11 +896,11 @@ static void context_stop(struct context *ctx)
for (i = 0; i < 10; i++) {
reg = reg_read(ctx->ohci, CONTROL_SET(ctx->regs));
if ((reg & CONTEXT_ACTIVE) == 0)
break;
return;

fw_notify("context_stop: still active (0x%08x)\n", reg);
mdelay(1);
}
fw_error("Error: DMA context still active (0x%08x)\n", reg);
}

struct driver_data {
Expand Down
Loading

0 comments on commit ceb5eb0

Please sign in to comment.