Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit febb02bd authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6: (53 commits)
  DVB: firedtv: FireDTV S2 problems with tuning solved
  DVB: firedtv: fix printk format mismatch
  ieee1394: constify device ID tables
  ieee1394: raw1394: add sparse annotations to raw1394_compat_write
  ieee1394: Storage class should be before const qualifier
  ieee1394: sbp2: follow up on "ieee1394: inherit ud vendor_id from node vendor_id"
  firewire: core: optimize propagation of BROADCAST_CHANNEL
  firewire: core: simplify broadcast channel allocation
  firewire: core: increase bus manager grace period
  firewire: core: drop unused call parameters of close_transaction
  firewire: cdev: add closure to async stream ioctl
  firewire: cdev: simplify FW_CDEV_IOC_SEND_REQUEST return value
  firewire: cdev: fix race of ioctl_send_request with bus reset
  firewire: cdev: secure add_descriptor ioctl
  firewire: cdev: amendment to "add ioctl to query maximum transmission speed"
  firewire: broadcast channel support
  firewire: implement asynchronous stream transmission
  firewire: core: normalize a function argument name
  firewire: normalize a variable name
  firewire: core: remove condition which is always false
  ...
parents 0b4d569d 32a0f488
Loading
Loading
Loading
Loading
+80 −69
Original line number Diff line number Diff line
@@ -63,8 +63,7 @@ static int descriptor_count;
#define BIB_CMC			((1) << 30)
#define BIB_IMC			((1) << 31)

static u32 *
generate_config_rom(struct fw_card *card, size_t *config_rom_length)
static u32 *generate_config_rom(struct fw_card *card, size_t *config_rom_length)
{
	struct fw_descriptor *desc;
	static u32 config_rom[256];
@@ -128,8 +127,7 @@ generate_config_rom(struct fw_card *card, size_t *config_rom_length)
	return config_rom;
}

static void
update_config_roms(void)
static void update_config_roms(void)
{
	struct fw_card *card;
	u32 *config_rom;
@@ -141,8 +139,7 @@ update_config_roms(void)
	}
}

int
fw_core_add_descriptor(struct fw_descriptor *desc)
int fw_core_add_descriptor(struct fw_descriptor *desc)
{
	size_t i;

@@ -171,8 +168,7 @@ fw_core_add_descriptor(struct fw_descriptor *desc)
	return 0;
}

void
fw_core_remove_descriptor(struct fw_descriptor *desc)
void fw_core_remove_descriptor(struct fw_descriptor *desc)
{
	mutex_lock(&card_mutex);

@@ -185,12 +181,30 @@ fw_core_remove_descriptor(struct fw_descriptor *desc)
	mutex_unlock(&card_mutex);
}

static int set_broadcast_channel(struct device *dev, void *data)
{
	fw_device_set_broadcast_channel(fw_device(dev), (long)data);
	return 0;
}

static void allocate_broadcast_channel(struct fw_card *card, int generation)
{
	int channel, bandwidth = 0;

	fw_iso_resource_manage(card, generation, 1ULL << 31,
			       &channel, &bandwidth, true);
	if (channel == 31) {
		card->broadcast_channel_allocated = true;
		device_for_each_child(card->device, (void *)(long)generation,
				      set_broadcast_channel);
	}
}

static const char gap_count_table[] = {
	63, 5, 7, 8, 10, 13, 16, 18, 21, 24, 26, 29, 32, 35, 37, 40
};

void
fw_schedule_bm_work(struct fw_card *card, unsigned long delay)
void fw_schedule_bm_work(struct fw_card *card, unsigned long delay)
{
	int scheduled;

@@ -200,37 +214,38 @@ fw_schedule_bm_work(struct fw_card *card, unsigned long delay)
		fw_card_put(card);
}

