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

Commit 7889b60e authored by Stefan Richter's avatar Stefan Richter
Browse files

firewire: core: optimize propagation of BROADCAST_CHANNEL



Cache the test result of whether a device implements BROADCAST_CHANNEL.
This minimizes traffic on the bus after each bus reset.  A majority of
devices does not implement BROADCAST_CHANNEL.

Remove busy retries; just rely on the hardware to retry requests to busy
responders.  Remove unnecessary log messages.

Rename the flag is_irm to broadcast_channel_allocated to better reflect
its meaning.  Reset the flag earlier in fw_core_handle_bus_reset.

Pass the generation down as a call parameter; that way generation can't
be newer than card->broadcast_channel_allocated and device->node_id.

Signed-off-by: default avatarStefan Richter <stefanr@s5r6.in-berlin.de>
parent cbae787c
Loading
Loading
Loading
Loading
+5 −80
Original line number Diff line number Diff line
@@ -181,83 +181,9 @@ void fw_core_remove_descriptor(struct fw_descriptor *desc)
	mutex_unlock(&card_mutex);
}

#define IRM_RETRIES 2

/*
 * The abi is set by device_for_each_child(), even though we have no use
 * for data, nor do we have a meaningful return value.
 */
int fw_irm_set_broadcast_channel_register(struct device *dev, void *data)
static int set_broadcast_channel(struct device *dev, void *data)
{
	struct fw_device *d;
	int rcode;
	int node_id;
	int max_speed;
	int retries;
	int generation;
	__be32 regval;
	struct fw_card *card;

	d = fw_device(dev);
	/* FIXME: do we need locking here? */
	generation = d->generation;
	smp_rmb(); /* Ensure generation is at least as old as node_id */
	node_id = d->node_id;
	max_speed = d->max_speed;
	retries = IRM_RETRIES;
	card = d->card;
tryagain_r:
	rcode = fw_run_transaction(card, TCODE_READ_QUADLET_REQUEST,
				   node_id, generation, max_speed,
				   CSR_REGISTER_BASE + CSR_BROADCAST_CHANNEL,
				   &regval, 4);
	switch (rcode) {
	case RCODE_BUSY:
		if (retries--)
			goto tryagain_r;
		fw_notify("node %x read broadcast channel busy\n",
			  node_id);
		return 0;

	default:
		fw_notify("node %x read broadcast channel failed %x\n",
			  node_id, rcode);
		return 0;

	case RCODE_COMPLETE:
		/*
		 * Paranoid reporting of nonstandard broadcast channel
		 * contents goes here
		 */
		if (regval != cpu_to_be32(BROADCAST_CHANNEL_INITIAL))
			return 0;
		break;
	}
	retries = IRM_RETRIES;
	regval = cpu_to_be32(BROADCAST_CHANNEL_INITIAL |
			     BROADCAST_CHANNEL_VALID);
tryagain_w:
	rcode = fw_run_transaction(card,
			TCODE_WRITE_QUADLET_REQUEST, node_id,
			generation, max_speed,
			CSR_REGISTER_BASE + CSR_BROADCAST_CHANNEL,
			&regval, 4);
	switch (rcode) {
	case RCODE_BUSY:
		if (retries--)
			goto tryagain_w;
		fw_notify("node %x write broadcast channel busy\n",
			  node_id);
		return 0;

	default:
		fw_notify("node %x write broadcast channel failed %x\n",
			  node_id, rcode);
		return 0;

	case RCODE_COMPLETE:
		return 0;
	}
	fw_device_set_broadcast_channel(fw_device(dev), (long)data);
	return 0;
}

@@ -268,9 +194,9 @@ static void allocate_broadcast_channel(struct fw_card *card, int generation)
	fw_iso_resource_manage(card, generation, 1ULL << 31,
			       &channel, &bandwidth, true);
	if (channel == 31) {
		card->is_irm = true;
		device_for_each_child(card->device, NULL,
				      fw_irm_set_broadcast_channel_register);
		card->broadcast_channel_allocated = true;
		device_for_each_child(card->device, (void *)(long)generation,
				      set_broadcast_channel);
	}
}

@@ -302,7 +228,6 @@ static void fw_card_bm_work(struct work_struct *work)
	__be32 lock_data[2];

	spin_lock_irqsave(&card->lock, flags);
	card->is_irm = false;

	if (card->local_node == NULL) {
		spin_unlock_irqrestore(&card->lock, flags);
+41 −4
Original line number Diff line number Diff line
@@ -518,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);

@@ -756,6 +756,44 @@ 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 =
@@ -849,9 +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;
		if (device->card->is_irm)
			fw_irm_set_broadcast_channel_register(&device->device,
							      NULL);

		fw_device_set_broadcast_channel(device, device->generation);
	}

	/*
+4 −1
Original line number Diff line number Diff line
@@ -71,7 +71,6 @@ struct fw_device {
	int node_id;
	int generation;
	unsigned max_speed;
	bool cmc;
	struct fw_card *card;
	struct device device;

@@ -81,6 +80,9 @@ struct fw_device {
	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;
};
@@ -109,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);
+1 −0
Original line number Diff line number Diff line
@@ -526,6 +526,7 @@ void fw_core_handle_bus_reset(struct fw_card *card, int node_id, int generation,

	spin_lock_irqsave(&card->lock, flags);

	card->broadcast_channel_allocated = false;
	card->node_id = node_id;
	/*
	 * Update node_id before generation to prevent anybody from using
+1 −5
Original line number Diff line number Diff line
@@ -230,11 +230,6 @@ struct fw_card {
	u8 color; /* must be u8 to match the definition in struct fw_node */
	int gap_count;
	bool beta_repeaters_present;
	/*
	 * Set if the local device is the IRM and the broadcast channel
	 * was allocated.
	 */
	bool is_irm;

	int index;

@@ -245,6 +240,7 @@ struct fw_card {
	int bm_retries;
	int bm_generation;

	bool broadcast_channel_allocated;
	u32 broadcast_channel;
	u32 topology_map[(CSR_TOPOLOGY_MAP_END - CSR_TOPOLOGY_MAP) / 4];
};