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

Commit dcb4a1f0 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:
  firewire: sbp2: parallelize login, reconnect, logout
  firewire: sbp2: octlet AT payloads can be stack-allocated
  firewire: sbp2: omit Scsi_Host lock from queuecommand
  firewire: core: use non-reentrant workqueue with rescuer
  firewire: optimize iso queueing by setting wake only after the last packet
  firewire: octlet AT payloads can be stack-allocated
  firewire: ohci: optimize find_branch_descriptor()
  firewire: ohci: avoid separate DMA mapping for small AT payloads
  firewire: ohci: do not start DMA contexts before link is enabled
parents c21fd1a8 105e53f8
Loading
Loading
Loading
Loading
+16 −11
Original line number Diff line number Diff line
@@ -228,7 +228,7 @@ void fw_schedule_bus_reset(struct fw_card *card, bool delayed, bool short_reset)

	/* Use an arbitrary short delay to combine multiple reset requests. */
	fw_card_get(card);
	if (!schedule_delayed_work(&card->br_work,
	if (!queue_delayed_work(fw_workqueue, &card->br_work,
				delayed ? DIV_ROUND_UP(HZ, 100) : 0))
		fw_card_put(card);
}
@@ -241,7 +241,7 @@ static void br_work(struct work_struct *work)
	/* Delay for 2s after last reset per IEEE 1394 clause 8.2.1. */
	if (card->reset_jiffies != 0 &&
	    time_before64(get_jiffies_64(), card->reset_jiffies + 2 * HZ)) {
		if (!schedule_delayed_work(&card->br_work, 2 * HZ))
		if (!queue_delayed_work(fw_workqueue, &card->br_work, 2 * HZ))
			fw_card_put(card);
		return;
	}
@@ -258,8 +258,7 @@ static void allocate_broadcast_channel(struct fw_card *card, int generation)

	if (!card->broadcast_channel_allocated) {
		fw_iso_resource_manage(card, generation, 1ULL << 31,
				       &channel, &bandwidth, true,
				       card->bm_transaction_data);
				       &channel, &bandwidth, true);
		if (channel != 31) {
			fw_notify("failed to allocate broadcast channel\n");
			return;
@@ -294,6 +293,7 @@ static void bm_work(struct work_struct *work)
	bool root_device_is_cmc;
	bool irm_is_1394_1995_only;
	bool keep_this_irm;
	__be32 transaction_data[2];

	spin_lock_irq(&card->lock);

@@ -355,21 +355,21 @@ static void bm_work(struct work_struct *work)
			goto pick_me;
		}

		card->bm_transaction_data[0] = cpu_to_be32(0x3f);
		card->bm_transaction_data[1] = cpu_to_be32(local_id);
		transaction_data[0] = cpu_to_be32(0x3f);
		transaction_data[1] = cpu_to_be32(local_id);

		spin_unlock_irq(&card->lock);

		rcode = fw_run_transaction(card, TCODE_LOCK_COMPARE_SWAP,
				irm_id, generation, SCODE_100,
				CSR_REGISTER_BASE + CSR_BUS_MANAGER_ID,
				card->bm_transaction_data, 8);
				transaction_data, 8);

		if (rcode == RCODE_GENERATION)
			/* Another bus reset, BM work has been rescheduled. */
			goto out;

		bm_id = be32_to_cpu(card->bm_transaction_data[0]);
		bm_id = be32_to_cpu(transaction_data[0]);

		spin_lock_irq(&card->lock);
		if (rcode == RCODE_COMPLETE && generation == card->generation)
@@ -490,11 +490,11 @@ static void bm_work(struct work_struct *work)
		/*
		 * Make sure that the cycle master sends cycle start packets.
		 */
		card->bm_transaction_data[0] = cpu_to_be32(CSR_STATE_BIT_CMSTR);
		transaction_data[0] = cpu_to_be32(CSR_STATE_BIT_CMSTR);
		rcode = fw_run_transaction(card, TCODE_WRITE_QUADLET_REQUEST,
				root_id, generation, SCODE_100,
				CSR_REGISTER_BASE + CSR_STATE_SET,
				card->bm_transaction_data, 4);
				transaction_data, 4);
		if (rcode == RCODE_GENERATION)
			goto out;
	}
