mirror of
https://github.com/adulau/aha.git
synced 2024-12-28 19:56:18 +00:00
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 <stefanr@s5r6.in-berlin.de>
This commit is contained in:
parent
d34316a4bd
commit
1dadff71d6
1 changed files with 27 additions and 14 deletions
|
@ -400,6 +400,9 @@ read_rom(struct fw_device *device, int generation, int index, u32 *data)
|
||||||
return callback_data.rcode;
|
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
|
* 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
|
* 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 int read_bus_info_block(struct fw_device *device, int generation)
|
||||||
{
|
{
|
||||||
static u32 rom[256];
|
u32 *rom, *stack;
|
||||||
u32 stack[16], sp, key;
|
u32 sp, key;
|
||||||
int i, end, length;
|
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;
|
device->max_speed = SCODE_100;
|
||||||
|
|
||||||
/* First read the bus info block. */
|
/* First read the bus info block. */
|
||||||
for (i = 0; i < 5; i++) {
|
for (i = 0; i < 5; i++) {
|
||||||
if (read_rom(device, generation, i, &rom[i]) != RCODE_COMPLETE)
|
if (read_rom(device, generation, i, &rom[i]) != RCODE_COMPLETE)
|
||||||
return -1;
|
goto out;
|
||||||
/*
|
/*
|
||||||
* As per IEEE1212 7.2, during power-up, devices can
|
* As per IEEE1212 7.2, during power-up, devices can
|
||||||
* reply with a 0 for the first quadlet of the config
|
* 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.
|
* retry mechanism will try again later.
|
||||||
*/
|
*/
|
||||||
if (i == 0 && rom[i] == 0)
|
if (i == 0 && rom[i] == 0)
|
||||||
return -1;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
device->max_speed = device->node->max_speed;
|
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];
|
key = stack[--sp];
|
||||||
i = key & 0xffffff;
|
i = key & 0xffffff;
|
||||||
if (i >= ARRAY_SIZE(rom))
|
if (i >= READ_BIB_ROM_SIZE)
|
||||||
/*
|
/*
|
||||||
* The reference points outside the standard
|
* The reference points outside the standard
|
||||||
* config rom area, something's fishy.
|
* config rom area, something's fishy.
|
||||||
*/
|
*/
|
||||||
return -1;
|
goto out;
|
||||||
|
|
||||||
/* Read header quadlet for the block to get the length. */
|
/* Read header quadlet for the block to get the length. */
|
||||||
if (read_rom(device, generation, i, &rom[i]) != RCODE_COMPLETE)
|
if (read_rom(device, generation, i, &rom[i]) != RCODE_COMPLETE)
|
||||||
return -1;
|
goto out;
|
||||||
end = i + (rom[i] >> 16) + 1;
|
end = i + (rom[i] >> 16) + 1;
|
||||||
i++;
|
i++;
|
||||||
if (end > ARRAY_SIZE(rom))
|
if (end > READ_BIB_ROM_SIZE)
|
||||||
/*
|
/*
|
||||||
* This block extends outside standard config
|
* This block extends outside standard config
|
||||||
* area (and the array we're reading it
|
* area (and the array we're reading it
|
||||||
* into). That's broken, so ignore this
|
* into). That's broken, so ignore this
|
||||||
* device.
|
* device.
|
||||||
*/
|
*/
|
||||||
return -1;
|
goto out;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now read in the block. If this is a directory
|
* 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) {
|
while (i < end) {
|
||||||
if (read_rom(device, generation, i, &rom[i]) !=
|
if (read_rom(device, generation, i, &rom[i]) !=
|
||||||
RCODE_COMPLETE)
|
RCODE_COMPLETE)
|
||||||
return -1;
|
goto out;
|
||||||
if ((key >> 30) == 3 && (rom[i] >> 30) > 1 &&
|
if ((key >> 30) == 3 && (rom[i] >> 30) > 1 &&
|
||||||
sp < ARRAY_SIZE(stack))
|
sp < READ_BIB_STACK_SIZE)
|
||||||
stack[sp++] = i + rom[i];
|
stack[sp++] = i + rom[i];
|
||||||
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);
|
device->config_rom = kmalloc(length * 4, GFP_KERNEL);
|
||||||
if (device->config_rom == NULL)
|
if (device->config_rom == NULL)
|
||||||
return -1;
|
goto out;
|
||||||
memcpy(device->config_rom, rom, length * 4);
|
memcpy(device->config_rom, rom, length * 4);
|
||||||
device->config_rom_length = length;
|
device->config_rom_length = length;
|
||||||
|
ret = 0;
|
||||||
|
out:
|
||||||
|
kfree(rom);
|
||||||
|
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fw_unit_release(struct device *dev)
|
static void fw_unit_release(struct device *dev)
|
||||||
|
|
Loading…
Reference in a new issue