static void
fw_card_bm_work(struct work_struct *work)
static void fw_card_bm_work(struct work_struct *work)
{
	struct fw_card *card = container_of(work, struct fw_card, work.work);
	struct fw_device *root_device;
	struct fw_node *root_node, *local_node;
	struct fw_node *root_node;
	unsigned long flags;
	int root_id, new_root_id, irm_id, gap_count, generation, grace, rcode;
	int root_id, new_root_id, irm_id, local_id;
	int gap_count, generation, grace, rcode;
	bool do_reset = false;
	bool root_device_is_running;
	bool root_device_is_cmc;
	__be32 lock_data[2];

	spin_lock_irqsave(&card->lock, flags);
	local_node = card->local_node;
	root_node  = card->root_node;

	if (local_node == NULL) {
	if (card->local_node == NULL) {
		spin_unlock_irqrestore(&card->lock, flags);
		goto out_put_card;
	}
	fw_node_get(local_node);
	fw_node_get(root_node);

	generation = card->generation;
	root_node = card->root_node;
	fw_node_get(root_node);
	root_device = root_node->data;
	root_device_is_running = root_device &&
			atomic_read(&root_device->state) == FW_DEVICE_RUNNING;
	root_device_is_cmc = root_device && root_device->cmc;
	root_id  = root_node->node_id;
	grace = time_after(jiffies, card->reset_jiffies + DIV_ROUND_UP(HZ, 10));
	irm_id   = card->irm_node->node_id;
	local_id = card->local_node->node_id;

	grace = time_after(jiffies, card->reset_jiffies + DIV_ROUND_UP(HZ, 8));

	if (is_next_generation(generation, card->bm_generation) ||
	    (card->bm_generation != generation && grace)) {
@@ -246,16 +261,15 @@ fw_card_bm_work(struct work_struct *work)
		 * next generation.
		 */

		irm_id = card->irm_node->node_id;
		if (!card->irm_node->link_on) {
			new_root_id = local_node->node_id;
			new_root_id = local_id;
			fw_notify("IRM has link off, making local node (%02x) root.\n",
				  new_root_id);
			goto pick_me;
		}

		lock_data[0] = cpu_to_be32(0x3f);
		lock_data[1] = cpu_to_be32(local_node->node_id);
		lock_data[1] = cpu_to_be32(local_id);

		spin_unlock_irqrestore(&card->lock, flags);

@@ -269,9 +283,14 @@ fw_card_bm_work(struct work_struct *work)
			goto out;

		if (rcode == RCODE_COMPLETE &&
		    lock_data[0] != cpu_to_be32(0x3f))
			/* Somebody else is BM, let them do the work. */
		    lock_data[0] != cpu_to_be32(0x3f)) {

			/* Somebody else is BM.  Only act as IRM. */
			if (local_id == irm_id)
				allocate_broadcast_channel(card, generation);

			goto out;
		}

		spin_lock_irqsave(&card->lock, flags);

@@ -282,19 +301,18 @@ fw_card_bm_work(struct work_struct *work)
			 * do a bus reset and pick the local node as
			 * root, and thus, IRM.
			 */
			new_root_id = local_node->node_id;
			new_root_id = local_id;
			fw_notify("BM lock failed, making local node (%02x) root.\n",
				  new_root_id);
			goto pick_me;
		}
	} else if (card->bm_generation != generation) {
		/*
		 * OK, we weren't BM in the last generation, and it's
		 * less than 100ms since last bus reset. Reschedule
		 * this task 100ms from now.
		 * We weren't BM in the last generation, and the last
		 * bus reset is less than 125ms ago.  Reschedule this job.
		 */
		spin_unlock_irqrestore(&card->lock, flags);
		fw_schedule_bm_work(card, DIV_ROUND_UP(HZ, 10));
		fw_schedule_bm_work(card, DIV_ROUND_UP(HZ, 8));
		goto out;
	}

@@ -310,7 +328,7 @@ fw_card_bm_work(struct work_struct *work)
		 * Either link_on is false, or we failed to read the
		 * config rom.  In either case, pick another root.
		 */
		new_root_id = local_node->node_id;
		new_root_id = local_id;
	} else if (!root_device_is_running) {
		/*
		 * If we haven't probed this device yet, bail out now
@@ -332,7 +350,7 @@ fw_card_bm_work(struct work_struct *work)
		 * successfully read the config rom, but it's not
		 * cycle master capable.
		 */
		new_root_id = local_node->node_id;
		new_root_id = local_id;
	}

 pick_me:
@@ -363,24 +381,27 @@ fw_card_bm_work(struct work_struct *work)
			  card->index, new_root_id, gap_count);
		fw_send_phy_config(card, new_root_id, generation, gap_count);
		fw_core_initiate_bus_reset(card, 1);
		/* Will allocate broadcast channel after the reset. */
	} else {
		if (local_id == irm_id)
			allocate_broadcast_channel(card, generation);
	}

 out:
	fw_node_put(root_node);
	fw_node_put(local_node);
 out_put_card:
	fw_card_put(card);
}