@@ -630,6 +630,10 @@ static int dummy_queue_iso(struct fw_iso_context *ctx, struct fw_iso_packet *p,
	return -ENODEV;
}

static void dummy_flush_queue_iso(struct fw_iso_context *ctx)
{
}

static const struct fw_card_driver dummy_driver_template = {
	.read_phy_reg		= dummy_read_phy_reg,
	.update_phy_reg		= dummy_update_phy_reg,
@@ -641,6 +645,7 @@ static const struct fw_card_driver dummy_driver_template = {
	.start_iso		= dummy_start_iso,
	.set_iso_channels	= dummy_set_iso_channels,
	.queue_iso		= dummy_queue_iso,
	.flush_queue_iso	= dummy_flush_queue_iso,
};

void fw_card_release(struct kref *kref)
+3 −4
Original line number Diff line number Diff line
@@ -141,7 +141,6 @@ struct iso_resource {
	int generation;
	u64 channels;
	s32 bandwidth;
	__be32 transaction_data[2];
	struct iso_resource_event *e_alloc, *e_dealloc;
};

@@ -150,7 +149,7 @@ 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))
	if (!queue_delayed_work(fw_workqueue, &r->work, delay))
		client_put(r->client);
}

@@ -1108,6 +1107,7 @@ static int ioctl_queue_iso(struct client *client, union ioctl_arg *arg)
		payload += u.packet.payload_length;
		count++;
	}
	fw_iso_context_queue_flush(ctx);

	a->size    -= uptr_to_u64(p) - a->packets;
	a->packets  = uptr_to_u64(p);
@@ -1229,8 +1229,7 @@ static void iso_resource_work(struct work_struct *work)
			r->channels, &channel, &bandwidth,
			todo == ISO_RES_ALLOC ||
			todo == ISO_RES_REALLOC ||
			todo == ISO_RES_ALLOC_ONCE,
			r->transaction_data);
			todo == ISO_RES_ALLOC_ONCE);
	/*
	 * Is this generation outdated already?  As long as this resource sticks
	 * in the idr, it will be scheduled again for a newer generation or at
+20 −11
Original line number Diff line number Diff line
@@ -725,6 +725,15 @@ struct fw_device *fw_device_get_by_devt(dev_t devt)
	return device;
}

struct workqueue_struct *fw_workqueue;
EXPORT_SYMBOL(fw_workqueue);

static void fw_schedule_device_work(struct fw_device *device,
				    unsigned long delay)
{
	queue_delayed_work(fw_workqueue, &device->work, delay);
}

/*
 * These defines control the retry behavior for reading the config
 * rom.  It shouldn't be necessary to tweak these; if the device
@@ -750,7 +759,7 @@ static void fw_device_shutdown(struct work_struct *work)
	if (time_before64(get_jiffies_64(),
			  device->card->reset_jiffies + SHUTDOWN_DELAY)
	    && !list_empty(&device->card->link)) {
		schedule_delayed_work(&device->work, SHUTDOWN_DELAY);
		fw_schedule_device_work(device, SHUTDOWN_DELAY);
		return;
	}

@@ -862,7 +871,7 @@ static int lookup_existing_device(struct device *dev, void *data)
		fw_notify("rediscovered device %s\n", dev_name(dev));

		PREPARE_DELAYED_WORK(&old->work, fw_device_update);
		schedule_delayed_work(&old->work, 0);
		fw_schedule_device_work(old, 0);

		if (current_node == card->root_node)
			fw_schedule_bm_work(card, 0);
@@ -953,7 +962,7 @@ static void fw_device_init(struct work_struct *work)
		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);
			fw_schedule_device_work(device, RETRY_DELAY);
		} else {
			if (device->node->link_on)
				fw_notify("giving up on config rom for node id %x\n",
@@ -1019,7 +1028,7 @@ static void fw_device_init(struct work_struct *work)
			   FW_DEVICE_INITIALIZING,
			   FW_DEVICE_RUNNING) == FW_DEVICE_GONE) {
		PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown);
		schedule_delayed_work(&device->work, SHUTDOWN_DELAY);
		fw_schedule_device_work(device, SHUTDOWN_DELAY);
	} else {
		if (device->config_rom_retries)
			fw_notify("created device %s: GUID %08x%08x, S%d00, "
@@ -1098,7 +1107,7 @@ static void fw_device_refresh(struct work_struct *work)
		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);
			fw_schedule_device_work(device, RETRY_DELAY / 2);

			return;
		}
@@ -1131,7 +1140,7 @@ static void fw_device_refresh(struct work_struct *work)
		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);
			fw_schedule_device_work(device, RETRY_DELAY);

			return;
		}
@@ -1158,7 +1167,7 @@ static void fw_device_refresh(struct work_struct *work)
 gone:
	atomic_set(&device->state, FW_DEVICE_GONE);
	PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown);
	schedule_delayed_work(&device->work, SHUTDOWN_DELAY);
	fw_schedule_device_work(device, SHUTDOWN_DELAY);
 out:
	if (node_id == card->root_node->node_id)
		fw_schedule_bm_work(card, 0);
@@ -1214,7 +1223,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
		 * first config rom scan half a second after bus reset.
		 */
		INIT_DELAYED_WORK(&device->work, fw_device_init);
		schedule_delayed_work(&device->work, INITIAL_DELAY);
		fw_schedule_device_work(device, INITIAL_DELAY);
		break;

	case FW_NODE_INITIATED_RESET:
@@ -1230,7 +1239,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
			    FW_DEVICE_RUNNING,
			    FW_DEVICE_INITIALIZING) == FW_DEVICE_RUNNING) {
			PREPARE_DELAYED_WORK(&device->work, fw_device_refresh);
			schedule_delayed_work(&device->work,
			fw_schedule_device_work(device,
				device->is_local ? 0 : INITIAL_DELAY);
		}
		break;
@@ -1245,7 +1254,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
		device->generation = card->generation;
		if (atomic_read(&device->state) == FW_DEVICE_RUNNING) {
			PREPARE_DELAYED_WORK(&device->work, fw_device_update);
			schedule_delayed_work(&device->work, 0);
			fw_schedule_device_work(device, 0);
		}
		break;

@@ -1270,7 +1279,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
		if (atomic_xchg(&device->state,
				FW_DEVICE_GONE) == FW_DEVICE_RUNNING) {
			PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown);
			schedule_delayed_work(&device->work,
			fw_schedule_device_work(device,
				list_empty(&card->link) ? 0 : SHUTDOWN_DELAY);
		}
		break;
+17 −10
Original line number Diff line number Diff line
@@ -185,6 +185,12 @@ int fw_iso_context_queue(struct fw_iso_context *ctx,
}
EXPORT_SYMBOL(fw_iso_context_queue);

void fw_iso_context_queue_flush(struct fw_iso_context *ctx)
{
	ctx->card->driver->flush_queue_iso(ctx);
}
EXPORT_SYMBOL(fw_iso_context_queue_flush);

int fw_iso_context_stop(struct fw_iso_context *ctx)
{
	return ctx->card->driver->stop_iso(ctx);
@@ -196,9 +202,10 @@ EXPORT_SYMBOL(fw_iso_context_stop);
 */

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

	/*
	 * On a 1394a IRM with low contention, try < 1 is enough.
@@ -233,9 +240,10 @@ static int manage_bandwidth(struct fw_card *card, int irm_id, int generation,
}

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

	old = all = allocate ? cpu_to_be32(~0) : 0;
@@ -284,7 +292,7 @@ static int manage_channel(struct fw_card *card, int irm_id, int generation,
}

static void deallocate_channel(struct fw_card *card, int irm_id,
			       int generation, int channel, __be32 buffer[2])
			       int generation, int channel)
{
	u32 mask;
	u64 offset;
@@ -293,7 +301,7 @@ static void deallocate_channel(struct fw_card *card, int irm_id,
	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, buffer);
	manage_channel(card, irm_id, generation, mask, offset, false);
}

/**
@@ -322,7 +330,7 @@ static void deallocate_channel(struct fw_card *card, int irm_id,
 */
void fw_iso_resource_manage(struct fw_card *card, int generation,
			    u64 channels_mask, int *channel, int *bandwidth,
			    bool allocate, __be32 buffer[2])
			    bool allocate)
{
	u32 channels_hi = channels_mask;	/* channels 31...0 */
	u32 channels_lo = channels_mask >> 32;	/* channels 63...32 */
@@ -335,11 +343,11 @@ void fw_iso_resource_manage(struct fw_card *card, int generation,
	if (channels_hi)
		c = manage_channel(card, irm_id, generation, channels_hi,
				CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_HI,
				allocate, buffer);
				allocate);
	if (channels_lo && c < 0) {
		c = manage_channel(card, irm_id, generation, channels_lo,
				CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_LO,
				allocate, buffer);
				allocate);
		if (c >= 0)
			c += 32;
	}
@@ -351,14 +359,13 @@ void fw_iso_resource_manage(struct fw_card *card, int generation,
	if (*bandwidth == 0)
		return;

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

	if (allocate && ret < 0) {
		if (c >= 0)
			deallocate_channel(card, irm_id, generation, c, buffer);
			deallocate_channel(card, irm_id, generation, c);
		*channel = ret;
	}
}
+15 −4
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/types.h>
#include <linux/workqueue.h>

#include <asm/byteorder.h>

@@ -326,8 +327,8 @@ static int allocate_tlabel(struct fw_card *card)
 * It will contain tag, channel, and sy data instead of a node ID then.
 *
 * The payload buffer at @data is going to be DMA-mapped except in case of
 * quadlet-sized payload or of local (loopback) requests.  Hence make sure that
 * the buffer complies with the restrictions for DMA-mapped memory.  The
 * @length <= 8 or of local (loopback) requests.  Hence make sure that the
 * buffer complies with the restrictions of the streaming DMA mapping API.
 * @payload must not be freed before the @callback is called.
 *
 * In case of request types without payload, @data is NULL and @length is 0.
@@ -411,7 +412,8 @@ static void transaction_callback(struct fw_card *card, int rcode,
 *
 * Returns the RCODE.  See fw_send_request() for parameter documentation.
 * Unlike fw_send_request(), @data points to the payload of the request or/and
 * to the payload of the response.
 * to the payload of the response.  DMA mapping restrictions apply to outbound
 * request payloads of >= 8 bytes but not to inbound response payloads.
 */
int fw_run_transaction(struct fw_card *card, int tcode, int destination_id,
		       int generation, int speed, unsigned long long offset,
@@ -1212,13 +1214,21 @@ static int __init fw_core_init(void)
{
	int ret;

	fw_workqueue = alloc_workqueue("firewire",
				       WQ_NON_REENTRANT | WQ_MEM_RECLAIM, 0);
	if (!fw_workqueue)
		return -ENOMEM;

	ret = bus_register(&fw_bus_type);
	if (ret < 0)
	if (ret < 0) {
		destroy_workqueue(fw_workqueue);
		return ret;
	}

	fw_cdev_major = register_chrdev(0, "firewire", &fw_device_ops);
	if (fw_cdev_major < 0) {
		bus_unregister(&fw_bus_type);
		destroy_workqueue(fw_workqueue);
		return fw_cdev_major;
	}

@@ -1234,6 +1244,7 @@ static void __exit fw_core_cleanup(void)
{
	unregister_chrdev(fw_cdev_major, "firewire");
	bus_unregister(&fw_bus_type);
	destroy_workqueue(fw_workqueue);
	idr_destroy(&fw_device_idr);
}

Loading