|
@@ -481,6 +481,7 @@ static int read_rom(struct fw_device *device,
|
|
|
* generation changes under us, read_config_rom will fail and get retried.
|
|
|
* It's better to start all over in this case because the node from which we
|
|
|
* are reading the ROM may have changed the ROM during the reset.
|
|
|
+ * Returns either a result code or a negative error code.
|
|
|
*/
|
|
|
static int read_config_rom(struct fw_device *device, int generation)
|
|
|
{
|
|
@@ -488,7 +489,7 @@ static int read_config_rom(struct fw_device *device, int generation)
|
|
|
const u32 *old_rom, *new_rom;
|
|
|
u32 *rom, *stack;
|
|
|
u32 sp, key;
|
|
|
- int i, end, length, ret = -1;
|
|
|
+ int i, end, length, ret;
|
|
|
|
|
|
rom = kmalloc(sizeof(*rom) * MAX_CONFIG_ROM_SIZE +
|
|
|
sizeof(*stack) * MAX_CONFIG_ROM_SIZE, GFP_KERNEL);
|
|
@@ -502,18 +503,21 @@ static int read_config_rom(struct fw_device *device, int generation)
|
|
|
|
|
|
/* First read the bus info block. */
|
|
|
for (i = 0; i < 5; i++) {
|
|
|
- if (read_rom(device, generation, i, &rom[i]) != RCODE_COMPLETE)
|
|
|
+ ret = read_rom(device, generation, i, &rom[i]);
|
|
|
+ if (ret != RCODE_COMPLETE)
|
|
|
goto out;
|
|
|
/*
|
|
|
- * As per IEEE1212 7.2, during power-up, devices can
|
|
|
+ * As per IEEE1212 7.2, during initialization, devices can
|
|
|
* reply with a 0 for the first quadlet of the config
|
|
|
* rom to indicate that they are booting (for example,
|
|
|
* if the firmware is on the disk of a external
|
|
|
* harddisk). In that case we just fail, and the
|
|
|
* retry mechanism will try again later.
|
|
|
*/
|
|
|
- if (i == 0 && rom[i] == 0)
|
|
|
+ if (i == 0 && rom[i] == 0) {
|
|
|
+ ret = RCODE_BUSY;
|
|
|
goto out;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
device->max_speed = device->node->max_speed;
|
|
@@ -563,11 +567,14 @@ static int read_config_rom(struct fw_device *device, int generation)
|
|
|
*/
|
|
|
key = stack[--sp];
|
|
|
i = key & 0xffffff;
|
|
|
- if (WARN_ON(i >= MAX_CONFIG_ROM_SIZE))
|
|
|
+ if (WARN_ON(i >= MAX_CONFIG_ROM_SIZE)) {
|
|
|
+ ret = -ENXIO;
|
|
|
goto out;
|
|
|
+ }
|
|
|
|
|
|
/* Read header quadlet for the block to get the length. */
|
|
|
- if (read_rom(device, generation, i, &rom[i]) != RCODE_COMPLETE)
|
|
|
+ ret = read_rom(device, generation, i, &rom[i]);
|
|
|
+ if (ret != RCODE_COMPLETE)
|
|
|
goto out;
|
|
|
end = i + (rom[i] >> 16) + 1;
|
|
|
if (end > MAX_CONFIG_ROM_SIZE) {
|
|
@@ -590,8 +597,8 @@ static int read_config_rom(struct fw_device *device, int generation)
|
|
|
* it references another block, and push it in that case.
|
|
|
*/
|
|
|
for (; i < end; i++) {
|
|
|
- if (read_rom(device, generation, i, &rom[i]) !=
|
|
|
- RCODE_COMPLETE)
|
|
|
+ ret = read_rom(device, generation, i, &rom[i]);
|
|
|
+ if (ret != RCODE_COMPLETE)
|
|
|
goto out;
|
|
|
|
|
|
if ((key >> 30) != 3 || (rom[i] >> 30) < 2)
|
|
@@ -619,8 +626,10 @@ static int read_config_rom(struct fw_device *device, int generation)
|
|
|
|
|
|
old_rom = device->config_rom;
|
|
|
new_rom = kmemdup(rom, length * 4, GFP_KERNEL);
|
|
|
- if (new_rom == NULL)
|
|
|
+ if (new_rom == NULL) {
|
|
|
+ ret = -ENOMEM;
|
|
|
goto out;
|
|
|
+ }
|
|
|
|
|
|
down_write(&fw_device_rwsem);
|
|
|
device->config_rom = new_rom;
|
|
@@ -628,7 +637,7 @@ static int read_config_rom(struct fw_device *device, int generation)
|
|
|
up_write(&fw_device_rwsem);
|
|
|
|
|
|
kfree(old_rom);
|
|
|
- ret = 0;
|
|
|
+ ret = RCODE_COMPLETE;
|
|
|
device->max_rec = rom[2] >> 12 & 0xf;
|
|
|
device->cmc = rom[2] >> 30 & 1;
|
|
|
device->irmc = rom[2] >> 31 & 1;
|
|
@@ -967,15 +976,17 @@ static void fw_device_init(struct work_struct *work)
|
|
|
* device.
|
|
|
*/
|
|
|
|
|
|
- if (read_config_rom(device, device->generation) < 0) {
|
|
|
+ ret = read_config_rom(device, device->generation);
|
|
|
+ if (ret != RCODE_COMPLETE) {
|
|
|
if (device->config_rom_retries < MAX_RETRIES &&
|
|
|
atomic_read(&device->state) == FW_DEVICE_INITIALIZING) {
|
|
|
device->config_rom_retries++;
|
|
|
fw_schedule_device_work(device, RETRY_DELAY);
|
|
|
} else {
|
|
|
if (device->node->link_on)
|
|
|
- fw_notice(card, "giving up on Config ROM for node id %x\n",
|
|
|
- device->node_id);
|
|
|
+ fw_notice(card, "giving up on node %x: reading config rom failed: %s\n",
|
|
|
+ device->node_id,
|
|
|
+ fw_rcode_string(ret));
|
|
|
if (device->node == card->root_node)
|
|
|
fw_schedule_bm_work(card, 0);
|
|
|
fw_device_release(&device->device);
|
|
@@ -1069,31 +1080,30 @@ static void fw_device_init(struct work_struct *work)
|
|
|
put_device(&device->device); /* our reference */
|
|
|
}
|
|
|
|
|
|
-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_config_rom(struct fw_device *device, int generation)
|
|
|
+static int reread_config_rom(struct fw_device *device, int generation,
|
|
|
+ bool *changed)
|
|
|
{
|
|
|
u32 q;
|
|
|
- int i;
|
|
|
+ int i, rcode;
|
|
|
|
|
|
for (i = 0; i < 6; i++) {
|
|
|
- if (read_rom(device, generation, i, &q) != RCODE_COMPLETE)
|
|
|
- return REREAD_BIB_ERROR;
|
|
|
+ rcode = read_rom(device, generation, i, &q);
|
|
|
+ if (rcode != RCODE_COMPLETE)
|
|
|
+ return rcode;
|
|
|
|
|
|
if (i == 0 && q == 0)
|
|
|
- return REREAD_BIB_GONE;
|
|
|
+ /* inaccessible (see read_config_rom); retry later */
|
|
|
+ return RCODE_BUSY;
|
|
|
|
|
|
- if (q != device->config_rom[i])
|
|
|
- return REREAD_BIB_CHANGED;
|
|
|
+ if (q != device->config_rom[i]) {
|
|
|
+ *changed = true;
|
|
|
+ return RCODE_COMPLETE;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- return REREAD_BIB_UNCHANGED;
|
|
|
+ *changed = false;
|
|
|
+ return RCODE_COMPLETE;
|
|
|
}
|
|
|
|
|
|
static void fw_device_refresh(struct work_struct *work)
|
|
@@ -1101,23 +1111,14 @@ 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_config_rom(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++;
|
|
|
- fw_schedule_device_work(device, RETRY_DELAY / 2);
|
|
|
-
|
|
|
- return;
|
|
|
- }
|
|
|
- goto give_up;
|
|
|
+ int ret, node_id = device->node_id;
|
|
|
+ bool changed;
|
|
|
|
|
|
- case REREAD_BIB_GONE:
|
|
|
- goto gone;
|
|
|
+ ret = reread_config_rom(device, device->generation, &changed);
|
|
|
+ if (ret != RCODE_COMPLETE)
|
|
|
+ goto failed_config_rom;
|
|
|
|
|
|
- case REREAD_BIB_UNCHANGED:
|
|
|
+ if (!changed) {
|
|
|
if (atomic_cmpxchg(&device->state,
|
|
|
FW_DEVICE_INITIALIZING,
|
|
|
FW_DEVICE_RUNNING) == FW_DEVICE_GONE)
|
|
@@ -1126,9 +1127,6 @@ static void fw_device_refresh(struct work_struct *work)
|
|
|
fw_device_update(work);
|
|
|
device->config_rom_retries = 0;
|
|
|
goto out;
|
|
|
-
|
|
|
- case REREAD_BIB_CHANGED:
|
|
|
- break;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -1137,16 +1135,9 @@ static void fw_device_refresh(struct work_struct *work)
|
|
|
*/
|
|
|
device_for_each_child(&device->device, NULL, shutdown_unit);
|
|
|
|
|
|
- if (read_config_rom(device, device->generation) < 0) {
|
|
|
- if (device->config_rom_retries < MAX_RETRIES &&
|
|
|
- atomic_read(&device->state) == FW_DEVICE_INITIALIZING) {
|
|
|
- device->config_rom_retries++;
|
|
|
- fw_schedule_device_work(device, RETRY_DELAY);
|
|
|
-
|
|
|
- return;
|
|
|
- }
|
|
|
- goto give_up;
|
|
|
- }
|
|
|
+ ret = read_config_rom(device, device->generation);
|
|
|
+ if (ret != RCODE_COMPLETE)
|
|
|
+ goto failed_config_rom;
|
|
|
|
|
|
fw_device_cdev_update(device);
|
|
|
create_units(device);
|
|
@@ -1163,9 +1154,16 @@ static void fw_device_refresh(struct work_struct *work)
|
|
|
device->config_rom_retries = 0;
|
|
|
goto out;
|
|
|
|
|
|
- give_up:
|
|
|
- fw_notice(card, "giving up on refresh of device %s\n",
|
|
|
- dev_name(&device->device));
|
|
|
+ failed_config_rom:
|
|
|
+ if (device->config_rom_retries < MAX_RETRIES &&
|
|
|
+ atomic_read(&device->state) == FW_DEVICE_INITIALIZING) {
|
|
|
+ device->config_rom_retries++;
|
|
|
+ fw_schedule_device_work(device, RETRY_DELAY);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ fw_notice(card, "giving up on refresh of device %s: %s\n",
|
|
|
+ dev_name(&device->device), fw_rcode_string(ret));
|
|
|
gone:
|
|
|
atomic_set(&device->state, FW_DEVICE_GONE);
|
|
|
PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown);
|