static void
flush_timer_callback(unsigned long data)
static void flush_timer_callback(unsigned long data)
{
	struct fw_card *card = (struct fw_card *)data;

	fw_flush_transactions(card);
}

void
fw_card_initialize(struct fw_card *card, const struct fw_card_driver *driver,
void fw_card_initialize(struct fw_card *card,
			const struct fw_card_driver *driver,
			struct device *device)
{
	static atomic_t index = ATOMIC_INIT(-1);
@@ -406,13 +427,12 @@ fw_card_initialize(struct fw_card *card, const struct fw_card_driver *driver,
}
EXPORT_SYMBOL(fw_card_initialize);

int
fw_card_add(struct fw_card *card,
int fw_card_add(struct fw_card *card,
		u32 max_receive, u32 link_speed, u64 guid)
{
	u32 *config_rom;
	size_t length;
	int err;
	int ret;

	card->max_receive = max_receive;
	card->link_speed = link_speed;
@@ -423,13 +443,14 @@ fw_card_add(struct fw_card *card,
	list_add_tail(&card->link, &card_list);
	mutex_unlock(&card_mutex);

	err = card->driver->enable(card, config_rom, length);
	if (err < 0) {
	ret = card->driver->enable(card, config_rom, length);
	if (ret < 0) {
		mutex_lock(&card_mutex);
		list_del(&card->link);
		mutex_unlock(&card_mutex);
	}
	return err;

	return ret;
}
EXPORT_SYMBOL(fw_card_add);

@@ -442,22 +463,19 @@ EXPORT_SYMBOL(fw_card_add);
 * dummy driver just fails all IO.
 */

static int
dummy_enable(struct fw_card *card, u32 *config_rom, size_t length)
static int dummy_enable(struct fw_card *card, u32 *config_rom, size_t length)
{
	BUG();
	return -1;
}

static int
dummy_update_phy_reg(struct fw_card *card, int address,
static int dummy_update_phy_reg(struct fw_card *card, int address,
				int clear_bits, int set_bits)
{
	return -ENODEV;
}

static int
dummy_set_config_rom(struct fw_card *card,
static int dummy_set_config_rom(struct fw_card *card,
				u32 *config_rom, size_t length)
{
	/*
@@ -468,26 +486,22 @@ dummy_set_config_rom(struct fw_card *card,
	return -1;
}

static void
dummy_send_request(struct fw_card *card, struct fw_packet *packet)
static void dummy_send_request(struct fw_card *card, struct fw_packet *packet)
{
	packet->callback(packet, card, -ENODEV);
}

static void
dummy_send_response(struct fw_card *card, struct fw_packet *packet)
static void dummy_send_response(struct fw_card *card, struct fw_packet *packet)
{
	packet->callback(packet, card, -ENODEV);
}

static int
dummy_cancel_packet(struct fw_card *card, struct fw_packet *packet)
static int dummy_cancel_packet(struct fw_card *card, struct fw_packet *packet)
{
	return -ENOENT;
}

static int
dummy_enable_phys_dma(struct fw_card *card,
static int dummy_enable_phys_dma(struct fw_card *card,
				 int node_id, int generation)
{
	return -ENODEV;
@@ -503,16 +517,14 @@ static struct fw_card_driver dummy_driver = {
	.enable_phys_dma = dummy_enable_phys_dma,
};

void
fw_card_release(struct kref *kref)
void fw_card_release(struct kref *kref)
{
	struct fw_card *card = container_of(kref, struct fw_card, kref);

	complete(&card->done);
}

void
fw_core_remove_card(struct fw_card *card)
void fw_core_remove_card(struct fw_card *card)
{
	card->driver->update_phy_reg(card, 4,
				     PHY_LINK_ACTIVE | PHY_CONTENDER, 0);
@@ -536,8 +548,7 @@ fw_core_remove_card(struct fw_card *card)
}
EXPORT_SYMBOL(fw_core_remove_card);

int
fw_core_initiate_bus_reset(struct fw_card *card, int short_reset)
int fw_core_initiate_bus_reset(struct fw_card *card, int short_reset)
{
	int reg = short_reset ? 5 : 1;
	int bit = short_reset ? PHY_BUS_SHORT_RESET : PHY_BUS_RESET;
+729 −315

File changed.

Preview size limit exceeded, changes collapsed.

+121 −82
Original line number Diff line number Diff line
@@ -18,22 +18,26 @@
 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include <linux/module.h>
#include <linux/wait.h>
#include <linux/errno.h>
#include <linux/kthread.h>
#include <linux/device.h>
#include <linux/ctype.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/idr.h>
#include <linux/jiffies.h>
#include <linux/string.h>
#include <linux/kobject.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/rwsem.h>
#include <linux/semaphore.h>
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/workqueue.h>

#include <asm/system.h>
#include <linux/ctype.h>
#include "fw-transaction.h"
#include "fw-topology.h"

#include "fw-device.h"
#include "fw-topology.h"
#include "fw-transaction.h"

void fw_csr_iterator_init(struct fw_csr_iterator *ci, u32 * p)
{
@@ -132,8 +136,7 @@ static int get_modalias(struct fw_unit *unit, char *buffer, size_t buffer_size)
			vendor, model, specifier_id, version);
}

static int
fw_unit_uevent(struct device *dev, struct kobj_uevent_env *env)
static int fw_unit_uevent(struct device *dev, struct kobj_uevent_env *env)
{
	struct fw_unit *unit = fw_unit(dev);
	char modalias[64];
@@ -152,27 +155,6 @@ struct bus_type fw_bus_type = {
};
EXPORT_SYMBOL(fw_bus_type);

static void fw_device_release(struct device *dev)
{
	struct fw_device *device = fw_device(dev);
	struct fw_card *card = device->card;
	unsigned long flags;

	/*
	 * Take the card lock so we don't set this to NULL while a
	 * FW_NODE_UPDATED callback is being handled or while the
	 * bus manager work looks at this node.
	 */
	spin_lock_irqsave(&card->lock, flags);
	device->node->data = NULL;
	spin_unlock_irqrestore(&card->lock, flags);

	fw_node_put(device->node);
	kfree(device->config_rom);
	kfree(device);
	fw_card_put(card);
}

int fw_device_enable_phys_dma(struct fw_device *device)
{
	int generation = device->generation;
@@ -191,8 +173,8 @@ struct config_rom_attribute {
	u32 key;
};

static ssize_t
show_immediate(struct device *dev, struct device_attribute *dattr, char *buf)
static ssize_t show_immediate(struct device *dev,
			      struct device_attribute *dattr, char *buf)
{
	struct config_rom_attribute *attr =
		container_of(dattr, struct config_rom_attribute, attr);
@@ -223,8 +205,8 @@ show_immediate(struct device *dev, struct device_attribute *dattr, char *buf)
#define IMMEDIATE_ATTR(name, key)				\
	{ __ATTR(name, S_IRUGO, show_immediate, NULL), key }

static ssize_t
show_text_leaf(struct device *dev, struct device_attribute *dattr, char *buf)
static ssize_t show_text_leaf(struct device *dev,
			      struct device_attribute *dattr, char *buf)
{
	struct config_rom_attribute *attr =
		container_of(dattr, struct config_rom_attribute, attr);
@@ -293,8 +275,7 @@ static struct config_rom_attribute config_rom_attributes[] = {
	TEXT_LEAF_ATTR(hardware_version_name, CSR_HARDWARE_VERSION),
};

static void
init_fw_attribute_group(struct device *dev,
static void init_fw_attribute_group(struct device *dev,
				    struct device_attribute *attrs,
				    struct fw_attribute_group *group)
{
@@ -319,8 +300,7 @@ init_fw_attribute_group(struct device *dev,
	dev->groups = group->groups;
}

static ssize_t
modalias_show(struct device *dev,
static ssize_t modalias_show(struct device *dev,
			     struct device_attribute *attr, char *buf)
{
	struct fw_unit *unit = fw_unit(dev);
@@ -332,8 +312,7 @@ modalias_show(struct device *dev,
	return length + 1;
}

static ssize_t
rom_index_show(struct device *dev,
static ssize_t rom_index_show(struct device *dev,
			      struct device_attribute *attr, char *buf)
{
	struct fw_device *device = fw_device(dev->parent);
@@ -349,8 +328,8 @@ static struct device_attribute fw_unit_attributes[] = {
	__ATTR_NULL,
};

static ssize_t
config_rom_show(struct device *dev, struct device_attribute *attr, char *buf)
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;
@@ -363,8 +342,8 @@ config_rom_show(struct device *dev, struct device_attribute *attr, char *buf)
	return length;
}

static ssize_t
guid_show(struct device *dev, struct device_attribute *attr, char *buf)
static ssize_t guid_show(struct device *dev,
			 struct device_attribute *attr, char *buf)
{
	struct fw_device *device = fw_device(dev);
	int ret;
@@ -383,8 +362,8 @@ static struct device_attribute fw_device_attributes[] = {
	__ATTR_NULL,
};

static int
read_rom(struct fw_device *device, int generation, int index, u32 *data)
static int read_rom(struct fw_device *device,
		    int generation, int index, u32 *data)
{
	int rcode;

@@ -539,7 +518,7 @@ static int read_bus_info_block(struct fw_device *device, int generation)

	kfree(old_rom);
	ret = 0;
	device->cmc = rom[2] & 1 << 30;
	device->cmc = rom[2] >> 30 & 1;
 out:
	kfree(rom);

@@ -679,11 +658,53 @@ static void fw_device_shutdown(struct work_struct *work)
	fw_device_put(device);
}

static void fw_device_release(struct device *dev)
{
	struct fw_device *device = fw_device(dev);
	struct fw_card *card = device->card;
	unsigned long flags;

	/*
	 * Take the card lock so we don't set this to NULL while a
	 * FW_NODE_UPDATED callback is being handled or while the
	 * bus manager work looks at this node.
	 */
	spin_lock_irqsave(&card->lock, flags);
	device->node->data = NULL;
	spin_unlock_irqrestore(&card->lock, flags);

	fw_node_put(device->node);
	kfree(device->config_rom);
	kfree(device);
	fw_card_put(card);
}

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

static void fw_device_update(struct work_struct *work);
static int update_unit(struct device *dev, void *data)
{
	struct fw_unit *unit = fw_unit(dev);
	struct fw_driver *driver = (struct fw_driver *)dev->driver;

	if (is_fw_unit(dev) && driver != NULL && driver->update != NULL) {
		down(&dev->sem);
		driver->update(unit);
		up(&dev->sem);
	}

	return 0;
}

static void fw_device_update(struct work_struct *work)
{
	struct fw_device *device =
		container_of(work, struct fw_device, work.work);

	fw_device_cdev_update(device);
	device_for_each_child(&device->device, NULL, update_unit);
}

/*
 * If a device was pending for deletion because its node went away but its
@@ -735,12 +756,50 @@ static int lookup_existing_device(struct device *dev, void *data)
	return match;
}

enum { BC_UNKNOWN = 0, BC_UNIMPLEMENTED, BC_IMPLEMENTED, };

void fw_device_set_broadcast_channel(struct fw_device *device, int generation)
{
	struct fw_card *card = device->card;
	__be32 data;
	int rcode;

	if (!card->broadcast_channel_allocated)
		return;

	if (device->bc_implemented == BC_UNKNOWN) {
		rcode = fw_run_transaction(card, TCODE_READ_QUADLET_REQUEST,
				device->node_id, generation, device->max_speed,
				CSR_REGISTER_BASE + CSR_BROADCAST_CHANNEL,
				&data, 4);
		switch (rcode) {
		case RCODE_COMPLETE:
			if (data & cpu_to_be32(1 << 31)) {
				device->bc_implemented = BC_IMPLEMENTED;
				break;
			}
			/* else fall through to case address error */
		case RCODE_ADDRESS_ERROR:
			device->bc_implemented = BC_UNIMPLEMENTED;
		}
	}

	if (device->bc_implemented == BC_IMPLEMENTED) {
		data = cpu_to_be32(BROADCAST_CHANNEL_INITIAL |
				   BROADCAST_CHANNEL_VALID);
		fw_run_transaction(card, TCODE_WRITE_QUADLET_REQUEST,
				device->node_id, generation, device->max_speed,
				CSR_REGISTER_BASE + CSR_BROADCAST_CHANNEL,
				&data, 4);
	}
}

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;
	int minor, ret;

	/*
	 * All failure paths here set node->data to NULL, so that we
@@ -776,12 +835,12 @@ static void fw_device_init(struct work_struct *work)

	fw_device_get(device);
	down_write(&fw_device_rwsem);
	err = idr_pre_get(&fw_device_idr, GFP_KERNEL) ?
	ret = idr_pre_get(&fw_device_idr, GFP_KERNEL) ?
	      idr_get_new(&fw_device_idr, device, &minor) :
	      -ENOMEM;
	up_write(&fw_device_rwsem);

	if (err < 0)
	if (ret < 0)
		goto error;

	device->device.bus = &fw_bus_type;
@@ -828,6 +887,8 @@ static void fw_device_init(struct work_struct *work)
				  device->config_rom[3], device->config_rom[4],
				  1 << device->max_speed);
		device->config_rom_retries = 0;

		fw_device_set_broadcast_channel(device, device->generation);
	}

	/*
@@ -851,29 +912,6 @@ static void fw_device_init(struct work_struct *work)
	put_device(&device->device);	/* our reference */
}

static int update_unit(struct device *dev, void *data)
{
	struct fw_unit *unit = fw_unit(dev);
	struct fw_driver *driver = (struct fw_driver *)dev->driver;

	if (is_fw_unit(dev) && driver != NULL && driver->update != NULL) {
		down(&dev->sem);
		driver->update(unit);
		up(&dev->sem);
	}

	return 0;
}

static void fw_device_update(struct work_struct *work)
{
	struct fw_device *device =
		container_of(work, struct fw_device, work.work);

	fw_device_cdev_update(device);
	device_for_each_child(&device->device, NULL, update_unit);
}

enum {
	REREAD_BIB_ERROR,
	REREAD_BIB_GONE,
@@ -894,7 +932,7 @@ static int reread_bus_info_block(struct fw_device *device, int generation)
		if (i == 0 && q == 0)
			return REREAD_BIB_GONE;

		if (i > device->config_rom_length || q != device->config_rom[i])
		if (q != device->config_rom[i])
			return REREAD_BIB_CHANGED;
	}

@@ -1004,6 +1042,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
		device->node = fw_node_get(node);
		device->node_id = node->node_id;
		device->generation = card->generation;
		mutex_init(&device->client_list_mutex);
		INIT_LIST_HEAD(&device->client_list);

		/*
+19 −4
Original line number Diff line number Diff line
@@ -19,10 +19,17 @@
#ifndef __fw_device_h
#define __fw_device_h

#include <linux/device.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/idr.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/rwsem.h>
#include <linux/sysfs.h>
#include <linux/types.h>
#include <linux/workqueue.h>

#include <asm/atomic.h>

enum fw_device_state {
@@ -38,6 +45,9 @@ struct fw_attribute_group {
	struct attribute *attrs[11];
};

struct fw_node;
struct fw_card;

/*
 * Note, fw_device.generation always has to be read before fw_device.node_id.
 * Use SMP memory barriers to ensure this.  Otherwise requests will be sent
@@ -61,13 +71,18 @@ struct fw_device {
	int node_id;
	int generation;
	unsigned max_speed;
	bool cmc;
	struct fw_card *card;
	struct device device;

	struct mutex client_list_mutex;
	struct list_head client_list;

	u32 *config_rom;
	size_t config_rom_length;
	int config_rom_retries;
	unsigned cmc:1;
	unsigned bc_implemented:2;

	struct delayed_work work;
	struct fw_attribute_group attribute_group;
};
@@ -96,6 +111,7 @@ static inline void fw_device_put(struct fw_device *device)

struct fw_device *fw_device_get_by_devt(dev_t devt);
int fw_device_enable_phys_dma(struct fw_device *device);
void fw_device_set_broadcast_channel(struct fw_device *device, int generation);

void fw_device_cdev_update(struct fw_device *device);
void fw_device_cdev_remove(struct fw_device *device);
@@ -176,8 +192,7 @@ struct fw_driver {
	const struct fw_device_id *id_table;
};

static inline struct fw_driver *
fw_driver(struct device_driver *drv)
static inline struct fw_driver *fw_driver(struct device_driver *drv)
{
	return container_of(drv, struct fw_driver, driver);
}
+198 −29
Original line number Diff line number Diff line
/*
 * Isochronous IO functionality
 * Isochronous I/O functionality:
 *   - Isochronous DMA context management
 *   - Isochronous bus resource management (channels, bandwidth), client side
 *
 * Copyright (C) 2006 Kristian Hoegsberg <krh@bitplanet.net>
 *
@@ -18,21 +20,25 @@
 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/dma-mapping.h>
#include <linux/vmalloc.h>
#include <linux/errno.h>
#include <linux/firewire-constants.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/spinlock.h>
#include <linux/vmalloc.h>

#include "fw-transaction.h"
#include "fw-topology.h"
#include "fw-device.h"
#include "fw-transaction.h"

/*
 * Isochronous DMA context management
 */

int
fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card,
int fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card,
		       int page_count, enum dma_data_direction direction)
{
	int i, j, retval = -ENOMEM;
	int i, j;
	dma_addr_t address;

	buffer->page_count = page_count;
@@ -69,19 +75,21 @@ fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card,
	kfree(buffer->pages);
 out:
	buffer->pages = NULL;
	return retval;

	return -ENOMEM;
}

int fw_iso_buffer_map(struct fw_iso_buffer *buffer, struct vm_area_struct *vma)
{
	unsigned long uaddr;
	int i, retval;
	int i, err;

	uaddr = vma->vm_start;
	for (i = 0; i < buffer->page_count; i++) {
		retval = vm_insert_page(vma, uaddr, buffer->pages[i]);
		if (retval)
			return retval;
		err = vm_insert_page(vma, uaddr, buffer->pages[i]);
		if (err)
			return err;

		uaddr += PAGE_SIZE;
	}

@@ -105,14 +113,14 @@ void fw_iso_buffer_destroy(struct fw_iso_buffer *buffer,
	buffer->pages = NULL;
}

struct fw_iso_context *
fw_iso_context_create(struct fw_card *card, int type,
		      int channel, int speed, size_t header_size,
struct fw_iso_context *fw_iso_context_create(struct fw_card *card,
		int type, int channel, int speed, size_t header_size,
		fw_iso_callback_t callback, void *callback_data)
{
	struct fw_iso_context *ctx;

	ctx = card->driver->allocate_iso_context(card, type, header_size);
	ctx = card->driver->allocate_iso_context(card,
						 type, channel, header_size);
	if (IS_ERR(ctx))
		return ctx;

@@ -134,14 +142,13 @@ void fw_iso_context_destroy(struct fw_iso_context *ctx)
	card->driver->free_iso_context(ctx);
}

int
fw_iso_context_start(struct fw_iso_context *ctx, int cycle, int sync, int tags)
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);
}

int
fw_iso_context_queue(struct fw_iso_context *ctx,
int fw_iso_context_queue(struct fw_iso_context *ctx,
			 struct fw_iso_packet *packet,
			 struct fw_iso_buffer *buffer,
			 unsigned long payload)
@@ -151,8 +158,170 @@ fw_iso_context_queue(struct fw_iso_context *ctx,
	return card->driver->queue_iso(ctx, packet, buffer, payload);
}

int
fw_iso_context_stop(struct fw_iso_context *ctx)
int fw_iso_context_stop(struct fw_iso_context *ctx)
{
	return ctx->card->driver->stop_iso(ctx);
}

/*
 * Isochronous bus resource management (channels, bandwidth), client side
 */

static int manage_bandwidth(struct fw_card *card, int irm_id, int generation,
			    int bandwidth, bool allocate)
{
	__be32 data[2];
	int try, new, old = allocate ? BANDWIDTH_AVAILABLE_INITIAL : 0;

	/*
	 * On a 1394a IRM with low contention, try < 1 is enough.
	 * On a 1394-1995 IRM, we need at least try < 2.
	 * Let's just do try < 5.
	 */
	for (try = 0; try < 5; try++) {
		new = allocate ? old - bandwidth : old + bandwidth;
		if (new < 0 || new > BANDWIDTH_AVAILABLE_INITIAL)
			break;

		data[0] = cpu_to_be32(old);
		data[1] = cpu_to_be32(new);
		switch (fw_run_transaction(card, TCODE_LOCK_COMPARE_SWAP,
				irm_id, generation, SCODE_100,
				CSR_REGISTER_BASE + CSR_BANDWIDTH_AVAILABLE,
				data, sizeof(data))) {
		case RCODE_GENERATION:
			/* A generation change frees all bandwidth. */
			return allocate ? -EAGAIN : bandwidth;

		case RCODE_COMPLETE:
			if (be32_to_cpup(data) == old)
				return bandwidth;

			old = be32_to_cpup(data);
			/* Fall through. */
		}
	}

	return -EIO;
}

static int manage_channel(struct fw_card *card, int irm_id, int generation,
			  u32 channels_mask, u64 offset, bool allocate)
{
	__be32 data[2], c, all, old;
	int i, retry = 5;

	old = all = allocate ? cpu_to_be32(~0) : 0;

	for (i = 0; i < 32; i++) {
		if (!(channels_mask & 1 << i))
			continue;

		c = cpu_to_be32(1 << (31 - i));
		if ((old & c) != (all & c))
			continue;

		data[0] = old;
		data[1] = old ^ c;
		switch (fw_run_transaction(card, TCODE_LOCK_COMPARE_SWAP,
					   irm_id, generation, SCODE_100,
					   offset, data, sizeof(data))) {
		case RCODE_GENERATION:
			/* A generation change frees all channels. */
			return allocate ? -EAGAIN : i;

		case RCODE_COMPLETE:
			if (data[0] == old)
				return i;

			old = data[0];

			/* Is the IRM 1394a-2000 compliant? */
			if ((data[0] & c) == (data[1] & c))
				continue;

			/* 1394-1995 IRM, fall through to retry. */
		default:
			if (retry--)
				i--;
		}
	}

	return -EIO;
}

static void deallocate_channel(struct fw_card *card, int irm_id,
			       int generation, int channel)
{
	u32 mask;
	u64 offset;

	mask = channel < 32 ? 1 << channel : 1 << (channel - 32);
	offset = channel < 32 ? CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_HI :
				CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_LO;

	manage_channel(card, irm_id, generation, mask, offset, false);
}

/**
 * fw_iso_resource_manage - Allocate or deallocate a channel and/or bandwidth
 *
 * In parameters: card, generation, channels_mask, bandwidth, allocate
 * Out parameters: channel, bandwidth
 * This function blocks (sleeps) during communication with the IRM.
 *
 * Allocates or deallocates at most one channel out of channels_mask.
 * channels_mask is a bitfield with MSB for channel 63 and LSB for channel 0.
 * (Note, the IRM's CHANNELS_AVAILABLE is a big-endian bitfield with MSB for
 * channel 0 and LSB for channel 63.)
 * Allocates or deallocates as many bandwidth allocation units as specified.
 *
 * Returns channel < 0 if no channel was allocated or deallocated.
 * Returns bandwidth = 0 if no bandwidth was allocated or deallocated.
 *
 * If generation is stale, deallocations succeed but allocations fail with
 * channel = -EAGAIN.
 *
 * If channel allocation fails, no bandwidth will be allocated either.
 * If bandwidth allocation fails, no channel will be allocated either.
 * But deallocations of channel and bandwidth are tried independently
 * of each other's success.
 */
void fw_iso_resource_manage(struct fw_card *card, int generation,
			    u64 channels_mask, int *channel, int *bandwidth,
			    bool allocate)
{
	u32 channels_hi = channels_mask;	/* channels 31...0 */
	u32 channels_lo = channels_mask >> 32;	/* channels 63...32 */
	int irm_id, ret, c = -EINVAL;

	spin_lock_irq(&card->lock);
	irm_id = card->irm_node->node_id;
	spin_unlock_irq(&card->lock);

	if (channels_hi)
		c = manage_channel(card, irm_id, generation, channels_hi,
		    CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_HI, allocate);
	if (channels_lo && c < 0) {
		c = manage_channel(card, irm_id, generation, channels_lo,
		    CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_LO, allocate);
		if (c >= 0)
			c += 32;
	}
	*channel = c;

	if (allocate && channels_mask != 0 && c < 0)
		*bandwidth = 0;

	if (*bandwidth == 0)
		return;

	ret = manage_bandwidth(card, irm_id, generation, *bandwidth, allocate);
	if (ret < 0)
		*bandwidth = 0;

	if (allocate && ret < 0 && c >= 0) {
		deallocate_channel(card, irm_id, generation, c);
		*channel = ret;
	}
}
Loading