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

Commit 2d530569 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: (82 commits)
  firewire: core: add forgotten dummy driver methods, remove unused ones
  firewire: add isochronous multichannel reception
  firewire: core: small clarifications in core-cdev
  firewire: core: remove unused code
  firewire: ohci: release channel in error path
  firewire: ohci: use memory barriers to order descriptor updates
  tools/firewire: nosy-dump: increment program version
  tools/firewire: nosy-dump: remove unused code
  tools/firewire: nosy-dump: use linux/firewire-constants.h
  tools/firewire: nosy-dump: break up a deeply nested function
  tools/firewire: nosy-dump: make some symbols static or const
  tools/firewire: nosy-dump: change to kernel coding style
  tools/firewire: nosy-dump: work around segfault in decode_fcp
  tools/firewire: nosy-dump: fix it on x86-64
  tools/firewire: add userspace front-end of nosy
  firewire: nosy: note ioctls in ioctl-number.txt
  firewire: nosy: use generic printk macros
  firewire: nosy: endianess fixes and annotations
  firewire: nosy: annotate __user pointers and __iomem pointers
  firewire: nosy: fix device shutdown with active client
  ...
parents 9e50ab91 e78483c5
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -79,6 +79,7 @@ Code Seq#(hex) Include File Comments
0x22	all	scsi/sg.h
'#'	00-3F	IEEE 1394 Subsystem	Block for the entire subsystem
'$'	00-0F	linux/perf_counter.h, linux/perf_event.h
'&'	00-07	drivers/firewire/nosy-user.h
'1'	00-1F	<linux/timepps.h>	PPS kit from Ulrich Windl
					<ftp://ftp.de.kernel.org/pub/linux/daemons/ntp/PPS/>
'2'	01-04	linux/i2o.h
+1 −0
Original line number Diff line number Diff line
@@ -2324,6 +2324,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6.git
S:	Maintained
F:	drivers/firewire/
F:	include/linux/firewire*.h
F:	tools/firewire/

FIRMWARE LOADER (request_firmware)
S:	Orphan
+24 −0
Original line number Diff line number Diff line
@@ -66,4 +66,28 @@ config FIREWIRE_NET

source "drivers/ieee1394/Kconfig"

config FIREWIRE_NOSY
	tristate "Nosy - a FireWire traffic sniffer for PCILynx cards"
	depends on PCI
	help
	  Nosy is an IEEE 1394 packet sniffer that is used for protocol
	  analysis and in development of IEEE 1394 drivers, applications,
	  or firmwares.

	  This driver lets you use a Texas Instruments PCILynx 1394 to PCI
	  link layer controller TSB12LV21/A/B as a low-budget bus analyzer.
	  PCILynx is a nowadays very rare IEEE 1394 controller which is
	  not OHCI 1394 compliant.

	  The following cards are known to be based on PCILynx or PCILynx-2:
	  IOI IOI-1394TT (PCI card), Unibrain Fireboard 400 PCI Lynx-2
	  (PCI card), Newer Technology FireWire 2 Go (CardBus card),
	  Apple Power Mac G3 blue & white (onboard controller).

	  To compile this driver as a module, say M here:  The module will be
	  called nosy.  Source code of a userspace interface to nosy, called
	  nosy-dump, can be found in tools/firewire/ of the kernel sources.

	  If unsure, say N.

endmenu
+1 −0
Original line number Diff line number Diff line
@@ -12,3 +12,4 @@ obj-$(CONFIG_FIREWIRE) += firewire-core.o
obj-$(CONFIG_FIREWIRE_OHCI) += firewire-ohci.o
obj-$(CONFIG_FIREWIRE_SBP2) += firewire-sbp2.o
obj-$(CONFIG_FIREWIRE_NET)  += firewire-net.o
obj-$(CONFIG_FIREWIRE_NOSY) += nosy.o
+152 −66
Original line number Diff line number Diff line
@@ -204,18 +204,63 @@ void fw_core_remove_descriptor(struct fw_descriptor *desc)
}
EXPORT_SYMBOL(fw_core_remove_descriptor);

