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

Commit bb592cf4 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:
  ieee1394: Use hweight32
  firewire: cdev: reduce stack usage by ioctl_dispatch
  firewire: ohci: 0 may be a valid DMA address
  firewire: core: WARN on wrong usage of core transaction functions
  firewire: core: optimize Topology Map creation
  firewire: core: clarify generate_config_rom usage
  firewire: optimize config ROM creation
  firewire: cdev: normalize variable names
  firewire: normalize style of queue_work wrappers
  firewire: cdev: fix memory leak in an error path
parents 79c9601c af0940da
Loading
Loading
Loading
Loading
+34 −41
Original line number Diff line number Diff line
@@ -38,15 +38,14 @@

#include "core.h"

int fw_compute_block_crc(u32 *block)
int fw_compute_block_crc(__be32 *block)
{
	__be32 be32_block[256];
	int i, length;
	int length;
	u16 crc;

	length = (*block >> 16) & 0xff;
	for (i = 0; i < length; i++)
		be32_block[i] = cpu_to_be32(block[i + 1]);
	*block |= crc_itu_t(0, (u8 *) be32_block, length * 4);
	length = (be32_to_cpu(block[0]) >> 16) & 0xff;
	crc = crc_itu_t(0, (u8 *)&block[1], length * 4);
	*block |= cpu_to_be32(crc);

	return length;
}
@@ -57,6 +56,8 @@ static LIST_HEAD(card_list);
static LIST_HEAD(descriptor_list);
static int descriptor_count;

static __be32 tmp_config_rom[256];

#define BIB_CRC(v)		((v) <<  0)
#define BIB_CRC_LENGTH(v)	((v) << 16)
#define BIB_INFO_LENGTH(v)	((v) << 24)
@@ -72,11 +73,10 @@ 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 size_t generate_config_rom(struct fw_card *card, __be32 *config_rom)
{
	struct fw_descriptor *desc;
	static u32 config_rom[256];
	int i, j, length;
	int i, j, k, length;

	/*
	 * Initialize contents of config rom buffer.  On the OHCI
@@ -87,40 +87,39 @@ static u32 *generate_config_rom(struct fw_card *card, size_t *config_rom_length)
	 * the version stored in the OHCI registers.
	 */

	memset(config_rom, 0, sizeof(config_rom));
	config_rom[0] = BIB_CRC_LENGTH(4) | BIB_INFO_LENGTH(4) | BIB_CRC(0);
	config_rom[1] = 0x31333934;

	config_rom[2] =
	config_rom[0] = cpu_to_be32(
		BIB_CRC_LENGTH(4) | BIB_INFO_LENGTH(4) | BIB_CRC(0));
	config_rom[1] = cpu_to_be32(0x31333934);
	config_rom[2] = cpu_to_be32(
		BIB_LINK_SPEED(card->link_speed) |
		BIB_GENERATION(card->config_rom_generation++ % 14 + 2) |
		BIB_MAX_ROM(2) |
		BIB_MAX_RECEIVE(card->max_receive) |
		BIB_BMC | BIB_ISC | BIB_CMC | BIB_IMC;
	config_rom[3] = card->guid >> 32;
	config_rom[4] = card->guid;
		BIB_BMC | BIB_ISC | BIB_CMC | BIB_IMC);
	config_rom[3] = cpu_to_be32(card->guid >> 32);
	config_rom[4] = cpu_to_be32(card->guid);

	/* Generate root directory. */
	i = 5;
	config_rom[i++] = 0;
	config_rom[i++] = 0x0c0083c0; /* node capabilities */
	j = i + descriptor_count;
	config_rom[6] = cpu_to_be32(0x0c0083c0); /* node capabilities */
	i = 7;
	j = 7 + descriptor_count;

	/* Generate root directory entries for descriptors. */
	list_for_each_entry (desc, &descriptor_list, link) {
		if (desc->immediate > 0)
			config_rom[i++] = desc->immediate;
		config_rom[i] = desc->key | (j - i);
			config_rom[i++] = cpu_to_be32(desc->immediate);
		config_rom[i] = cpu_to_be32(desc->key | (j - i));
		i++;
		j += desc->length;
	}

	/* Update root directory length. */
	config_rom[5] = (i - 5 - 1) << 16;
	config_rom[5] = cpu_to_be32((i - 5 - 1) << 16);

	/* End of root directory, now copy in descriptors. */
	list_for_each_entry (desc, &descriptor_list, link) {
		memcpy(&config_rom[i], desc->data, desc->length * 4);
		for (k = 0; k < desc->length; k++)
			config_rom[i + k] = cpu_to_be32(desc->data[k]);
		i += desc->length;
	}

@@ -131,20 +130,17 @@ static u32 *generate_config_rom(struct fw_card *card, size_t *config_rom_length)
	for (i = 0; i < j; i += length + 1)
		length = fw_compute_block_crc(config_rom + i);

	*config_rom_length = j;

	return config_rom;
	return j;
}

