18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Core IEEE1394 transaction logic
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2004-2006 Kristian Hoegsberg <krh@bitplanet.net>
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/bug.h>
98c2ecf20Sopenharmony_ci#include <linux/completion.h>
108c2ecf20Sopenharmony_ci#include <linux/device.h>
118c2ecf20Sopenharmony_ci#include <linux/errno.h>
128c2ecf20Sopenharmony_ci#include <linux/firewire.h>
138c2ecf20Sopenharmony_ci#include <linux/firewire-constants.h>
148c2ecf20Sopenharmony_ci#include <linux/fs.h>
158c2ecf20Sopenharmony_ci#include <linux/init.h>
168c2ecf20Sopenharmony_ci#include <linux/idr.h>
178c2ecf20Sopenharmony_ci#include <linux/jiffies.h>
188c2ecf20Sopenharmony_ci#include <linux/kernel.h>
198c2ecf20Sopenharmony_ci#include <linux/list.h>
208c2ecf20Sopenharmony_ci#include <linux/module.h>
218c2ecf20Sopenharmony_ci#include <linux/rculist.h>
228c2ecf20Sopenharmony_ci#include <linux/slab.h>
238c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
248c2ecf20Sopenharmony_ci#include <linux/string.h>
258c2ecf20Sopenharmony_ci#include <linux/timer.h>
268c2ecf20Sopenharmony_ci#include <linux/types.h>
278c2ecf20Sopenharmony_ci#include <linux/workqueue.h>
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#include <asm/byteorder.h>
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#include "core.h"
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#define HEADER_PRI(pri)			((pri) << 0)
348c2ecf20Sopenharmony_ci#define HEADER_TCODE(tcode)		((tcode) << 4)
358c2ecf20Sopenharmony_ci#define HEADER_RETRY(retry)		((retry) << 8)
368c2ecf20Sopenharmony_ci#define HEADER_TLABEL(tlabel)		((tlabel) << 10)
378c2ecf20Sopenharmony_ci#define HEADER_DESTINATION(destination)	((destination) << 16)
388c2ecf20Sopenharmony_ci#define HEADER_SOURCE(source)		((source) << 16)
398c2ecf20Sopenharmony_ci#define HEADER_RCODE(rcode)		((rcode) << 12)
408c2ecf20Sopenharmony_ci#define HEADER_OFFSET_HIGH(offset_high)	((offset_high) << 0)
418c2ecf20Sopenharmony_ci#define HEADER_DATA_LENGTH(length)	((length) << 16)
428c2ecf20Sopenharmony_ci#define HEADER_EXTENDED_TCODE(tcode)	((tcode) << 0)
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci#define HEADER_GET_TCODE(q)		(((q) >> 4) & 0x0f)
458c2ecf20Sopenharmony_ci#define HEADER_GET_TLABEL(q)		(((q) >> 10) & 0x3f)
468c2ecf20Sopenharmony_ci#define HEADER_GET_RCODE(q)		(((q) >> 12) & 0x0f)
478c2ecf20Sopenharmony_ci#define HEADER_GET_DESTINATION(q)	(((q) >> 16) & 0xffff)
488c2ecf20Sopenharmony_ci#define HEADER_GET_SOURCE(q)		(((q) >> 16) & 0xffff)
498c2ecf20Sopenharmony_ci#define HEADER_GET_OFFSET_HIGH(q)	(((q) >> 0) & 0xffff)
508c2ecf20Sopenharmony_ci#define HEADER_GET_DATA_LENGTH(q)	(((q) >> 16) & 0xffff)
518c2ecf20Sopenharmony_ci#define HEADER_GET_EXTENDED_TCODE(q)	(((q) >> 0) & 0xffff)
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci#define HEADER_DESTINATION_IS_BROADCAST(q) \
548c2ecf20Sopenharmony_ci	(((q) & HEADER_DESTINATION(0x3f)) == HEADER_DESTINATION(0x3f))
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci#define PHY_PACKET_CONFIG	0x0
578c2ecf20Sopenharmony_ci#define PHY_PACKET_LINK_ON	0x1
588c2ecf20Sopenharmony_ci#define PHY_PACKET_SELF_ID	0x2
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci#define PHY_CONFIG_GAP_COUNT(gap_count)	(((gap_count) << 16) | (1 << 22))
618c2ecf20Sopenharmony_ci#define PHY_CONFIG_ROOT_ID(node_id)	((((node_id) & 0x3f) << 24) | (1 << 23))
628c2ecf20Sopenharmony_ci#define PHY_IDENTIFIER(id)		((id) << 30)
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci/* returns 0 if the split timeout handler is already running */
658c2ecf20Sopenharmony_cistatic int try_cancel_split_timeout(struct fw_transaction *t)
668c2ecf20Sopenharmony_ci{
678c2ecf20Sopenharmony_ci	if (t->is_split_transaction)
688c2ecf20Sopenharmony_ci		return del_timer(&t->split_timeout_timer);
698c2ecf20Sopenharmony_ci	else
708c2ecf20Sopenharmony_ci		return 1;
718c2ecf20Sopenharmony_ci}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_cistatic int close_transaction(struct fw_transaction *transaction,
748c2ecf20Sopenharmony_ci			     struct fw_card *card, int rcode)
758c2ecf20Sopenharmony_ci{
768c2ecf20Sopenharmony_ci	struct fw_transaction *t = NULL, *iter;
778c2ecf20Sopenharmony_ci	unsigned long flags;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	spin_lock_irqsave(&card->lock, flags);
808c2ecf20Sopenharmony_ci	list_for_each_entry(iter, &card->transaction_list, link) {
818c2ecf20Sopenharmony_ci		if (iter == transaction) {
828c2ecf20Sopenharmony_ci			if (!try_cancel_split_timeout(iter)) {
838c2ecf20Sopenharmony_ci				spin_unlock_irqrestore(&card->lock, flags);
848c2ecf20Sopenharmony_ci				goto timed_out;
858c2ecf20Sopenharmony_ci			}
868c2ecf20Sopenharmony_ci			list_del_init(&iter->link);
878c2ecf20Sopenharmony_ci			card->tlabel_mask &= ~(1ULL << iter->tlabel);
888c2ecf20Sopenharmony_ci			t = iter;
898c2ecf20Sopenharmony_ci			break;
908c2ecf20Sopenharmony_ci		}
918c2ecf20Sopenharmony_ci	}
928c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&card->lock, flags);
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	if (t) {
958c2ecf20Sopenharmony_ci		t->callback(card, rcode, NULL, 0, t->callback_data);
968c2ecf20Sopenharmony_ci		return 0;
978c2ecf20Sopenharmony_ci	}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci timed_out:
1008c2ecf20Sopenharmony_ci	return -ENOENT;
1018c2ecf20Sopenharmony_ci}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci/*
1048c2ecf20Sopenharmony_ci * Only valid for transactions that are potentially pending (ie have
1058c2ecf20Sopenharmony_ci * been sent).
1068c2ecf20Sopenharmony_ci */
1078c2ecf20Sopenharmony_ciint fw_cancel_transaction(struct fw_card *card,
1088c2ecf20Sopenharmony_ci			  struct fw_transaction *transaction)
1098c2ecf20Sopenharmony_ci{
1108c2ecf20Sopenharmony_ci	/*
1118c2ecf20Sopenharmony_ci	 * Cancel the packet transmission if it's still queued.  That
1128c2ecf20Sopenharmony_ci	 * will call the packet transmission callback which cancels
1138c2ecf20Sopenharmony_ci	 * the transaction.
1148c2ecf20Sopenharmony_ci	 */
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	if (card->driver->cancel_packet(card, &transaction->packet) == 0)
1178c2ecf20Sopenharmony_ci		return 0;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	/*
1208c2ecf20Sopenharmony_ci	 * If the request packet has already been sent, we need to see
1218c2ecf20Sopenharmony_ci	 * if the transaction is still pending and remove it in that case.
1228c2ecf20Sopenharmony_ci	 */
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	return close_transaction(transaction, card, RCODE_CANCELLED);
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ciEXPORT_SYMBOL(fw_cancel_transaction);
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_cistatic void split_transaction_timeout_callback(struct timer_list *timer)
1298c2ecf20Sopenharmony_ci{
1308c2ecf20Sopenharmony_ci	struct fw_transaction *t = from_timer(t, timer, split_timeout_timer);
1318c2ecf20Sopenharmony_ci	struct fw_card *card = t->card;
1328c2ecf20Sopenharmony_ci	unsigned long flags;
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	spin_lock_irqsave(&card->lock, flags);
1358c2ecf20Sopenharmony_ci	if (list_empty(&t->link)) {
1368c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&card->lock, flags);
1378c2ecf20Sopenharmony_ci		return;
1388c2ecf20Sopenharmony_ci	}
1398c2ecf20Sopenharmony_ci	list_del(&t->link);
1408c2ecf20Sopenharmony_ci	card->tlabel_mask &= ~(1ULL << t->tlabel);
1418c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&card->lock, flags);
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	t->callback(card, RCODE_CANCELLED, NULL, 0, t->callback_data);
1448c2ecf20Sopenharmony_ci}
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_cistatic void start_split_transaction_timeout(struct fw_transaction *t,
1478c2ecf20Sopenharmony_ci					    struct fw_card *card)
1488c2ecf20Sopenharmony_ci{
1498c2ecf20Sopenharmony_ci	unsigned long flags;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	spin_lock_irqsave(&card->lock, flags);
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	if (list_empty(&t->link) || WARN_ON(t->is_split_transaction)) {
1548c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&card->lock, flags);
1558c2ecf20Sopenharmony_ci		return;
1568c2ecf20Sopenharmony_ci	}
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	t->is_split_transaction = true;
1598c2ecf20Sopenharmony_ci	mod_timer(&t->split_timeout_timer,
1608c2ecf20Sopenharmony_ci		  jiffies + card->split_timeout_jiffies);
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&card->lock, flags);
1638c2ecf20Sopenharmony_ci}
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_cistatic void transmit_complete_callback(struct fw_packet *packet,
1668c2ecf20Sopenharmony_ci				       struct fw_card *card, int status)
1678c2ecf20Sopenharmony_ci{
1688c2ecf20Sopenharmony_ci	struct fw_transaction *t =
1698c2ecf20Sopenharmony_ci	    container_of(packet, struct fw_transaction, packet);
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	switch (status) {
1728c2ecf20Sopenharmony_ci	case ACK_COMPLETE:
1738c2ecf20Sopenharmony_ci		close_transaction(t, card, RCODE_COMPLETE);
1748c2ecf20Sopenharmony_ci		break;
1758c2ecf20Sopenharmony_ci	case ACK_PENDING:
1768c2ecf20Sopenharmony_ci		start_split_transaction_timeout(t, card);
1778c2ecf20Sopenharmony_ci		break;
1788c2ecf20Sopenharmony_ci	case ACK_BUSY_X:
1798c2ecf20Sopenharmony_ci	case ACK_BUSY_A:
1808c2ecf20Sopenharmony_ci	case ACK_BUSY_B:
1818c2ecf20Sopenharmony_ci		close_transaction(t, card, RCODE_BUSY);
1828c2ecf20Sopenharmony_ci		break;
1838c2ecf20Sopenharmony_ci	case ACK_DATA_ERROR:
1848c2ecf20Sopenharmony_ci		close_transaction(t, card, RCODE_DATA_ERROR);
1858c2ecf20Sopenharmony_ci		break;
1868c2ecf20Sopenharmony_ci	case ACK_TYPE_ERROR:
1878c2ecf20Sopenharmony_ci		close_transaction(t, card, RCODE_TYPE_ERROR);
1888c2ecf20Sopenharmony_ci		break;
1898c2ecf20Sopenharmony_ci	default:
1908c2ecf20Sopenharmony_ci		/*
1918c2ecf20Sopenharmony_ci		 * In this case the ack is really a juju specific
1928c2ecf20Sopenharmony_ci		 * rcode, so just forward that to the callback.
1938c2ecf20Sopenharmony_ci		 */
1948c2ecf20Sopenharmony_ci		close_transaction(t, card, status);
1958c2ecf20Sopenharmony_ci		break;
1968c2ecf20Sopenharmony_ci	}
1978c2ecf20Sopenharmony_ci}
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_cistatic void fw_fill_request(struct fw_packet *packet, int tcode, int tlabel,
2008c2ecf20Sopenharmony_ci		int destination_id, int source_id, int generation, int speed,
2018c2ecf20Sopenharmony_ci		unsigned long long offset, void *payload, size_t length)
2028c2ecf20Sopenharmony_ci{
2038c2ecf20Sopenharmony_ci	int ext_tcode;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	if (tcode == TCODE_STREAM_DATA) {
2068c2ecf20Sopenharmony_ci		packet->header[0] =
2078c2ecf20Sopenharmony_ci			HEADER_DATA_LENGTH(length) |
2088c2ecf20Sopenharmony_ci			destination_id |
2098c2ecf20Sopenharmony_ci			HEADER_TCODE(TCODE_STREAM_DATA);
2108c2ecf20Sopenharmony_ci		packet->header_length = 4;
2118c2ecf20Sopenharmony_ci		packet->payload = payload;
2128c2ecf20Sopenharmony_ci		packet->payload_length = length;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci		goto common;
2158c2ecf20Sopenharmony_ci	}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	if (tcode > 0x10) {
2188c2ecf20Sopenharmony_ci		ext_tcode = tcode & ~0x10;
2198c2ecf20Sopenharmony_ci		tcode = TCODE_LOCK_REQUEST;
2208c2ecf20Sopenharmony_ci	} else
2218c2ecf20Sopenharmony_ci		ext_tcode = 0;
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	packet->header[0] =
2248c2ecf20Sopenharmony_ci		HEADER_RETRY(RETRY_X) |
2258c2ecf20Sopenharmony_ci		HEADER_TLABEL(tlabel) |
2268c2ecf20Sopenharmony_ci		HEADER_TCODE(tcode) |
2278c2ecf20Sopenharmony_ci		HEADER_DESTINATION(destination_id);
2288c2ecf20Sopenharmony_ci	packet->header[1] =
2298c2ecf20Sopenharmony_ci		HEADER_OFFSET_HIGH(offset >> 32) | HEADER_SOURCE(source_id);
2308c2ecf20Sopenharmony_ci	packet->header[2] =
2318c2ecf20Sopenharmony_ci		offset;
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	switch (tcode) {
2348c2ecf20Sopenharmony_ci	case TCODE_WRITE_QUADLET_REQUEST:
2358c2ecf20Sopenharmony_ci		packet->header[3] = *(u32 *)payload;
2368c2ecf20Sopenharmony_ci		packet->header_length = 16;
2378c2ecf20Sopenharmony_ci		packet->payload_length = 0;
2388c2ecf20Sopenharmony_ci		break;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	case TCODE_LOCK_REQUEST:
2418c2ecf20Sopenharmony_ci	case TCODE_WRITE_BLOCK_REQUEST:
2428c2ecf20Sopenharmony_ci		packet->header[3] =
2438c2ecf20Sopenharmony_ci			HEADER_DATA_LENGTH(length) |
2448c2ecf20Sopenharmony_ci			HEADER_EXTENDED_TCODE(ext_tcode);
2458c2ecf20Sopenharmony_ci		packet->header_length = 16;
2468c2ecf20Sopenharmony_ci		packet->payload = payload;
2478c2ecf20Sopenharmony_ci		packet->payload_length = length;
2488c2ecf20Sopenharmony_ci		break;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	case TCODE_READ_QUADLET_REQUEST:
2518c2ecf20Sopenharmony_ci		packet->header_length = 12;
2528c2ecf20Sopenharmony_ci		packet->payload_length = 0;
2538c2ecf20Sopenharmony_ci		break;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	case TCODE_READ_BLOCK_REQUEST:
2568c2ecf20Sopenharmony_ci		packet->header[3] =
2578c2ecf20Sopenharmony_ci			HEADER_DATA_LENGTH(length) |
2588c2ecf20Sopenharmony_ci			HEADER_EXTENDED_TCODE(ext_tcode);
2598c2ecf20Sopenharmony_ci		packet->header_length = 16;
2608c2ecf20Sopenharmony_ci		packet->payload_length = 0;
2618c2ecf20Sopenharmony_ci		break;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	default:
2648c2ecf20Sopenharmony_ci		WARN(1, "wrong tcode %d\n", tcode);
2658c2ecf20Sopenharmony_ci	}
2668c2ecf20Sopenharmony_ci common:
2678c2ecf20Sopenharmony_ci	packet->speed = speed;
2688c2ecf20Sopenharmony_ci	packet->generation = generation;
2698c2ecf20Sopenharmony_ci	packet->ack = 0;
2708c2ecf20Sopenharmony_ci	packet->payload_mapped = false;
2718c2ecf20Sopenharmony_ci}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_cistatic int allocate_tlabel(struct fw_card *card)
2748c2ecf20Sopenharmony_ci{
2758c2ecf20Sopenharmony_ci	int tlabel;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	tlabel = card->current_tlabel;
2788c2ecf20Sopenharmony_ci	while (card->tlabel_mask & (1ULL << tlabel)) {
2798c2ecf20Sopenharmony_ci		tlabel = (tlabel + 1) & 0x3f;
2808c2ecf20Sopenharmony_ci		if (tlabel == card->current_tlabel)
2818c2ecf20Sopenharmony_ci			return -EBUSY;
2828c2ecf20Sopenharmony_ci	}
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	card->current_tlabel = (tlabel + 1) & 0x3f;
2858c2ecf20Sopenharmony_ci	card->tlabel_mask |= 1ULL << tlabel;
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	return tlabel;
2888c2ecf20Sopenharmony_ci}
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci/**
2918c2ecf20Sopenharmony_ci * fw_send_request() - submit a request packet for transmission
2928c2ecf20Sopenharmony_ci * @card:		interface to send the request at
2938c2ecf20Sopenharmony_ci * @t:			transaction instance to which the request belongs
2948c2ecf20Sopenharmony_ci * @tcode:		transaction code
2958c2ecf20Sopenharmony_ci * @destination_id:	destination node ID, consisting of bus_ID and phy_ID
2968c2ecf20Sopenharmony_ci * @generation:		bus generation in which request and response are valid
2978c2ecf20Sopenharmony_ci * @speed:		transmission speed
2988c2ecf20Sopenharmony_ci * @offset:		48bit wide offset into destination's address space
2998c2ecf20Sopenharmony_ci * @payload:		data payload for the request subaction
3008c2ecf20Sopenharmony_ci * @length:		length of the payload, in bytes
3018c2ecf20Sopenharmony_ci * @callback:		function to be called when the transaction is completed
3028c2ecf20Sopenharmony_ci * @callback_data:	data to be passed to the transaction completion callback
3038c2ecf20Sopenharmony_ci *
3048c2ecf20Sopenharmony_ci * Submit a request packet into the asynchronous request transmission queue.
3058c2ecf20Sopenharmony_ci * Can be called from atomic context.  If you prefer a blocking API, use
3068c2ecf20Sopenharmony_ci * fw_run_transaction() in a context that can sleep.
3078c2ecf20Sopenharmony_ci *
3088c2ecf20Sopenharmony_ci * In case of lock requests, specify one of the firewire-core specific %TCODE_
3098c2ecf20Sopenharmony_ci * constants instead of %TCODE_LOCK_REQUEST in @tcode.
3108c2ecf20Sopenharmony_ci *
3118c2ecf20Sopenharmony_ci * Make sure that the value in @destination_id is not older than the one in
3128c2ecf20Sopenharmony_ci * @generation.  Otherwise the request is in danger to be sent to a wrong node.
3138c2ecf20Sopenharmony_ci *
3148c2ecf20Sopenharmony_ci * In case of asynchronous stream packets i.e. %TCODE_STREAM_DATA, the caller
3158c2ecf20Sopenharmony_ci * needs to synthesize @destination_id with fw_stream_packet_destination_id().
3168c2ecf20Sopenharmony_ci * It will contain tag, channel, and sy data instead of a node ID then.
3178c2ecf20Sopenharmony_ci *
3188c2ecf20Sopenharmony_ci * The payload buffer at @data is going to be DMA-mapped except in case of
3198c2ecf20Sopenharmony_ci * @length <= 8 or of local (loopback) requests.  Hence make sure that the
3208c2ecf20Sopenharmony_ci * buffer complies with the restrictions of the streaming DMA mapping API.
3218c2ecf20Sopenharmony_ci * @payload must not be freed before the @callback is called.
3228c2ecf20Sopenharmony_ci *
3238c2ecf20Sopenharmony_ci * In case of request types without payload, @data is NULL and @length is 0.
3248c2ecf20Sopenharmony_ci *
3258c2ecf20Sopenharmony_ci * After the transaction is completed successfully or unsuccessfully, the
3268c2ecf20Sopenharmony_ci * @callback will be called.  Among its parameters is the response code which
3278c2ecf20Sopenharmony_ci * is either one of the rcodes per IEEE 1394 or, in case of internal errors,
3288c2ecf20Sopenharmony_ci * the firewire-core specific %RCODE_SEND_ERROR.  The other firewire-core
3298c2ecf20Sopenharmony_ci * specific rcodes (%RCODE_CANCELLED, %RCODE_BUSY, %RCODE_GENERATION,
3308c2ecf20Sopenharmony_ci * %RCODE_NO_ACK) denote transaction timeout, busy responder, stale request
3318c2ecf20Sopenharmony_ci * generation, or missing ACK respectively.
3328c2ecf20Sopenharmony_ci *
3338c2ecf20Sopenharmony_ci * Note some timing corner cases:  fw_send_request() may complete much earlier
3348c2ecf20Sopenharmony_ci * than when the request packet actually hits the wire.  On the other hand,
3358c2ecf20Sopenharmony_ci * transaction completion and hence execution of @callback may happen even
3368c2ecf20Sopenharmony_ci * before fw_send_request() returns.
3378c2ecf20Sopenharmony_ci */
3388c2ecf20Sopenharmony_civoid fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode,
3398c2ecf20Sopenharmony_ci		     int destination_id, int generation, int speed,
3408c2ecf20Sopenharmony_ci		     unsigned long long offset, void *payload, size_t length,
3418c2ecf20Sopenharmony_ci		     fw_transaction_callback_t callback, void *callback_data)
3428c2ecf20Sopenharmony_ci{
3438c2ecf20Sopenharmony_ci	unsigned long flags;
3448c2ecf20Sopenharmony_ci	int tlabel;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	/*
3478c2ecf20Sopenharmony_ci	 * Allocate tlabel from the bitmap and put the transaction on
3488c2ecf20Sopenharmony_ci	 * the list while holding the card spinlock.
3498c2ecf20Sopenharmony_ci	 */
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	spin_lock_irqsave(&card->lock, flags);
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	tlabel = allocate_tlabel(card);
3548c2ecf20Sopenharmony_ci	if (tlabel < 0) {
3558c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&card->lock, flags);
3568c2ecf20Sopenharmony_ci		callback(card, RCODE_SEND_ERROR, NULL, 0, callback_data);
3578c2ecf20Sopenharmony_ci		return;
3588c2ecf20Sopenharmony_ci	}
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	t->node_id = destination_id;
3618c2ecf20Sopenharmony_ci	t->tlabel = tlabel;
3628c2ecf20Sopenharmony_ci	t->card = card;
3638c2ecf20Sopenharmony_ci	t->is_split_transaction = false;
3648c2ecf20Sopenharmony_ci	timer_setup(&t->split_timeout_timer,
3658c2ecf20Sopenharmony_ci		    split_transaction_timeout_callback, 0);
3668c2ecf20Sopenharmony_ci	t->callback = callback;
3678c2ecf20Sopenharmony_ci	t->callback_data = callback_data;
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	fw_fill_request(&t->packet, tcode, t->tlabel,
3708c2ecf20Sopenharmony_ci			destination_id, card->node_id, generation,
3718c2ecf20Sopenharmony_ci			speed, offset, payload, length);
3728c2ecf20Sopenharmony_ci	t->packet.callback = transmit_complete_callback;
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	list_add_tail(&t->link, &card->transaction_list);
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&card->lock, flags);
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	card->driver->send_request(card, &t->packet);
3798c2ecf20Sopenharmony_ci}
3808c2ecf20Sopenharmony_ciEXPORT_SYMBOL(fw_send_request);
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_cistruct transaction_callback_data {
3838c2ecf20Sopenharmony_ci	struct completion done;
3848c2ecf20Sopenharmony_ci	void *payload;
3858c2ecf20Sopenharmony_ci	int rcode;
3868c2ecf20Sopenharmony_ci};
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_cistatic void transaction_callback(struct fw_card *card, int rcode,
3898c2ecf20Sopenharmony_ci				 void *payload, size_t length, void *data)
3908c2ecf20Sopenharmony_ci{
3918c2ecf20Sopenharmony_ci	struct transaction_callback_data *d = data;
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	if (rcode == RCODE_COMPLETE)
3948c2ecf20Sopenharmony_ci		memcpy(d->payload, payload, length);
3958c2ecf20Sopenharmony_ci	d->rcode = rcode;
3968c2ecf20Sopenharmony_ci	complete(&d->done);
3978c2ecf20Sopenharmony_ci}
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci/**
4008c2ecf20Sopenharmony_ci * fw_run_transaction() - send request and sleep until transaction is completed
4018c2ecf20Sopenharmony_ci * @card:		card interface for this request
4028c2ecf20Sopenharmony_ci * @tcode:		transaction code
4038c2ecf20Sopenharmony_ci * @destination_id:	destination node ID, consisting of bus_ID and phy_ID
4048c2ecf20Sopenharmony_ci * @generation:		bus generation in which request and response are valid
4058c2ecf20Sopenharmony_ci * @speed:		transmission speed
4068c2ecf20Sopenharmony_ci * @offset:		48bit wide offset into destination's address space
4078c2ecf20Sopenharmony_ci * @payload:		data payload for the request subaction
4088c2ecf20Sopenharmony_ci * @length:		length of the payload, in bytes
4098c2ecf20Sopenharmony_ci *
4108c2ecf20Sopenharmony_ci * Returns the RCODE.  See fw_send_request() for parameter documentation.
4118c2ecf20Sopenharmony_ci * Unlike fw_send_request(), @data points to the payload of the request or/and
4128c2ecf20Sopenharmony_ci * to the payload of the response.  DMA mapping restrictions apply to outbound
4138c2ecf20Sopenharmony_ci * request payloads of >= 8 bytes but not to inbound response payloads.
4148c2ecf20Sopenharmony_ci */
4158c2ecf20Sopenharmony_ciint fw_run_transaction(struct fw_card *card, int tcode, int destination_id,
4168c2ecf20Sopenharmony_ci		       int generation, int speed, unsigned long long offset,
4178c2ecf20Sopenharmony_ci		       void *payload, size_t length)
4188c2ecf20Sopenharmony_ci{
4198c2ecf20Sopenharmony_ci	struct transaction_callback_data d;
4208c2ecf20Sopenharmony_ci	struct fw_transaction t;
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	timer_setup_on_stack(&t.split_timeout_timer, NULL, 0);
4238c2ecf20Sopenharmony_ci	init_completion(&d.done);
4248c2ecf20Sopenharmony_ci	d.payload = payload;
4258c2ecf20Sopenharmony_ci	fw_send_request(card, &t, tcode, destination_id, generation, speed,
4268c2ecf20Sopenharmony_ci			offset, payload, length, transaction_callback, &d);
4278c2ecf20Sopenharmony_ci	wait_for_completion(&d.done);
4288c2ecf20Sopenharmony_ci	destroy_timer_on_stack(&t.split_timeout_timer);
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	return d.rcode;
4318c2ecf20Sopenharmony_ci}
4328c2ecf20Sopenharmony_ciEXPORT_SYMBOL(fw_run_transaction);
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(phy_config_mutex);
4358c2ecf20Sopenharmony_cistatic DECLARE_COMPLETION(phy_config_done);
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_cistatic void transmit_phy_packet_callback(struct fw_packet *packet,
4388c2ecf20Sopenharmony_ci					 struct fw_card *card, int status)
4398c2ecf20Sopenharmony_ci{
4408c2ecf20Sopenharmony_ci	complete(&phy_config_done);
4418c2ecf20Sopenharmony_ci}
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_cistatic struct fw_packet phy_config_packet = {
4448c2ecf20Sopenharmony_ci	.header_length	= 12,
4458c2ecf20Sopenharmony_ci	.header[0]	= TCODE_LINK_INTERNAL << 4,
4468c2ecf20Sopenharmony_ci	.payload_length	= 0,
4478c2ecf20Sopenharmony_ci	.speed		= SCODE_100,
4488c2ecf20Sopenharmony_ci	.callback	= transmit_phy_packet_callback,
4498c2ecf20Sopenharmony_ci};
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_civoid fw_send_phy_config(struct fw_card *card,
4528c2ecf20Sopenharmony_ci			int node_id, int generation, int gap_count)
4538c2ecf20Sopenharmony_ci{
4548c2ecf20Sopenharmony_ci	long timeout = DIV_ROUND_UP(HZ, 10);
4558c2ecf20Sopenharmony_ci	u32 data = PHY_IDENTIFIER(PHY_PACKET_CONFIG);
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	if (node_id != FW_PHY_CONFIG_NO_NODE_ID)
4588c2ecf20Sopenharmony_ci		data |= PHY_CONFIG_ROOT_ID(node_id);
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	if (gap_count == FW_PHY_CONFIG_CURRENT_GAP_COUNT) {
4618c2ecf20Sopenharmony_ci		gap_count = card->driver->read_phy_reg(card, 1);
4628c2ecf20Sopenharmony_ci		if (gap_count < 0)
4638c2ecf20Sopenharmony_ci			return;
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci		gap_count &= 63;
4668c2ecf20Sopenharmony_ci		if (gap_count == 63)
4678c2ecf20Sopenharmony_ci			return;
4688c2ecf20Sopenharmony_ci	}
4698c2ecf20Sopenharmony_ci	data |= PHY_CONFIG_GAP_COUNT(gap_count);
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	mutex_lock(&phy_config_mutex);
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	phy_config_packet.header[1] = data;
4748c2ecf20Sopenharmony_ci	phy_config_packet.header[2] = ~data;
4758c2ecf20Sopenharmony_ci	phy_config_packet.generation = generation;
4768c2ecf20Sopenharmony_ci	reinit_completion(&phy_config_done);
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	card->driver->send_request(card, &phy_config_packet);
4798c2ecf20Sopenharmony_ci	wait_for_completion_timeout(&phy_config_done, timeout);
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	mutex_unlock(&phy_config_mutex);
4828c2ecf20Sopenharmony_ci}
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_cistatic struct fw_address_handler *lookup_overlapping_address_handler(
4858c2ecf20Sopenharmony_ci	struct list_head *list, unsigned long long offset, size_t length)
4868c2ecf20Sopenharmony_ci{
4878c2ecf20Sopenharmony_ci	struct fw_address_handler *handler;
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(handler, list, link) {
4908c2ecf20Sopenharmony_ci		if (handler->offset < offset + length &&
4918c2ecf20Sopenharmony_ci		    offset < handler->offset + handler->length)
4928c2ecf20Sopenharmony_ci			return handler;
4938c2ecf20Sopenharmony_ci	}
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	return NULL;
4968c2ecf20Sopenharmony_ci}
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_cistatic bool is_enclosing_handler(struct fw_address_handler *handler,
4998c2ecf20Sopenharmony_ci				 unsigned long long offset, size_t length)
5008c2ecf20Sopenharmony_ci{
5018c2ecf20Sopenharmony_ci	return handler->offset <= offset &&
5028c2ecf20Sopenharmony_ci		offset + length <= handler->offset + handler->length;
5038c2ecf20Sopenharmony_ci}
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_cistatic struct fw_address_handler *lookup_enclosing_address_handler(
5068c2ecf20Sopenharmony_ci	struct list_head *list, unsigned long long offset, size_t length)
5078c2ecf20Sopenharmony_ci{
5088c2ecf20Sopenharmony_ci	struct fw_address_handler *handler;
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(handler, list, link) {
5118c2ecf20Sopenharmony_ci		if (is_enclosing_handler(handler, offset, length))
5128c2ecf20Sopenharmony_ci			return handler;
5138c2ecf20Sopenharmony_ci	}
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	return NULL;
5168c2ecf20Sopenharmony_ci}
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(address_handler_list_lock);
5198c2ecf20Sopenharmony_cistatic LIST_HEAD(address_handler_list);
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ciconst struct fw_address_region fw_high_memory_region =
5228c2ecf20Sopenharmony_ci	{ .start = FW_MAX_PHYSICAL_RANGE, .end = 0xffffe0000000ULL, };
5238c2ecf20Sopenharmony_ciEXPORT_SYMBOL(fw_high_memory_region);
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_cistatic const struct fw_address_region low_memory_region =
5268c2ecf20Sopenharmony_ci	{ .start = 0x000000000000ULL, .end = FW_MAX_PHYSICAL_RANGE, };
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci#if 0
5298c2ecf20Sopenharmony_ciconst struct fw_address_region fw_private_region =
5308c2ecf20Sopenharmony_ci	{ .start = 0xffffe0000000ULL, .end = 0xfffff0000000ULL,  };
5318c2ecf20Sopenharmony_ciconst struct fw_address_region fw_csr_region =
5328c2ecf20Sopenharmony_ci	{ .start = CSR_REGISTER_BASE,
5338c2ecf20Sopenharmony_ci	  .end   = CSR_REGISTER_BASE | CSR_CONFIG_ROM_END,  };
5348c2ecf20Sopenharmony_ciconst struct fw_address_region fw_unit_space_region =
5358c2ecf20Sopenharmony_ci	{ .start = 0xfffff0000900ULL, .end = 0x1000000000000ULL, };
5368c2ecf20Sopenharmony_ci#endif  /*  0  */
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_cistatic bool is_in_fcp_region(u64 offset, size_t length)
5398c2ecf20Sopenharmony_ci{
5408c2ecf20Sopenharmony_ci	return offset >= (CSR_REGISTER_BASE | CSR_FCP_COMMAND) &&
5418c2ecf20Sopenharmony_ci		offset + length <= (CSR_REGISTER_BASE | CSR_FCP_END);
5428c2ecf20Sopenharmony_ci}
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci/**
5458c2ecf20Sopenharmony_ci * fw_core_add_address_handler() - register for incoming requests
5468c2ecf20Sopenharmony_ci * @handler:	callback
5478c2ecf20Sopenharmony_ci * @region:	region in the IEEE 1212 node space address range
5488c2ecf20Sopenharmony_ci *
5498c2ecf20Sopenharmony_ci * region->start, ->end, and handler->length have to be quadlet-aligned.
5508c2ecf20Sopenharmony_ci *
5518c2ecf20Sopenharmony_ci * When a request is received that falls within the specified address range,
5528c2ecf20Sopenharmony_ci * the specified callback is invoked.  The parameters passed to the callback
5538c2ecf20Sopenharmony_ci * give the details of the particular request.
5548c2ecf20Sopenharmony_ci *
5558c2ecf20Sopenharmony_ci * To be called in process context.
5568c2ecf20Sopenharmony_ci * Return value:  0 on success, non-zero otherwise.
5578c2ecf20Sopenharmony_ci *
5588c2ecf20Sopenharmony_ci * The start offset of the handler's address region is determined by
5598c2ecf20Sopenharmony_ci * fw_core_add_address_handler() and is returned in handler->offset.
5608c2ecf20Sopenharmony_ci *
5618c2ecf20Sopenharmony_ci * Address allocations are exclusive, except for the FCP registers.
5628c2ecf20Sopenharmony_ci */
5638c2ecf20Sopenharmony_ciint fw_core_add_address_handler(struct fw_address_handler *handler,
5648c2ecf20Sopenharmony_ci				const struct fw_address_region *region)
5658c2ecf20Sopenharmony_ci{
5668c2ecf20Sopenharmony_ci	struct fw_address_handler *other;
5678c2ecf20Sopenharmony_ci	int ret = -EBUSY;
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	if (region->start & 0xffff000000000003ULL ||
5708c2ecf20Sopenharmony_ci	    region->start >= region->end ||
5718c2ecf20Sopenharmony_ci	    region->end   > 0x0001000000000000ULL ||
5728c2ecf20Sopenharmony_ci	    handler->length & 3 ||
5738c2ecf20Sopenharmony_ci	    handler->length == 0)
5748c2ecf20Sopenharmony_ci		return -EINVAL;
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	spin_lock(&address_handler_list_lock);
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	handler->offset = region->start;
5798c2ecf20Sopenharmony_ci	while (handler->offset + handler->length <= region->end) {
5808c2ecf20Sopenharmony_ci		if (is_in_fcp_region(handler->offset, handler->length))
5818c2ecf20Sopenharmony_ci			other = NULL;
5828c2ecf20Sopenharmony_ci		else
5838c2ecf20Sopenharmony_ci			other = lookup_overlapping_address_handler
5848c2ecf20Sopenharmony_ci					(&address_handler_list,
5858c2ecf20Sopenharmony_ci					 handler->offset, handler->length);
5868c2ecf20Sopenharmony_ci		if (other != NULL) {
5878c2ecf20Sopenharmony_ci			handler->offset += other->length;
5888c2ecf20Sopenharmony_ci		} else {
5898c2ecf20Sopenharmony_ci			list_add_tail_rcu(&handler->link, &address_handler_list);
5908c2ecf20Sopenharmony_ci			ret = 0;
5918c2ecf20Sopenharmony_ci			break;
5928c2ecf20Sopenharmony_ci		}
5938c2ecf20Sopenharmony_ci	}
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	spin_unlock(&address_handler_list_lock);
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	return ret;
5988c2ecf20Sopenharmony_ci}
5998c2ecf20Sopenharmony_ciEXPORT_SYMBOL(fw_core_add_address_handler);
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci/**
6028c2ecf20Sopenharmony_ci * fw_core_remove_address_handler() - unregister an address handler
6038c2ecf20Sopenharmony_ci * @handler: callback
6048c2ecf20Sopenharmony_ci *
6058c2ecf20Sopenharmony_ci * To be called in process context.
6068c2ecf20Sopenharmony_ci *
6078c2ecf20Sopenharmony_ci * When fw_core_remove_address_handler() returns, @handler->callback() is
6088c2ecf20Sopenharmony_ci * guaranteed to not run on any CPU anymore.
6098c2ecf20Sopenharmony_ci */
6108c2ecf20Sopenharmony_civoid fw_core_remove_address_handler(struct fw_address_handler *handler)
6118c2ecf20Sopenharmony_ci{
6128c2ecf20Sopenharmony_ci	spin_lock(&address_handler_list_lock);
6138c2ecf20Sopenharmony_ci	list_del_rcu(&handler->link);
6148c2ecf20Sopenharmony_ci	spin_unlock(&address_handler_list_lock);
6158c2ecf20Sopenharmony_ci	synchronize_rcu();
6168c2ecf20Sopenharmony_ci}
6178c2ecf20Sopenharmony_ciEXPORT_SYMBOL(fw_core_remove_address_handler);
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_cistruct fw_request {
6208c2ecf20Sopenharmony_ci	struct fw_packet response;
6218c2ecf20Sopenharmony_ci	u32 request_header[4];
6228c2ecf20Sopenharmony_ci	int ack;
6238c2ecf20Sopenharmony_ci	u32 length;
6248c2ecf20Sopenharmony_ci	u32 data[];
6258c2ecf20Sopenharmony_ci};
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_cistatic void free_response_callback(struct fw_packet *packet,
6288c2ecf20Sopenharmony_ci				   struct fw_card *card, int status)
6298c2ecf20Sopenharmony_ci{
6308c2ecf20Sopenharmony_ci	struct fw_request *request;
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	request = container_of(packet, struct fw_request, response);
6338c2ecf20Sopenharmony_ci	kfree(request);
6348c2ecf20Sopenharmony_ci}
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ciint fw_get_response_length(struct fw_request *r)
6378c2ecf20Sopenharmony_ci{
6388c2ecf20Sopenharmony_ci	int tcode, ext_tcode, data_length;
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci	tcode = HEADER_GET_TCODE(r->request_header[0]);
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	switch (tcode) {
6438c2ecf20Sopenharmony_ci	case TCODE_WRITE_QUADLET_REQUEST:
6448c2ecf20Sopenharmony_ci	case TCODE_WRITE_BLOCK_REQUEST:
6458c2ecf20Sopenharmony_ci		return 0;
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	case TCODE_READ_QUADLET_REQUEST:
6488c2ecf20Sopenharmony_ci		return 4;
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	case TCODE_READ_BLOCK_REQUEST:
6518c2ecf20Sopenharmony_ci		data_length = HEADER_GET_DATA_LENGTH(r->request_header[3]);
6528c2ecf20Sopenharmony_ci		return data_length;
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci	case TCODE_LOCK_REQUEST:
6558c2ecf20Sopenharmony_ci		ext_tcode = HEADER_GET_EXTENDED_TCODE(r->request_header[3]);
6568c2ecf20Sopenharmony_ci		data_length = HEADER_GET_DATA_LENGTH(r->request_header[3]);
6578c2ecf20Sopenharmony_ci		switch (ext_tcode) {
6588c2ecf20Sopenharmony_ci		case EXTCODE_FETCH_ADD:
6598c2ecf20Sopenharmony_ci		case EXTCODE_LITTLE_ADD:
6608c2ecf20Sopenharmony_ci			return data_length;
6618c2ecf20Sopenharmony_ci		default:
6628c2ecf20Sopenharmony_ci			return data_length / 2;
6638c2ecf20Sopenharmony_ci		}
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci	default:
6668c2ecf20Sopenharmony_ci		WARN(1, "wrong tcode %d\n", tcode);
6678c2ecf20Sopenharmony_ci		return 0;
6688c2ecf20Sopenharmony_ci	}
6698c2ecf20Sopenharmony_ci}
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_civoid fw_fill_response(struct fw_packet *response, u32 *request_header,
6728c2ecf20Sopenharmony_ci		      int rcode, void *payload, size_t length)
6738c2ecf20Sopenharmony_ci{
6748c2ecf20Sopenharmony_ci	int tcode, tlabel, extended_tcode, source, destination;
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci	tcode          = HEADER_GET_TCODE(request_header[0]);
6778c2ecf20Sopenharmony_ci	tlabel         = HEADER_GET_TLABEL(request_header[0]);
6788c2ecf20Sopenharmony_ci	source         = HEADER_GET_DESTINATION(request_header[0]);
6798c2ecf20Sopenharmony_ci	destination    = HEADER_GET_SOURCE(request_header[1]);
6808c2ecf20Sopenharmony_ci	extended_tcode = HEADER_GET_EXTENDED_TCODE(request_header[3]);
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci	response->header[0] =
6838c2ecf20Sopenharmony_ci		HEADER_RETRY(RETRY_1) |
6848c2ecf20Sopenharmony_ci		HEADER_TLABEL(tlabel) |
6858c2ecf20Sopenharmony_ci		HEADER_DESTINATION(destination);
6868c2ecf20Sopenharmony_ci	response->header[1] =
6878c2ecf20Sopenharmony_ci		HEADER_SOURCE(source) |
6888c2ecf20Sopenharmony_ci		HEADER_RCODE(rcode);
6898c2ecf20Sopenharmony_ci	response->header[2] = 0;
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	switch (tcode) {
6928c2ecf20Sopenharmony_ci	case TCODE_WRITE_QUADLET_REQUEST:
6938c2ecf20Sopenharmony_ci	case TCODE_WRITE_BLOCK_REQUEST:
6948c2ecf20Sopenharmony_ci		response->header[0] |= HEADER_TCODE(TCODE_WRITE_RESPONSE);
6958c2ecf20Sopenharmony_ci		response->header_length = 12;
6968c2ecf20Sopenharmony_ci		response->payload_length = 0;
6978c2ecf20Sopenharmony_ci		break;
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci	case TCODE_READ_QUADLET_REQUEST:
7008c2ecf20Sopenharmony_ci		response->header[0] |=
7018c2ecf20Sopenharmony_ci			HEADER_TCODE(TCODE_READ_QUADLET_RESPONSE);
7028c2ecf20Sopenharmony_ci		if (payload != NULL)
7038c2ecf20Sopenharmony_ci			response->header[3] = *(u32 *)payload;
7048c2ecf20Sopenharmony_ci		else
7058c2ecf20Sopenharmony_ci			response->header[3] = 0;
7068c2ecf20Sopenharmony_ci		response->header_length = 16;
7078c2ecf20Sopenharmony_ci		response->payload_length = 0;
7088c2ecf20Sopenharmony_ci		break;
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	case TCODE_READ_BLOCK_REQUEST:
7118c2ecf20Sopenharmony_ci	case TCODE_LOCK_REQUEST:
7128c2ecf20Sopenharmony_ci		response->header[0] |= HEADER_TCODE(tcode + 2);
7138c2ecf20Sopenharmony_ci		response->header[3] =
7148c2ecf20Sopenharmony_ci			HEADER_DATA_LENGTH(length) |
7158c2ecf20Sopenharmony_ci			HEADER_EXTENDED_TCODE(extended_tcode);
7168c2ecf20Sopenharmony_ci		response->header_length = 16;
7178c2ecf20Sopenharmony_ci		response->payload = payload;
7188c2ecf20Sopenharmony_ci		response->payload_length = length;
7198c2ecf20Sopenharmony_ci		break;
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci	default:
7228c2ecf20Sopenharmony_ci		WARN(1, "wrong tcode %d\n", tcode);
7238c2ecf20Sopenharmony_ci	}
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	response->payload_mapped = false;
7268c2ecf20Sopenharmony_ci}
7278c2ecf20Sopenharmony_ciEXPORT_SYMBOL(fw_fill_response);
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_cistatic u32 compute_split_timeout_timestamp(struct fw_card *card,
7308c2ecf20Sopenharmony_ci					   u32 request_timestamp)
7318c2ecf20Sopenharmony_ci{
7328c2ecf20Sopenharmony_ci	unsigned int cycles;
7338c2ecf20Sopenharmony_ci	u32 timestamp;
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci	cycles = card->split_timeout_cycles;
7368c2ecf20Sopenharmony_ci	cycles += request_timestamp & 0x1fff;
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci	timestamp = request_timestamp & ~0x1fff;
7398c2ecf20Sopenharmony_ci	timestamp += (cycles / 8000) << 13;
7408c2ecf20Sopenharmony_ci	timestamp |= cycles % 8000;
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	return timestamp;
7438c2ecf20Sopenharmony_ci}
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_cistatic struct fw_request *allocate_request(struct fw_card *card,
7468c2ecf20Sopenharmony_ci					   struct fw_packet *p)
7478c2ecf20Sopenharmony_ci{
7488c2ecf20Sopenharmony_ci	struct fw_request *request;
7498c2ecf20Sopenharmony_ci	u32 *data, length;
7508c2ecf20Sopenharmony_ci	int request_tcode;
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci	request_tcode = HEADER_GET_TCODE(p->header[0]);
7538c2ecf20Sopenharmony_ci	switch (request_tcode) {
7548c2ecf20Sopenharmony_ci	case TCODE_WRITE_QUADLET_REQUEST:
7558c2ecf20Sopenharmony_ci		data = &p->header[3];
7568c2ecf20Sopenharmony_ci		length = 4;
7578c2ecf20Sopenharmony_ci		break;
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci	case TCODE_WRITE_BLOCK_REQUEST:
7608c2ecf20Sopenharmony_ci	case TCODE_LOCK_REQUEST:
7618c2ecf20Sopenharmony_ci		data = p->payload;
7628c2ecf20Sopenharmony_ci		length = HEADER_GET_DATA_LENGTH(p->header[3]);
7638c2ecf20Sopenharmony_ci		break;
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci	case TCODE_READ_QUADLET_REQUEST:
7668c2ecf20Sopenharmony_ci		data = NULL;
7678c2ecf20Sopenharmony_ci		length = 4;
7688c2ecf20Sopenharmony_ci		break;
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci	case TCODE_READ_BLOCK_REQUEST:
7718c2ecf20Sopenharmony_ci		data = NULL;
7728c2ecf20Sopenharmony_ci		length = HEADER_GET_DATA_LENGTH(p->header[3]);
7738c2ecf20Sopenharmony_ci		break;
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci	default:
7768c2ecf20Sopenharmony_ci		fw_notice(card, "ERROR - corrupt request received - %08x %08x %08x\n",
7778c2ecf20Sopenharmony_ci			 p->header[0], p->header[1], p->header[2]);
7788c2ecf20Sopenharmony_ci		return NULL;
7798c2ecf20Sopenharmony_ci	}
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci	request = kmalloc(sizeof(*request) + length, GFP_ATOMIC);
7828c2ecf20Sopenharmony_ci	if (request == NULL)
7838c2ecf20Sopenharmony_ci		return NULL;
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_ci	request->response.speed = p->speed;
7868c2ecf20Sopenharmony_ci	request->response.timestamp =
7878c2ecf20Sopenharmony_ci			compute_split_timeout_timestamp(card, p->timestamp);
7888c2ecf20Sopenharmony_ci	request->response.generation = p->generation;
7898c2ecf20Sopenharmony_ci	request->response.ack = 0;
7908c2ecf20Sopenharmony_ci	request->response.callback = free_response_callback;
7918c2ecf20Sopenharmony_ci	request->ack = p->ack;
7928c2ecf20Sopenharmony_ci	request->length = length;
7938c2ecf20Sopenharmony_ci	if (data)
7948c2ecf20Sopenharmony_ci		memcpy(request->data, data, length);
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci	memcpy(request->request_header, p->header, sizeof(p->header));
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci	return request;
7998c2ecf20Sopenharmony_ci}
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_civoid fw_send_response(struct fw_card *card,
8028c2ecf20Sopenharmony_ci		      struct fw_request *request, int rcode)
8038c2ecf20Sopenharmony_ci{
8048c2ecf20Sopenharmony_ci	if (WARN_ONCE(!request, "invalid for FCP address handlers"))
8058c2ecf20Sopenharmony_ci		return;
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci	/* unified transaction or broadcast transaction: don't respond */
8088c2ecf20Sopenharmony_ci	if (request->ack != ACK_PENDING ||
8098c2ecf20Sopenharmony_ci	    HEADER_DESTINATION_IS_BROADCAST(request->request_header[0])) {
8108c2ecf20Sopenharmony_ci		kfree(request);
8118c2ecf20Sopenharmony_ci		return;
8128c2ecf20Sopenharmony_ci	}
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	if (rcode == RCODE_COMPLETE)
8158c2ecf20Sopenharmony_ci		fw_fill_response(&request->response, request->request_header,
8168c2ecf20Sopenharmony_ci				 rcode, request->data,
8178c2ecf20Sopenharmony_ci				 fw_get_response_length(request));
8188c2ecf20Sopenharmony_ci	else
8198c2ecf20Sopenharmony_ci		fw_fill_response(&request->response, request->request_header,
8208c2ecf20Sopenharmony_ci				 rcode, NULL, 0);
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ci	card->driver->send_response(card, &request->response);
8238c2ecf20Sopenharmony_ci}
8248c2ecf20Sopenharmony_ciEXPORT_SYMBOL(fw_send_response);
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ci/**
8278c2ecf20Sopenharmony_ci * fw_get_request_speed() - returns speed at which the @request was received
8288c2ecf20Sopenharmony_ci * @request: firewire request data
8298c2ecf20Sopenharmony_ci */
8308c2ecf20Sopenharmony_ciint fw_get_request_speed(struct fw_request *request)
8318c2ecf20Sopenharmony_ci{
8328c2ecf20Sopenharmony_ci	return request->response.speed;
8338c2ecf20Sopenharmony_ci}
8348c2ecf20Sopenharmony_ciEXPORT_SYMBOL(fw_get_request_speed);
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_cistatic void handle_exclusive_region_request(struct fw_card *card,
8378c2ecf20Sopenharmony_ci					    struct fw_packet *p,
8388c2ecf20Sopenharmony_ci					    struct fw_request *request,
8398c2ecf20Sopenharmony_ci					    unsigned long long offset)
8408c2ecf20Sopenharmony_ci{
8418c2ecf20Sopenharmony_ci	struct fw_address_handler *handler;
8428c2ecf20Sopenharmony_ci	int tcode, destination, source;
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci	destination = HEADER_GET_DESTINATION(p->header[0]);
8458c2ecf20Sopenharmony_ci	source      = HEADER_GET_SOURCE(p->header[1]);
8468c2ecf20Sopenharmony_ci	tcode       = HEADER_GET_TCODE(p->header[0]);
8478c2ecf20Sopenharmony_ci	if (tcode == TCODE_LOCK_REQUEST)
8488c2ecf20Sopenharmony_ci		tcode = 0x10 + HEADER_GET_EXTENDED_TCODE(p->header[3]);
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci	rcu_read_lock();
8518c2ecf20Sopenharmony_ci	handler = lookup_enclosing_address_handler(&address_handler_list,
8528c2ecf20Sopenharmony_ci						   offset, request->length);
8538c2ecf20Sopenharmony_ci	if (handler)
8548c2ecf20Sopenharmony_ci		handler->address_callback(card, request,
8558c2ecf20Sopenharmony_ci					  tcode, destination, source,
8568c2ecf20Sopenharmony_ci					  p->generation, offset,
8578c2ecf20Sopenharmony_ci					  request->data, request->length,
8588c2ecf20Sopenharmony_ci					  handler->callback_data);
8598c2ecf20Sopenharmony_ci	rcu_read_unlock();
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci	if (!handler)
8628c2ecf20Sopenharmony_ci		fw_send_response(card, request, RCODE_ADDRESS_ERROR);
8638c2ecf20Sopenharmony_ci}
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_cistatic void handle_fcp_region_request(struct fw_card *card,
8668c2ecf20Sopenharmony_ci				      struct fw_packet *p,
8678c2ecf20Sopenharmony_ci				      struct fw_request *request,
8688c2ecf20Sopenharmony_ci				      unsigned long long offset)
8698c2ecf20Sopenharmony_ci{
8708c2ecf20Sopenharmony_ci	struct fw_address_handler *handler;
8718c2ecf20Sopenharmony_ci	int tcode, destination, source;
8728c2ecf20Sopenharmony_ci
8738c2ecf20Sopenharmony_ci	if ((offset != (CSR_REGISTER_BASE | CSR_FCP_COMMAND) &&
8748c2ecf20Sopenharmony_ci	     offset != (CSR_REGISTER_BASE | CSR_FCP_RESPONSE)) ||
8758c2ecf20Sopenharmony_ci	    request->length > 0x200) {
8768c2ecf20Sopenharmony_ci		fw_send_response(card, request, RCODE_ADDRESS_ERROR);
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci		return;
8798c2ecf20Sopenharmony_ci	}
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_ci	tcode       = HEADER_GET_TCODE(p->header[0]);
8828c2ecf20Sopenharmony_ci	destination = HEADER_GET_DESTINATION(p->header[0]);
8838c2ecf20Sopenharmony_ci	source      = HEADER_GET_SOURCE(p->header[1]);
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci	if (tcode != TCODE_WRITE_QUADLET_REQUEST &&
8868c2ecf20Sopenharmony_ci	    tcode != TCODE_WRITE_BLOCK_REQUEST) {
8878c2ecf20Sopenharmony_ci		fw_send_response(card, request, RCODE_TYPE_ERROR);
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci		return;
8908c2ecf20Sopenharmony_ci	}
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci	rcu_read_lock();
8938c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(handler, &address_handler_list, link) {
8948c2ecf20Sopenharmony_ci		if (is_enclosing_handler(handler, offset, request->length))
8958c2ecf20Sopenharmony_ci			handler->address_callback(card, NULL, tcode,
8968c2ecf20Sopenharmony_ci						  destination, source,
8978c2ecf20Sopenharmony_ci						  p->generation, offset,
8988c2ecf20Sopenharmony_ci						  request->data,
8998c2ecf20Sopenharmony_ci						  request->length,
9008c2ecf20Sopenharmony_ci						  handler->callback_data);
9018c2ecf20Sopenharmony_ci	}
9028c2ecf20Sopenharmony_ci	rcu_read_unlock();
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci	fw_send_response(card, request, RCODE_COMPLETE);
9058c2ecf20Sopenharmony_ci}
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_civoid fw_core_handle_request(struct fw_card *card, struct fw_packet *p)
9088c2ecf20Sopenharmony_ci{
9098c2ecf20Sopenharmony_ci	struct fw_request *request;
9108c2ecf20Sopenharmony_ci	unsigned long long offset;
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	if (p->ack != ACK_PENDING && p->ack != ACK_COMPLETE)
9138c2ecf20Sopenharmony_ci		return;
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci	if (TCODE_IS_LINK_INTERNAL(HEADER_GET_TCODE(p->header[0]))) {
9168c2ecf20Sopenharmony_ci		fw_cdev_handle_phy_packet(card, p);
9178c2ecf20Sopenharmony_ci		return;
9188c2ecf20Sopenharmony_ci	}
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ci	request = allocate_request(card, p);
9218c2ecf20Sopenharmony_ci	if (request == NULL) {
9228c2ecf20Sopenharmony_ci		/* FIXME: send statically allocated busy packet. */
9238c2ecf20Sopenharmony_ci		return;
9248c2ecf20Sopenharmony_ci	}
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci	offset = ((u64)HEADER_GET_OFFSET_HIGH(p->header[1]) << 32) |
9278c2ecf20Sopenharmony_ci		p->header[2];
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_ci	if (!is_in_fcp_region(offset, request->length))
9308c2ecf20Sopenharmony_ci		handle_exclusive_region_request(card, p, request, offset);
9318c2ecf20Sopenharmony_ci	else
9328c2ecf20Sopenharmony_ci		handle_fcp_region_request(card, p, request, offset);
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ci}
9358c2ecf20Sopenharmony_ciEXPORT_SYMBOL(fw_core_handle_request);
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_civoid fw_core_handle_response(struct fw_card *card, struct fw_packet *p)
9388c2ecf20Sopenharmony_ci{
9398c2ecf20Sopenharmony_ci	struct fw_transaction *t = NULL, *iter;
9408c2ecf20Sopenharmony_ci	unsigned long flags;
9418c2ecf20Sopenharmony_ci	u32 *data;
9428c2ecf20Sopenharmony_ci	size_t data_length;
9438c2ecf20Sopenharmony_ci	int tcode, tlabel, source, rcode;
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci	tcode	= HEADER_GET_TCODE(p->header[0]);
9468c2ecf20Sopenharmony_ci	tlabel	= HEADER_GET_TLABEL(p->header[0]);
9478c2ecf20Sopenharmony_ci	source	= HEADER_GET_SOURCE(p->header[1]);
9488c2ecf20Sopenharmony_ci	rcode	= HEADER_GET_RCODE(p->header[1]);
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_ci	spin_lock_irqsave(&card->lock, flags);
9518c2ecf20Sopenharmony_ci	list_for_each_entry(iter, &card->transaction_list, link) {
9528c2ecf20Sopenharmony_ci		if (iter->node_id == source && iter->tlabel == tlabel) {
9538c2ecf20Sopenharmony_ci			if (!try_cancel_split_timeout(iter)) {
9548c2ecf20Sopenharmony_ci				spin_unlock_irqrestore(&card->lock, flags);
9558c2ecf20Sopenharmony_ci				goto timed_out;
9568c2ecf20Sopenharmony_ci			}
9578c2ecf20Sopenharmony_ci			list_del_init(&iter->link);
9588c2ecf20Sopenharmony_ci			card->tlabel_mask &= ~(1ULL << iter->tlabel);
9598c2ecf20Sopenharmony_ci			t = iter;
9608c2ecf20Sopenharmony_ci			break;
9618c2ecf20Sopenharmony_ci		}
9628c2ecf20Sopenharmony_ci	}
9638c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&card->lock, flags);
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci	if (!t) {
9668c2ecf20Sopenharmony_ci timed_out:
9678c2ecf20Sopenharmony_ci		fw_notice(card, "unsolicited response (source %x, tlabel %x)\n",
9688c2ecf20Sopenharmony_ci			  source, tlabel);
9698c2ecf20Sopenharmony_ci		return;
9708c2ecf20Sopenharmony_ci	}
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_ci	/*
9738c2ecf20Sopenharmony_ci	 * FIXME: sanity check packet, is length correct, does tcodes
9748c2ecf20Sopenharmony_ci	 * and addresses match.
9758c2ecf20Sopenharmony_ci	 */
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_ci	switch (tcode) {
9788c2ecf20Sopenharmony_ci	case TCODE_READ_QUADLET_RESPONSE:
9798c2ecf20Sopenharmony_ci		data = (u32 *) &p->header[3];
9808c2ecf20Sopenharmony_ci		data_length = 4;
9818c2ecf20Sopenharmony_ci		break;
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci	case TCODE_WRITE_RESPONSE:
9848c2ecf20Sopenharmony_ci		data = NULL;
9858c2ecf20Sopenharmony_ci		data_length = 0;
9868c2ecf20Sopenharmony_ci		break;
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci	case TCODE_READ_BLOCK_RESPONSE:
9898c2ecf20Sopenharmony_ci	case TCODE_LOCK_RESPONSE:
9908c2ecf20Sopenharmony_ci		data = p->payload;
9918c2ecf20Sopenharmony_ci		data_length = HEADER_GET_DATA_LENGTH(p->header[3]);
9928c2ecf20Sopenharmony_ci		break;
9938c2ecf20Sopenharmony_ci
9948c2ecf20Sopenharmony_ci	default:
9958c2ecf20Sopenharmony_ci		/* Should never happen, this is just to shut up gcc. */
9968c2ecf20Sopenharmony_ci		data = NULL;
9978c2ecf20Sopenharmony_ci		data_length = 0;
9988c2ecf20Sopenharmony_ci		break;
9998c2ecf20Sopenharmony_ci	}
10008c2ecf20Sopenharmony_ci
10018c2ecf20Sopenharmony_ci	/*
10028c2ecf20Sopenharmony_ci	 * The response handler may be executed while the request handler
10038c2ecf20Sopenharmony_ci	 * is still pending.  Cancel the request handler.
10048c2ecf20Sopenharmony_ci	 */
10058c2ecf20Sopenharmony_ci	card->driver->cancel_packet(card, &t->packet);
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_ci	t->callback(card, rcode, data, data_length, t->callback_data);
10088c2ecf20Sopenharmony_ci}
10098c2ecf20Sopenharmony_ciEXPORT_SYMBOL(fw_core_handle_response);
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_ci/**
10128c2ecf20Sopenharmony_ci * fw_rcode_string - convert a firewire result code to an error description
10138c2ecf20Sopenharmony_ci * @rcode: the result code
10148c2ecf20Sopenharmony_ci */
10158c2ecf20Sopenharmony_ciconst char *fw_rcode_string(int rcode)
10168c2ecf20Sopenharmony_ci{
10178c2ecf20Sopenharmony_ci	static const char *const names[] = {
10188c2ecf20Sopenharmony_ci		[RCODE_COMPLETE]       = "no error",
10198c2ecf20Sopenharmony_ci		[RCODE_CONFLICT_ERROR] = "conflict error",
10208c2ecf20Sopenharmony_ci		[RCODE_DATA_ERROR]     = "data error",
10218c2ecf20Sopenharmony_ci		[RCODE_TYPE_ERROR]     = "type error",
10228c2ecf20Sopenharmony_ci		[RCODE_ADDRESS_ERROR]  = "address error",
10238c2ecf20Sopenharmony_ci		[RCODE_SEND_ERROR]     = "send error",
10248c2ecf20Sopenharmony_ci		[RCODE_CANCELLED]      = "timeout",
10258c2ecf20Sopenharmony_ci		[RCODE_BUSY]           = "busy",
10268c2ecf20Sopenharmony_ci		[RCODE_GENERATION]     = "bus reset",
10278c2ecf20Sopenharmony_ci		[RCODE_NO_ACK]         = "no ack",
10288c2ecf20Sopenharmony_ci	};
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci	if ((unsigned int)rcode < ARRAY_SIZE(names) && names[rcode])
10318c2ecf20Sopenharmony_ci		return names[rcode];
10328c2ecf20Sopenharmony_ci	else
10338c2ecf20Sopenharmony_ci		return "unknown";
10348c2ecf20Sopenharmony_ci}
10358c2ecf20Sopenharmony_ciEXPORT_SYMBOL(fw_rcode_string);
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_cistatic const struct fw_address_region topology_map_region =
10388c2ecf20Sopenharmony_ci	{ .start = CSR_REGISTER_BASE | CSR_TOPOLOGY_MAP,
10398c2ecf20Sopenharmony_ci	  .end   = CSR_REGISTER_BASE | CSR_TOPOLOGY_MAP_END, };
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_cistatic void handle_topology_map(struct fw_card *card, struct fw_request *request,
10428c2ecf20Sopenharmony_ci		int tcode, int destination, int source, int generation,
10438c2ecf20Sopenharmony_ci		unsigned long long offset, void *payload, size_t length,
10448c2ecf20Sopenharmony_ci		void *callback_data)
10458c2ecf20Sopenharmony_ci{
10468c2ecf20Sopenharmony_ci	int start;
10478c2ecf20Sopenharmony_ci
10488c2ecf20Sopenharmony_ci	if (!TCODE_IS_READ_REQUEST(tcode)) {
10498c2ecf20Sopenharmony_ci		fw_send_response(card, request, RCODE_TYPE_ERROR);
10508c2ecf20Sopenharmony_ci		return;
10518c2ecf20Sopenharmony_ci	}
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_ci	if ((offset & 3) > 0 || (length & 3) > 0) {
10548c2ecf20Sopenharmony_ci		fw_send_response(card, request, RCODE_ADDRESS_ERROR);
10558c2ecf20Sopenharmony_ci		return;
10568c2ecf20Sopenharmony_ci	}
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_ci	start = (offset - topology_map_region.start) / 4;
10598c2ecf20Sopenharmony_ci	memcpy(payload, &card->topology_map[start], length);
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci	fw_send_response(card, request, RCODE_COMPLETE);
10628c2ecf20Sopenharmony_ci}
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_cistatic struct fw_address_handler topology_map = {
10658c2ecf20Sopenharmony_ci	.length			= 0x400,
10668c2ecf20Sopenharmony_ci	.address_callback	= handle_topology_map,
10678c2ecf20Sopenharmony_ci};
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_cistatic const struct fw_address_region registers_region =
10708c2ecf20Sopenharmony_ci	{ .start = CSR_REGISTER_BASE,
10718c2ecf20Sopenharmony_ci	  .end   = CSR_REGISTER_BASE | CSR_CONFIG_ROM, };
10728c2ecf20Sopenharmony_ci
10738c2ecf20Sopenharmony_cistatic void update_split_timeout(struct fw_card *card)
10748c2ecf20Sopenharmony_ci{
10758c2ecf20Sopenharmony_ci	unsigned int cycles;
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_ci	cycles = card->split_timeout_hi * 8000 + (card->split_timeout_lo >> 19);
10788c2ecf20Sopenharmony_ci
10798c2ecf20Sopenharmony_ci	/* minimum per IEEE 1394, maximum which doesn't overflow OHCI */
10808c2ecf20Sopenharmony_ci	cycles = clamp(cycles, 800u, 3u * 8000u);
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_ci	card->split_timeout_cycles = cycles;
10838c2ecf20Sopenharmony_ci	card->split_timeout_jiffies = DIV_ROUND_UP(cycles * HZ, 8000);
10848c2ecf20Sopenharmony_ci}
10858c2ecf20Sopenharmony_ci
10868c2ecf20Sopenharmony_cistatic void handle_registers(struct fw_card *card, struct fw_request *request,
10878c2ecf20Sopenharmony_ci		int tcode, int destination, int source, int generation,
10888c2ecf20Sopenharmony_ci		unsigned long long offset, void *payload, size_t length,
10898c2ecf20Sopenharmony_ci		void *callback_data)
10908c2ecf20Sopenharmony_ci{
10918c2ecf20Sopenharmony_ci	int reg = offset & ~CSR_REGISTER_BASE;
10928c2ecf20Sopenharmony_ci	__be32 *data = payload;
10938c2ecf20Sopenharmony_ci	int rcode = RCODE_COMPLETE;
10948c2ecf20Sopenharmony_ci	unsigned long flags;
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci	switch (reg) {
10978c2ecf20Sopenharmony_ci	case CSR_PRIORITY_BUDGET:
10988c2ecf20Sopenharmony_ci		if (!card->priority_budget_implemented) {
10998c2ecf20Sopenharmony_ci			rcode = RCODE_ADDRESS_ERROR;
11008c2ecf20Sopenharmony_ci			break;
11018c2ecf20Sopenharmony_ci		}
11028c2ecf20Sopenharmony_ci		fallthrough;
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_ci	case CSR_NODE_IDS:
11058c2ecf20Sopenharmony_ci		/*
11068c2ecf20Sopenharmony_ci		 * per IEEE 1394-2008 8.3.22.3, not IEEE 1394.1-2004 3.2.8
11078c2ecf20Sopenharmony_ci		 * and 9.6, but interoperable with IEEE 1394.1-2004 bridges
11088c2ecf20Sopenharmony_ci		 */
11098c2ecf20Sopenharmony_ci		fallthrough;
11108c2ecf20Sopenharmony_ci
11118c2ecf20Sopenharmony_ci	case CSR_STATE_CLEAR:
11128c2ecf20Sopenharmony_ci	case CSR_STATE_SET:
11138c2ecf20Sopenharmony_ci	case CSR_CYCLE_TIME:
11148c2ecf20Sopenharmony_ci	case CSR_BUS_TIME:
11158c2ecf20Sopenharmony_ci	case CSR_BUSY_TIMEOUT:
11168c2ecf20Sopenharmony_ci		if (tcode == TCODE_READ_QUADLET_REQUEST)
11178c2ecf20Sopenharmony_ci			*data = cpu_to_be32(card->driver->read_csr(card, reg));
11188c2ecf20Sopenharmony_ci		else if (tcode == TCODE_WRITE_QUADLET_REQUEST)
11198c2ecf20Sopenharmony_ci			card->driver->write_csr(card, reg, be32_to_cpu(*data));
11208c2ecf20Sopenharmony_ci		else
11218c2ecf20Sopenharmony_ci			rcode = RCODE_TYPE_ERROR;
11228c2ecf20Sopenharmony_ci		break;
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_ci	case CSR_RESET_START:
11258c2ecf20Sopenharmony_ci		if (tcode == TCODE_WRITE_QUADLET_REQUEST)
11268c2ecf20Sopenharmony_ci			card->driver->write_csr(card, CSR_STATE_CLEAR,
11278c2ecf20Sopenharmony_ci						CSR_STATE_BIT_ABDICATE);
11288c2ecf20Sopenharmony_ci		else
11298c2ecf20Sopenharmony_ci			rcode = RCODE_TYPE_ERROR;
11308c2ecf20Sopenharmony_ci		break;
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_ci	case CSR_SPLIT_TIMEOUT_HI:
11338c2ecf20Sopenharmony_ci		if (tcode == TCODE_READ_QUADLET_REQUEST) {
11348c2ecf20Sopenharmony_ci			*data = cpu_to_be32(card->split_timeout_hi);
11358c2ecf20Sopenharmony_ci		} else if (tcode == TCODE_WRITE_QUADLET_REQUEST) {
11368c2ecf20Sopenharmony_ci			spin_lock_irqsave(&card->lock, flags);
11378c2ecf20Sopenharmony_ci			card->split_timeout_hi = be32_to_cpu(*data) & 7;
11388c2ecf20Sopenharmony_ci			update_split_timeout(card);
11398c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&card->lock, flags);
11408c2ecf20Sopenharmony_ci		} else {
11418c2ecf20Sopenharmony_ci			rcode = RCODE_TYPE_ERROR;
11428c2ecf20Sopenharmony_ci		}
11438c2ecf20Sopenharmony_ci		break;
11448c2ecf20Sopenharmony_ci
11458c2ecf20Sopenharmony_ci	case CSR_SPLIT_TIMEOUT_LO:
11468c2ecf20Sopenharmony_ci		if (tcode == TCODE_READ_QUADLET_REQUEST) {
11478c2ecf20Sopenharmony_ci			*data = cpu_to_be32(card->split_timeout_lo);
11488c2ecf20Sopenharmony_ci		} else if (tcode == TCODE_WRITE_QUADLET_REQUEST) {
11498c2ecf20Sopenharmony_ci			spin_lock_irqsave(&card->lock, flags);
11508c2ecf20Sopenharmony_ci			card->split_timeout_lo =
11518c2ecf20Sopenharmony_ci					be32_to_cpu(*data) & 0xfff80000;
11528c2ecf20Sopenharmony_ci			update_split_timeout(card);
11538c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&card->lock, flags);
11548c2ecf20Sopenharmony_ci		} else {
11558c2ecf20Sopenharmony_ci			rcode = RCODE_TYPE_ERROR;
11568c2ecf20Sopenharmony_ci		}
11578c2ecf20Sopenharmony_ci		break;
11588c2ecf20Sopenharmony_ci
11598c2ecf20Sopenharmony_ci	case CSR_MAINT_UTILITY:
11608c2ecf20Sopenharmony_ci		if (tcode == TCODE_READ_QUADLET_REQUEST)
11618c2ecf20Sopenharmony_ci			*data = card->maint_utility_register;
11628c2ecf20Sopenharmony_ci		else if (tcode == TCODE_WRITE_QUADLET_REQUEST)
11638c2ecf20Sopenharmony_ci			card->maint_utility_register = *data;
11648c2ecf20Sopenharmony_ci		else
11658c2ecf20Sopenharmony_ci			rcode = RCODE_TYPE_ERROR;
11668c2ecf20Sopenharmony_ci		break;
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_ci	case CSR_BROADCAST_CHANNEL:
11698c2ecf20Sopenharmony_ci		if (tcode == TCODE_READ_QUADLET_REQUEST)
11708c2ecf20Sopenharmony_ci			*data = cpu_to_be32(card->broadcast_channel);
11718c2ecf20Sopenharmony_ci		else if (tcode == TCODE_WRITE_QUADLET_REQUEST)
11728c2ecf20Sopenharmony_ci			card->broadcast_channel =
11738c2ecf20Sopenharmony_ci			    (be32_to_cpu(*data) & BROADCAST_CHANNEL_VALID) |
11748c2ecf20Sopenharmony_ci			    BROADCAST_CHANNEL_INITIAL;
11758c2ecf20Sopenharmony_ci		else
11768c2ecf20Sopenharmony_ci			rcode = RCODE_TYPE_ERROR;
11778c2ecf20Sopenharmony_ci		break;
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_ci	case CSR_BUS_MANAGER_ID:
11808c2ecf20Sopenharmony_ci	case CSR_BANDWIDTH_AVAILABLE:
11818c2ecf20Sopenharmony_ci	case CSR_CHANNELS_AVAILABLE_HI:
11828c2ecf20Sopenharmony_ci	case CSR_CHANNELS_AVAILABLE_LO:
11838c2ecf20Sopenharmony_ci		/*
11848c2ecf20Sopenharmony_ci		 * FIXME: these are handled by the OHCI hardware and
11858c2ecf20Sopenharmony_ci		 * the stack never sees these request. If we add
11868c2ecf20Sopenharmony_ci		 * support for a new type of controller that doesn't
11878c2ecf20Sopenharmony_ci		 * handle this in hardware we need to deal with these
11888c2ecf20Sopenharmony_ci		 * transactions.
11898c2ecf20Sopenharmony_ci		 */
11908c2ecf20Sopenharmony_ci		BUG();
11918c2ecf20Sopenharmony_ci		break;
11928c2ecf20Sopenharmony_ci
11938c2ecf20Sopenharmony_ci	default:
11948c2ecf20Sopenharmony_ci		rcode = RCODE_ADDRESS_ERROR;
11958c2ecf20Sopenharmony_ci		break;
11968c2ecf20Sopenharmony_ci	}
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_ci	fw_send_response(card, request, rcode);
11998c2ecf20Sopenharmony_ci}
12008c2ecf20Sopenharmony_ci
12018c2ecf20Sopenharmony_cistatic struct fw_address_handler registers = {
12028c2ecf20Sopenharmony_ci	.length			= 0x400,
12038c2ecf20Sopenharmony_ci	.address_callback	= handle_registers,
12048c2ecf20Sopenharmony_ci};
12058c2ecf20Sopenharmony_ci
12068c2ecf20Sopenharmony_cistatic void handle_low_memory(struct fw_card *card, struct fw_request *request,
12078c2ecf20Sopenharmony_ci		int tcode, int destination, int source, int generation,
12088c2ecf20Sopenharmony_ci		unsigned long long offset, void *payload, size_t length,
12098c2ecf20Sopenharmony_ci		void *callback_data)
12108c2ecf20Sopenharmony_ci{
12118c2ecf20Sopenharmony_ci	/*
12128c2ecf20Sopenharmony_ci	 * This catches requests not handled by the physical DMA unit,
12138c2ecf20Sopenharmony_ci	 * i.e., wrong transaction types or unauthorized source nodes.
12148c2ecf20Sopenharmony_ci	 */
12158c2ecf20Sopenharmony_ci	fw_send_response(card, request, RCODE_TYPE_ERROR);
12168c2ecf20Sopenharmony_ci}
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_cistatic struct fw_address_handler low_memory = {
12198c2ecf20Sopenharmony_ci	.length			= FW_MAX_PHYSICAL_RANGE,
12208c2ecf20Sopenharmony_ci	.address_callback	= handle_low_memory,
12218c2ecf20Sopenharmony_ci};
12228c2ecf20Sopenharmony_ci
12238c2ecf20Sopenharmony_ciMODULE_AUTHOR("Kristian Hoegsberg <krh@bitplanet.net>");
12248c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Core IEEE1394 transaction logic");
12258c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
12268c2ecf20Sopenharmony_ci
12278c2ecf20Sopenharmony_cistatic const u32 vendor_textual_descriptor[] = {
12288c2ecf20Sopenharmony_ci	/* textual descriptor leaf () */
12298c2ecf20Sopenharmony_ci	0x00060000,
12308c2ecf20Sopenharmony_ci	0x00000000,
12318c2ecf20Sopenharmony_ci	0x00000000,
12328c2ecf20Sopenharmony_ci	0x4c696e75,		/* L i n u */
12338c2ecf20Sopenharmony_ci	0x78204669,		/* x   F i */
12348c2ecf20Sopenharmony_ci	0x72657769,		/* r e w i */
12358c2ecf20Sopenharmony_ci	0x72650000,		/* r e     */
12368c2ecf20Sopenharmony_ci};
12378c2ecf20Sopenharmony_ci
12388c2ecf20Sopenharmony_cistatic const u32 model_textual_descriptor[] = {
12398c2ecf20Sopenharmony_ci	/* model descriptor leaf () */
12408c2ecf20Sopenharmony_ci	0x00030000,
12418c2ecf20Sopenharmony_ci	0x00000000,
12428c2ecf20Sopenharmony_ci	0x00000000,
12438c2ecf20Sopenharmony_ci	0x4a756a75,		/* J u j u */
12448c2ecf20Sopenharmony_ci};
12458c2ecf20Sopenharmony_ci
12468c2ecf20Sopenharmony_cistatic struct fw_descriptor vendor_id_descriptor = {
12478c2ecf20Sopenharmony_ci	.length = ARRAY_SIZE(vendor_textual_descriptor),
12488c2ecf20Sopenharmony_ci	.immediate = 0x03001f11,
12498c2ecf20Sopenharmony_ci	.key = 0x81000000,
12508c2ecf20Sopenharmony_ci	.data = vendor_textual_descriptor,
12518c2ecf20Sopenharmony_ci};
12528c2ecf20Sopenharmony_ci
12538c2ecf20Sopenharmony_cistatic struct fw_descriptor model_id_descriptor = {
12548c2ecf20Sopenharmony_ci	.length = ARRAY_SIZE(model_textual_descriptor),
12558c2ecf20Sopenharmony_ci	.immediate = 0x17023901,
12568c2ecf20Sopenharmony_ci	.key = 0x81000000,
12578c2ecf20Sopenharmony_ci	.data = model_textual_descriptor,
12588c2ecf20Sopenharmony_ci};
12598c2ecf20Sopenharmony_ci
12608c2ecf20Sopenharmony_cistatic int __init fw_core_init(void)
12618c2ecf20Sopenharmony_ci{
12628c2ecf20Sopenharmony_ci	int ret;
12638c2ecf20Sopenharmony_ci
12648c2ecf20Sopenharmony_ci	fw_workqueue = alloc_workqueue("firewire", WQ_MEM_RECLAIM, 0);
12658c2ecf20Sopenharmony_ci	if (!fw_workqueue)
12668c2ecf20Sopenharmony_ci		return -ENOMEM;
12678c2ecf20Sopenharmony_ci
12688c2ecf20Sopenharmony_ci	ret = bus_register(&fw_bus_type);
12698c2ecf20Sopenharmony_ci	if (ret < 0) {
12708c2ecf20Sopenharmony_ci		destroy_workqueue(fw_workqueue);
12718c2ecf20Sopenharmony_ci		return ret;
12728c2ecf20Sopenharmony_ci	}
12738c2ecf20Sopenharmony_ci
12748c2ecf20Sopenharmony_ci	fw_cdev_major = register_chrdev(0, "firewire", &fw_device_ops);
12758c2ecf20Sopenharmony_ci	if (fw_cdev_major < 0) {
12768c2ecf20Sopenharmony_ci		bus_unregister(&fw_bus_type);
12778c2ecf20Sopenharmony_ci		destroy_workqueue(fw_workqueue);
12788c2ecf20Sopenharmony_ci		return fw_cdev_major;
12798c2ecf20Sopenharmony_ci	}
12808c2ecf20Sopenharmony_ci
12818c2ecf20Sopenharmony_ci	fw_core_add_address_handler(&topology_map, &topology_map_region);
12828c2ecf20Sopenharmony_ci	fw_core_add_address_handler(&registers, &registers_region);
12838c2ecf20Sopenharmony_ci	fw_core_add_address_handler(&low_memory, &low_memory_region);
12848c2ecf20Sopenharmony_ci	fw_core_add_descriptor(&vendor_id_descriptor);
12858c2ecf20Sopenharmony_ci	fw_core_add_descriptor(&model_id_descriptor);
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_ci	return 0;
12888c2ecf20Sopenharmony_ci}
12898c2ecf20Sopenharmony_ci
12908c2ecf20Sopenharmony_cistatic void __exit fw_core_cleanup(void)
12918c2ecf20Sopenharmony_ci{
12928c2ecf20Sopenharmony_ci	unregister_chrdev(fw_cdev_major, "firewire");
12938c2ecf20Sopenharmony_ci	bus_unregister(&fw_bus_type);
12948c2ecf20Sopenharmony_ci	destroy_workqueue(fw_workqueue);
12958c2ecf20Sopenharmony_ci	idr_destroy(&fw_device_idr);
12968c2ecf20Sopenharmony_ci}
12978c2ecf20Sopenharmony_ci
12988c2ecf20Sopenharmony_cimodule_init(fw_core_init);
12998c2ecf20Sopenharmony_cimodule_exit(fw_core_cleanup);
1300