static int reset_bus(struct fw_card *card, bool short_reset)
{
	int reg = short_reset ? 5 : 1;
	int bit = short_reset ? PHY_BUS_SHORT_RESET : PHY_BUS_RESET;

	return card->driver->update_phy_reg(card, reg, 0, bit);
}

void fw_schedule_bus_reset(struct fw_card *card, bool delayed, bool short_reset)
{
	/* We don't try hard to sort out requests of long vs. short resets. */
	card->br_short = short_reset;

	/* Use an arbitrary short delay to combine multiple reset requests. */
	fw_card_get(card);
	if (!schedule_delayed_work(&card->br_work,
				   delayed ? DIV_ROUND_UP(HZ, 100) : 0))
		fw_card_put(card);
}
EXPORT_SYMBOL(fw_schedule_bus_reset);

static void br_work(struct work_struct *work)
{
	struct fw_card *card = container_of(work, struct fw_card, br_work.work);

	/* Delay for 2s after last reset per IEEE 1394 clause 8.2.1. */
	if (card->reset_jiffies != 0 &&
	    time_is_after_jiffies(card->reset_jiffies + 2 * HZ)) {
		if (!schedule_delayed_work(&card->br_work, 2 * HZ))
			fw_card_put(card);
		return;
	}

	fw_send_phy_config(card, FW_PHY_CONFIG_NO_NODE_ID, card->generation,
			   FW_PHY_CONFIG_CURRENT_GAP_COUNT);
	reset_bus(card, card->br_short);
	fw_card_put(card);
}

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, card->bm_transaction_data);
	if (channel == 31) {
	if (!card->broadcast_channel_allocated) {
		fw_iso_resource_manage(card, generation, 1ULL << 31,
				       &channel, &bandwidth, true,
				       card->bm_transaction_data);
		if (channel != 31) {
			fw_notify("failed to allocate broadcast channel\n");
			return;
		}
		card->broadcast_channel_allocated = true;
	}

	device_for_each_child(card->device, (void *)(long)generation,
			      fw_device_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
@@ -224,27 +269,26 @@ static const char gap_count_table[] = {
void fw_schedule_bm_work(struct fw_card *card, unsigned long delay)
{
	fw_card_get(card);
	if (!schedule_delayed_work(&card->work, delay))
	if (!schedule_delayed_work(&card->bm_work, delay))
		fw_card_put(card);
}

static void fw_card_bm_work(struct work_struct *work)
static void bm_work(struct work_struct *work)
{
	struct fw_card *card = container_of(work, struct fw_card, work.work);
	struct fw_card *card = container_of(work, struct fw_card, bm_work.work);
	struct fw_device *root_device, *irm_device;
	struct fw_node *root_node;
	unsigned long flags;
	int root_id, new_root_id, irm_id, local_id;
	int root_id, new_root_id, irm_id, bm_id, local_id;
	int gap_count, generation, grace, rcode;
	bool do_reset = false;
	bool root_device_is_running;
	bool root_device_is_cmc;
	bool irm_is_1394_1995_only;

	spin_lock_irqsave(&card->lock, flags);
	spin_lock_irq(&card->lock);

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

@@ -267,7 +311,8 @@ static void fw_card_bm_work(struct work_struct *work)

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

	if (is_next_generation(generation, card->bm_generation) ||
	if ((is_next_generation(generation, card->bm_generation) &&
	     !card->bm_abdicate) ||
	    (card->bm_generation != generation && grace)) {
		/*
		 * This first step is to figure out who is IRM and
@@ -298,21 +343,26 @@ static void fw_card_bm_work(struct work_struct *work)
		card->bm_transaction_data[0] = cpu_to_be32(0x3f);
		card->bm_transaction_data[1] = cpu_to_be32(local_id);

		spin_unlock_irqrestore(&card->lock, flags);
		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,
				sizeof(card->bm_transaction_data));
				card->bm_transaction_data, 8);

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

		if (rcode == RCODE_COMPLETE &&
		    card->bm_transaction_data[0] != cpu_to_be32(0x3f)) {
		bm_id = be32_to_cpu(card->bm_transaction_data[0]);

		spin_lock_irq(&card->lock);
		if (rcode == RCODE_COMPLETE && generation == card->generation)
			card->bm_node_id =
			    bm_id == 0x3f ? local_id : 0xffc0 | bm_id;
		spin_unlock_irq(&card->lock);

		if (rcode == RCODE_COMPLETE && bm_id != 0x3f) {
			/* Somebody else is BM.  Only act as IRM. */
			if (local_id == irm_id)
				allocate_broadcast_channel(card, generation);
@@ -320,7 +370,17 @@ static void fw_card_bm_work(struct work_struct *work)
			goto out;
		}

		spin_lock_irqsave(&card->lock, flags);
		if (rcode == RCODE_SEND_ERROR) {
			/*
			 * We have been unable to send the lock request due to
			 * some local problem.  Let's try again later and hope
			 * that the problem has gone away by then.
			 */
			fw_schedule_bm_work(card, DIV_ROUND_UP(HZ, 8));
			goto out;
		}

		spin_lock_irq(&card->lock);

		if (rcode != RCODE_COMPLETE) {
			/*
@@ -339,7 +399,7 @@ static void fw_card_bm_work(struct work_struct *work)
		 * 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);
		spin_unlock_irq(&card->lock);
		fw_schedule_bm_work(card, DIV_ROUND_UP(HZ, 8));
		goto out;
	}
@@ -362,14 +422,12 @@ static void fw_card_bm_work(struct work_struct *work)
		 * If we haven't probed this device yet, bail out now
		 * and let's try again once that's done.
		 */
		spin_unlock_irqrestore(&card->lock, flags);
		spin_unlock_irq(&card->lock);
		goto out;
	} else if (root_device_is_cmc) {
		/*
		 * FIXME: I suppose we should set the cmstr bit in the
		 * STATE_CLEAR register of this node, as described in
		 * 1394-1995, 8.4.2.6.  Also, send out a force root
		 * packet for this node.
		 * We will send out a force root packet for this
		 * node as part of the gap count optimization.
		 */
		new_root_id = root_id;
	} else {
@@ -402,18 +460,32 @@ static void fw_card_bm_work(struct work_struct *work)
	    (card->gap_count != gap_count || new_root_id != root_id))
		do_reset = true;

	spin_unlock_irqrestore(&card->lock, flags);
	spin_unlock_irq(&card->lock);

	if (do_reset) {
		fw_notify("phy config: card %d, new root=%x, gap_count=%d\n",
			  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);
		reset_bus(card, true);
		/* Will allocate broadcast channel after the reset. */
	} else {
		goto out;
	}

	if (root_device_is_cmc) {
		/*
		 * Make sure that the cycle master sends cycle start packets.
		 */
		card->bm_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);
		if (rcode == RCODE_GENERATION)
			goto out;
	}

	if (local_id == irm_id)
		allocate_broadcast_channel(card, generation);
	}

 out:
	fw_node_put(root_node);
@@ -432,17 +504,23 @@ void fw_card_initialize(struct fw_card *card,
	card->device = device;
	card->current_tlabel = 0;
	card->tlabel_mask = 0;
	card->split_timeout_hi = 0;
	card->split_timeout_lo = 800 << 19;
	card->split_timeout_cycles = 800;
	card->split_timeout_jiffies = DIV_ROUND_UP(HZ, 10);
	card->color = 0;
	card->broadcast_channel = BROADCAST_CHANNEL_INITIAL;

	kref_init(&card->kref);
	init_completion(&card->done);
	INIT_LIST_HEAD(&card->transaction_list);
	INIT_LIST_HEAD(&card->phy_receiver_list);
	spin_lock_init(&card->lock);

	card->local_node = NULL;

	INIT_DELAYED_WORK(&card->work, fw_card_bm_work);
	INIT_DELAYED_WORK(&card->br_work, br_work);
	INIT_DELAYED_WORK(&card->bm_work, bm_work);
}
EXPORT_SYMBOL(fw_card_initialize);

@@ -468,20 +546,22 @@ int fw_card_add(struct fw_card *card,
}
EXPORT_SYMBOL(fw_card_add);


/*
 * The next few functions implement a dummy driver that is used once a card
 * driver shuts down an fw_card.  This allows the driver to cleanly unload,
 * as all IO to the card will be handled (and failed) by the dummy driver
 * instead of calling into the module.  Only functions for iso context
 * shutdown still need to be provided by the card driver.
 *
 * .read/write_csr() should never be called anymore after the dummy driver
 * was bound since they are only used within request handler context.
 * .set_config_rom() is never called since the card is taken out of card_list
 * before switching to the dummy driver.
 */

static int dummy_enable(struct fw_card *card,
			const __be32 *config_rom, size_t length)
static int dummy_read_phy_reg(struct fw_card *card, int address)
{
	BUG();
	return -1;
	return -ENODEV;
}

static int dummy_update_phy_reg(struct fw_card *card, int address,
@@ -490,25 +570,14 @@ static int dummy_update_phy_reg(struct fw_card *card, int address,
	return -ENODEV;
}

static int dummy_set_config_rom(struct fw_card *card,
				const __be32 *config_rom, size_t length)
{
	/*
	 * We take the card out of card_list before setting the dummy
	 * driver, so this should never get called.
	 */
	BUG();
	return -1;
}

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

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

static int dummy_cancel_packet(struct fw_card *card, struct fw_packet *packet)
@@ -522,14 +591,40 @@ static int dummy_enable_phys_dma(struct fw_card *card,
	return -ENODEV;
}

static struct fw_iso_context *dummy_allocate_iso_context(struct fw_card *card,
				int type, int channel, size_t header_size)
{
	return ERR_PTR(-ENODEV);
}

static int dummy_start_iso(struct fw_iso_context *ctx,
			   s32 cycle, u32 sync, u32 tags)
{
	return -ENODEV;
}

static int dummy_set_iso_channels(struct fw_iso_context *ctx, u64 *channels)
{
	return -ENODEV;
}

static int dummy_queue_iso(struct fw_iso_context *ctx, struct fw_iso_packet *p,
			   struct fw_iso_buffer *buffer, unsigned long payload)
{
	return -ENODEV;
}

static const struct fw_card_driver dummy_driver_template = {
	.enable          = dummy_enable,
	.read_phy_reg		= dummy_read_phy_reg,
	.update_phy_reg		= dummy_update_phy_reg,
	.set_config_rom  = dummy_set_config_rom,
	.send_request		= dummy_send_request,
	.cancel_packet   = dummy_cancel_packet,
	.send_response		= dummy_send_response,
	.cancel_packet		= dummy_cancel_packet,
	.enable_phys_dma	= dummy_enable_phys_dma,
	.allocate_iso_context	= dummy_allocate_iso_context,
	.start_iso		= dummy_start_iso,
	.set_iso_channels	= dummy_set_iso_channels,
	.queue_iso		= dummy_queue_iso,
};

void fw_card_release(struct kref *kref)
@@ -545,7 +640,7 @@ void fw_core_remove_card(struct fw_card *card)

	card->driver->update_phy_reg(card, 4,
				     PHY_LINK_ACTIVE | PHY_CONTENDER, 0);
	fw_core_initiate_bus_reset(card, 1);
	fw_schedule_bus_reset(card, false, true);

	mutex_lock(&card_mutex);
	list_del_init(&card->link);
@@ -565,12 +660,3 @@ void fw_core_remove_card(struct fw_card *card)
	WARN_ON(!list_empty(&card->transaction_list));
}
EXPORT_SYMBOL(fw_core_remove_card);

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;

	return card->driver->update_phy_reg(card, reg, 0, bit);
}
EXPORT_SYMBOL(fw_core_initiate_bus_reset);
Loading