static void update_config_roms(void)
{
	struct fw_card *card;
	u32 *config_rom;
	size_t length;

	list_for_each_entry (card, &card_list, link) {
		config_rom = generate_config_rom(card, &length);
		card->driver->set_config_rom(card, config_rom, length);
		length = generate_config_rom(card, tmp_config_rom);
		card->driver->set_config_rom(card, tmp_config_rom, length);
	}
}

@@ -211,11 +207,8 @@ static const char gap_count_table[] = {

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

	fw_card_get(card);
	scheduled = schedule_delayed_work(&card->work, delay);
	if (!scheduled)
	if (!schedule_delayed_work(&card->work, delay))
		fw_card_put(card);
}

@@ -435,7 +428,6 @@ EXPORT_SYMBOL(fw_card_initialize);
int fw_card_add(struct fw_card *card,
		u32 max_receive, u32 link_speed, u64 guid)
{
	u32 *config_rom;
	size_t length;
	int ret;

@@ -445,8 +437,8 @@ int fw_card_add(struct fw_card *card,

	mutex_lock(&card_mutex);

	config_rom = generate_config_rom(card, &length);
	ret = card->driver->enable(card, config_rom, length);
	length = generate_config_rom(card, tmp_config_rom);
	ret = card->driver->enable(card, tmp_config_rom, length);
	if (ret == 0)
		list_add_tail(&card->link, &card_list);

@@ -465,7 +457,8 @@ EXPORT_SYMBOL(fw_card_add);
 * shutdown still need to be provided by the card driver.
 */

static int dummy_enable(struct fw_card *card, u32 *config_rom, size_t length)
static int dummy_enable(struct fw_card *card,
			const __be32 *config_rom, size_t length)
{
	BUG();
	return -1;
@@ -478,7 +471,7 @@ static int dummy_update_phy_reg(struct fw_card *card, int address,
}

static int dummy_set_config_rom(struct fw_card *card,
				u32 *config_rom, size_t length)
				const __be32 *config_rom, size_t length)
{
	/*
	 * We take the card out of card_list before setting the dummy
+67 −46
Original line number Diff line number Diff line
@@ -130,9 +130,22 @@ struct iso_resource {
	struct iso_resource_event *e_alloc, *e_dealloc;
};

static void schedule_iso_resource(struct iso_resource *);
static void release_iso_resource(struct client *, struct client_resource *);

static void schedule_iso_resource(struct iso_resource *r, unsigned long delay)
{
	client_get(r->client);
	if (!schedule_delayed_work(&r->work, delay))
		client_put(r->client);
}

static void schedule_if_iso_resource(struct client_resource *resource)
{
	if (resource->release == release_iso_resource)
		schedule_iso_resource(container_of(resource,
					struct iso_resource, resource), 0);
}

/*
 * dequeue_event() just kfree()'s the event, so the event has to be
 * the first field in a struct XYZ_event.
@@ -166,7 +179,7 @@ struct iso_interrupt_event {

struct iso_resource_event {
	struct event event;
	struct fw_cdev_event_iso_resource resource;
	struct fw_cdev_event_iso_resource iso_resource;
};

static inline void __user *u64_to_uptr(__u64 value)
@@ -314,11 +327,8 @@ static void for_each_client(struct fw_device *device,

static int schedule_reallocations(int id, void *p, void *data)
{
	struct client_resource *r = p;
	schedule_if_iso_resource(p);

	if (r->release == release_iso_resource)
		schedule_iso_resource(container_of(r,
					struct iso_resource, resource));
	return 0;
}

@@ -414,9 +424,7 @@ static int add_client_resource(struct client *client,
				  &resource->handle);
	if (ret >= 0) {
		client_get(client);
		if (resource->release == release_iso_resource)
			schedule_iso_resource(container_of(resource,
						struct iso_resource, resource));
		schedule_if_iso_resource(resource);
	}
	spin_unlock_irqrestore(&client->lock, flags);

@@ -428,26 +436,26 @@ static int add_client_resource(struct client *client,

static int release_client_resource(struct client *client, u32 handle,
				   client_resource_release_fn_t release,
				   struct client_resource **resource)
				   struct client_resource **return_resource)
{
	struct client_resource *r;
	struct client_resource *resource;

	spin_lock_irq(&client->lock);
	if (client->in_shutdown)
		r = NULL;
		resource = NULL;
	else
		r = idr_find(&client->resource_idr, handle);
	if (r && r->release == release)
		resource = idr_find(&client->resource_idr, handle);
	if (resource && resource->release == release)
		idr_remove(&client->resource_idr, handle);
	spin_unlock_irq(&client->lock);

	if (!(r && r->release == release))
	if (!(resource && resource->release == release))
		return -EINVAL;

	if (resource)
		*resource = r;
	if (return_resource)
		*return_resource = resource;
	else
		r->release(client, r);
		resource->release(client, resource);

	client_put(client);

@@ -699,6 +707,7 @@ static int ioctl_send_response(struct client *client, void *buffer)
	struct fw_cdev_send_response *request = buffer;
	struct client_resource *resource;
	struct inbound_transaction_resource *r;
	int ret = 0;

	if (release_client_resource(client, request->handle,
				    release_request, &resource) < 0)
@@ -708,13 +717,17 @@ static int ioctl_send_response(struct client *client, void *buffer)
			 resource);
	if (request->length < r->length)
		r->length = request->length;
	if (copy_from_user(r->data, u64_to_uptr(request->data), r->length))
		return -EFAULT;

	if (copy_from_user(r->data, u64_to_uptr(request->data), r->length)) {
		ret = -EFAULT;
		goto out;
	}

	fw_send_response(client->device->card, r->request, request->rcode);
 out:
	kfree(r);

	return 0;
	return ret;
}

static int ioctl_initiate_bus_reset(struct client *client, void *buffer)
@@ -1028,8 +1041,7 @@ static void iso_resource_work(struct work_struct *work)
	/* Allow 1000ms grace period for other reallocations. */
	if (todo == ISO_RES_ALLOC &&
	    time_is_after_jiffies(client->device->card->reset_jiffies + HZ)) {
		if (schedule_delayed_work(&r->work, DIV_ROUND_UP(HZ, 3)))
			client_get(client);
		schedule_iso_resource(r, DIV_ROUND_UP(HZ, 3));
		skip = true;
	} else {
		/* We could be called twice within the same generation. */
@@ -1097,12 +1109,12 @@ static void iso_resource_work(struct work_struct *work)
		e = r->e_dealloc;
		r->e_dealloc = NULL;
	}
	e->resource.handle	= r->resource.handle;
	e->resource.channel	= channel;
	e->resource.bandwidth	= bandwidth;
	e->iso_resource.handle    = r->resource.handle;
	e->iso_resource.channel   = channel;
	e->iso_resource.bandwidth = bandwidth;

	queue_event(client, &e->event,
		    &e->resource, sizeof(e->resource), NULL, 0);
		    &e->iso_resource, sizeof(e->iso_resource), NULL, 0);

	if (free) {
		cancel_delayed_work(&r->work);
@@ -1114,13 +1126,6 @@ static void iso_resource_work(struct work_struct *work)
	client_put(client);
}

static void schedule_iso_resource(struct iso_resource *r)
{
	client_get(r->client);
	if (!schedule_delayed_work(&r->work, 0))
		client_put(r->client);
}

static void release_iso_resource(struct client *client,
				 struct client_resource *resource)
{
@@ -1129,7 +1134,7 @@ static void release_iso_resource(struct client *client,

	spin_lock_irq(&client->lock);
	r->todo = ISO_RES_DEALLOC;
	schedule_iso_resource(r);
	schedule_iso_resource(r, 0);
	spin_unlock_irq(&client->lock);
}

@@ -1162,10 +1167,10 @@ static int init_iso_resource(struct client *client,
	r->e_alloc	= e1;
	r->e_dealloc	= e2;

	e1->resource.closure	= request->closure;
	e1->resource.type	= FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED;
	e2->resource.closure	= request->closure;
	e2->resource.type	= FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED;
	e1->iso_resource.closure = request->closure;
	e1->iso_resource.type    = FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED;
	e2->iso_resource.closure = request->closure;
	e2->iso_resource.type    = FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED;

	if (todo == ISO_RES_ALLOC) {
		r->resource.release = release_iso_resource;
@@ -1175,7 +1180,7 @@ static int init_iso_resource(struct client *client,
	} else {
		r->resource.release = NULL;
		r->resource.handle = -1;
		schedule_iso_resource(r);
		schedule_iso_resource(r, 0);
	}
	request->handle = r->resource.handle;

@@ -1295,7 +1300,23 @@ static int (* const ioctl_handlers[])(struct client *client, void *buffer) = {
static int dispatch_ioctl(struct client *client,
			  unsigned int cmd, void __user *arg)
{
	char buffer[256];
	char buffer[sizeof(union {
		struct fw_cdev_get_info			_00;
		struct fw_cdev_send_request		_01;
		struct fw_cdev_allocate			_02;
		struct fw_cdev_deallocate		_03;
		struct fw_cdev_send_response		_04;
		struct fw_cdev_initiate_bus_reset	_05;
		struct fw_cdev_add_descriptor		_06;
		struct fw_cdev_remove_descriptor	_07;
		struct fw_cdev_create_iso_context	_08;
		struct fw_cdev_queue_iso		_09;
		struct fw_cdev_start_iso		_0a;
		struct fw_cdev_stop_iso			_0b;
		struct fw_cdev_get_cycle_timer		_0c;
		struct fw_cdev_allocate_iso_resource	_0d;
		struct fw_cdev_send_stream_packet	_13;
	})];
	int ret;

	if (_IOC_TYPE(cmd) != '#' ||
@@ -1390,10 +1411,10 @@ static int fw_device_op_mmap(struct file *file, struct vm_area_struct *vma)

static int shutdown_resource(int id, void *p, void *data)
{
	struct client_resource *r = p;
	struct client_resource *resource = p;
	struct client *client = data;

	r->release(client, r);
	resource->release(client, resource);
	client_put(client);

	return 0;
@@ -1402,7 +1423,7 @@ static int shutdown_resource(int id, void *p, void *data)
static int fw_device_op_release(struct inode *inode, struct file *file)
{
	struct client *client = file->private_data;
	struct event *e, *next_e;
	struct event *event, *next_event;

	mutex_lock(&client->device->client_list_mutex);
	list_del(&client->link);
@@ -1423,8 +1444,8 @@ static int fw_device_op_release(struct inode *inode, struct file *file)
	idr_remove_all(&client->resource_idr);
	idr_destroy(&client->resource_idr);

	list_for_each_entry_safe(e, next_e, &client->event_list, link)
		kfree(e);
	list_for_each_entry_safe(event, next_event, &client->event_list, link)
		kfree(event);

	client_put(client);

+10 −7
Original line number Diff line number Diff line
@@ -28,9 +28,9 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/string.h>

#include <asm/atomic.h>
#include <asm/byteorder.h>
#include <asm/system.h>

#include "core.h"
@@ -510,13 +510,16 @@ static void update_tree(struct fw_card *card, struct fw_node *root)
static void update_topology_map(struct fw_card *card,
				u32 *self_ids, int self_id_count)
{
	int node_count;
	int node_count = (card->root_node->node_id & 0x3f) + 1;
	__be32 *map = card->topology_map;

	*map++ = cpu_to_be32((self_id_count + 2) << 16);
	*map++ = cpu_to_be32(be32_to_cpu(card->topology_map[1]) + 1);
	*map++ = cpu_to_be32((node_count << 16) | self_id_count);

	while (self_id_count--)
		*map++ = cpu_to_be32p(self_ids++);

	card->topology_map[1]++;
	node_count = (card->root_node->node_id & 0x3f) + 1;
	card->topology_map[2] = (node_count << 16) | self_id_count;
	card->topology_map[0] = (self_id_count + 2) << 16;
	memcpy(&card->topology_map[3], self_ids, self_id_count * 4);
	fw_compute_block_crc(card->topology_map);
}

+8 −11
Original line number Diff line number Diff line
@@ -218,12 +218,15 @@ static void fw_fill_request(struct fw_packet *packet, int tcode, int tlabel,
		packet->header_length = 16;
		packet->payload_length = 0;
		break;

	default:
		WARN(1, KERN_ERR "wrong tcode %d", tcode);
	}
 common:
	packet->speed = speed;
	packet->generation = generation;
	packet->ack = 0;
	packet->payload_bus = 0;
	packet->payload_mapped = false;
}

/**
@@ -595,11 +598,10 @@ void fw_fill_response(struct fw_packet *response, u32 *request_header,
		break;

	default:
		BUG();
		return;
		WARN(1, KERN_ERR "wrong tcode %d", tcode);
	}

	response->payload_bus = 0;
	response->payload_mapped = false;
}
EXPORT_SYMBOL(fw_fill_response);

@@ -810,8 +812,7 @@ static void handle_topology_map(struct fw_card *card, struct fw_request *request
		int speed, unsigned long long offset,
		void *payload, size_t length, void *callback_data)
{
	int i, start, end;
	__be32 *map;
	int start;

	if (!TCODE_IS_READ_REQUEST(tcode)) {
		fw_send_response(card, request, RCODE_TYPE_ERROR);
@@ -824,11 +825,7 @@ static void handle_topology_map(struct fw_card *card, struct fw_request *request
	}

	start = (offset - topology_map_region.start) / 4;
	end = start + length / 4;
	map = payload;

	for (i = 0; i < length / 4; i++)
		map[i] = cpu_to_be32(card->topology_map[start + i]);
	memcpy(payload, &card->topology_map[start], length);

	fw_send_response(card, request, RCODE_COMPLETE);
}
+5 −4
Original line number Diff line number Diff line
@@ -40,7 +40,8 @@ struct fw_card_driver {
	 * enable the PHY or set the link_on bit and initiate a bus
	 * reset.
	 */
	int (*enable)(struct fw_card *card, u32 *config_rom, size_t length);
	int (*enable)(struct fw_card *card,
		      const __be32 *config_rom, size_t length);

	int (*update_phy_reg)(struct fw_card *card, int address,
			      int clear_bits, int set_bits);
@@ -48,10 +49,10 @@ struct fw_card_driver {
	/*
	 * Update the config rom for an enabled card.  This function
	 * should change the config rom that is presented on the bus
	 * an initiate a bus reset.
	 * and initiate a bus reset.
	 */
	int (*set_config_rom)(struct fw_card *card,
			      u32 *config_rom, size_t length);
			      const __be32 *config_rom, size_t length);

	void (*send_request)(struct fw_card *card, struct fw_packet *packet);
	void (*send_response)(struct fw_card *card, struct fw_packet *packet);
@@ -93,7 +94,7 @@ int fw_card_add(struct fw_card *card,
		u32 max_receive, u32 link_speed, u64 guid);
void fw_core_remove_card(struct fw_card *card);
int fw_core_initiate_bus_reset(struct fw_card *card, int short_reset);
int fw_compute_block_crc(u32 *block);
int fw_compute_block_crc(__be32 *block);
void fw_schedule_bm_work(struct fw_card *card, unsigned long delay);

static inline struct fw_card *fw_card_get(struct fw_card *card)
Loading