Commit eddeb0e2 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6: (43 commits)
  firewire: cleanups
  firewire: fix synchronization of gap counts
  firewire: wait until PHY configuration packet was transmitted (fix bus reset loop)
  firewire: remove unused struct member
  firewire: use bitwise and to get reg in handle_registers
  firewire: replace more hex values with defined csr constants
  firewire: reread config ROM when device reset the bus
  firewire: replace static ROM cache by allocated cache
  firewire: fw-ohci: work around generation bug in TI controllers (fix AV/C and more)
  firewire: fw-ohci: extend logging of bus generations and node ID
  firewire: fw-ohci: conditionally log busReset interrupts
  firewire: fw-ohci: don't append to AT context when it's not active
  firewire: fw-ohci: log regAccessFail events
  firewire: fw-ohci: make sure HCControl register LPS bit is set
  firewire: fw-ohci: missing PPC PMac feature calls in failure path
  firewire: fw-ohci: untangle a mixed unsigned/signed expression
  firewire: debug interrupt events
  firewire: fw-ohci: catch self_id_count == 0
  firewire: fw-ohci: add self ID error check
  firewire: fw-ohci: refactor probe, remove, suspend, resume
  ...
parents 855d854a db8be076
......@@ -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
-----
......
......@@ -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
......
......@@ -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
......@@ -220,7 +218,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;
......@@ -331,7 +329,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
......@@ -360,14 +358,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);
......@@ -398,7 +396,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 +426,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 +531,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)
{
......
......@@ -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);
......
......@@ -25,7 +25,7 @@
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/idr.h>
#include <linux/rwsem.h>
#include <linux/string.h>
#include <asm/semaphore.h>
#include <asm/system.h>
#include <linux/ctype.h>
......@@ -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[] = {
......@@ -388,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);
......@@ -400,6 +422,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 +434,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, *old_rom, *new_rom;
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 +460,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 +510,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 +539,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++;
}
......@@ -517,13 +549,23 @@ 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)
return -1;
memcpy(device->config_rom, rom, length * 4);
old_rom = device->config_rom;
new_rom = kmemdup(rom, length * 4, GFP_KERNEL);
if (new_rom == NULL)
goto out;
down_write(&fw_device_rwsem);
device->config_rom = new_rom;
device->config_rom_length = length;
up_write(&fw_device_rwsem);
return 0;
kfree(old_rom);
ret = 0;
device->cmc = rom[2] & 1 << 30;
out:
kfree(rom);
return ret;
}
static void fw_unit_release(struct device *dev)
......@@ -592,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;
......@@ -600,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;
}
......@@ -619,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);
}
......@@ -674,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;
......@@ -711,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, "
......@@ -725,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;
}
/*
......@@ -739,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 */
......@@ -771,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;