Path: blob/master/drivers/firewire/core-transaction.c
15109 views
/*1* Core IEEE1394 transaction logic2*3* Copyright (C) 2004-2006 Kristian Hoegsberg <[email protected]>4*5* This program is free software; you can redistribute it and/or modify6* it under the terms of the GNU General Public License as published by7* the Free Software Foundation; either version 2 of the License, or8* (at your option) any later version.9*10* This program is distributed in the hope that it will be useful,11* but WITHOUT ANY WARRANTY; without even the implied warranty of12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13* GNU General Public License for more details.14*15* You should have received a copy of the GNU General Public License16* along with this program; if not, write to the Free Software Foundation,17* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.18*/1920#include <linux/bug.h>21#include <linux/completion.h>22#include <linux/device.h>23#include <linux/errno.h>24#include <linux/firewire.h>25#include <linux/firewire-constants.h>26#include <linux/fs.h>27#include <linux/init.h>28#include <linux/idr.h>29#include <linux/jiffies.h>30#include <linux/kernel.h>31#include <linux/list.h>32#include <linux/module.h>33#include <linux/slab.h>34#include <linux/spinlock.h>35#include <linux/string.h>36#include <linux/timer.h>37#include <linux/types.h>38#include <linux/workqueue.h>3940#include <asm/byteorder.h>4142#include "core.h"4344#define HEADER_PRI(pri) ((pri) << 0)45#define HEADER_TCODE(tcode) ((tcode) << 4)46#define HEADER_RETRY(retry) ((retry) << 8)47#define HEADER_TLABEL(tlabel) ((tlabel) << 10)48#define HEADER_DESTINATION(destination) ((destination) << 16)49#define HEADER_SOURCE(source) ((source) << 16)50#define HEADER_RCODE(rcode) ((rcode) << 12)51#define HEADER_OFFSET_HIGH(offset_high) ((offset_high) << 0)52#define HEADER_DATA_LENGTH(length) ((length) << 16)53#define HEADER_EXTENDED_TCODE(tcode) ((tcode) << 0)5455#define HEADER_GET_TCODE(q) (((q) >> 4) & 0x0f)56#define HEADER_GET_TLABEL(q) (((q) >> 10) & 0x3f)57#define HEADER_GET_RCODE(q) (((q) >> 12) & 0x0f)58#define HEADER_GET_DESTINATION(q) (((q) >> 16) & 0xffff)59#define HEADER_GET_SOURCE(q) (((q) >> 16) & 0xffff)60#define HEADER_GET_OFFSET_HIGH(q) (((q) >> 0) & 0xffff)61#define HEADER_GET_DATA_LENGTH(q) (((q) >> 16) & 0xffff)62#define HEADER_GET_EXTENDED_TCODE(q) (((q) >> 0) & 0xffff)6364#define HEADER_DESTINATION_IS_BROADCAST(q) \65(((q) & HEADER_DESTINATION(0x3f)) == HEADER_DESTINATION(0x3f))6667#define PHY_PACKET_CONFIG 0x068#define PHY_PACKET_LINK_ON 0x169#define PHY_PACKET_SELF_ID 0x27071#define PHY_CONFIG_GAP_COUNT(gap_count) (((gap_count) << 16) | (1 << 22))72#define PHY_CONFIG_ROOT_ID(node_id) ((((node_id) & 0x3f) << 24) | (1 << 23))73#define PHY_IDENTIFIER(id) ((id) << 30)7475/* returns 0 if the split timeout handler is already running */76static int try_cancel_split_timeout(struct fw_transaction *t)77{78if (t->is_split_transaction)79return del_timer(&t->split_timeout_timer);80else81return 1;82}8384static int close_transaction(struct fw_transaction *transaction,85struct fw_card *card, int rcode)86{87struct fw_transaction *t;88unsigned long flags;8990spin_lock_irqsave(&card->lock, flags);91list_for_each_entry(t, &card->transaction_list, link) {92if (t == transaction) {93if (!try_cancel_split_timeout(t)) {94spin_unlock_irqrestore(&card->lock, flags);95goto timed_out;96}97list_del_init(&t->link);98card->tlabel_mask &= ~(1ULL << t->tlabel);99break;100}101}102spin_unlock_irqrestore(&card->lock, flags);103104if (&t->link != &card->transaction_list) {105t->callback(card, rcode, NULL, 0, t->callback_data);106return 0;107}108109timed_out:110return -ENOENT;111}112113/*114* Only valid for transactions that are potentially pending (ie have115* been sent).116*/117int fw_cancel_transaction(struct fw_card *card,118struct fw_transaction *transaction)119{120/*121* Cancel the packet transmission if it's still queued. That122* will call the packet transmission callback which cancels123* the transaction.124*/125126if (card->driver->cancel_packet(card, &transaction->packet) == 0)127return 0;128129/*130* If the request packet has already been sent, we need to see131* if the transaction is still pending and remove it in that case.132*/133134return close_transaction(transaction, card, RCODE_CANCELLED);135}136EXPORT_SYMBOL(fw_cancel_transaction);137138static void split_transaction_timeout_callback(unsigned long data)139{140struct fw_transaction *t = (struct fw_transaction *)data;141struct fw_card *card = t->card;142unsigned long flags;143144spin_lock_irqsave(&card->lock, flags);145if (list_empty(&t->link)) {146spin_unlock_irqrestore(&card->lock, flags);147return;148}149list_del(&t->link);150card->tlabel_mask &= ~(1ULL << t->tlabel);151spin_unlock_irqrestore(&card->lock, flags);152153t->callback(card, RCODE_CANCELLED, NULL, 0, t->callback_data);154}155156static void start_split_transaction_timeout(struct fw_transaction *t,157struct fw_card *card)158{159unsigned long flags;160161spin_lock_irqsave(&card->lock, flags);162163if (list_empty(&t->link) || WARN_ON(t->is_split_transaction)) {164spin_unlock_irqrestore(&card->lock, flags);165return;166}167168t->is_split_transaction = true;169mod_timer(&t->split_timeout_timer,170jiffies + card->split_timeout_jiffies);171172spin_unlock_irqrestore(&card->lock, flags);173}174175static void transmit_complete_callback(struct fw_packet *packet,176struct fw_card *card, int status)177{178struct fw_transaction *t =179container_of(packet, struct fw_transaction, packet);180181switch (status) {182case ACK_COMPLETE:183close_transaction(t, card, RCODE_COMPLETE);184break;185case ACK_PENDING:186start_split_transaction_timeout(t, card);187break;188case ACK_BUSY_X:189case ACK_BUSY_A:190case ACK_BUSY_B:191close_transaction(t, card, RCODE_BUSY);192break;193case ACK_DATA_ERROR:194close_transaction(t, card, RCODE_DATA_ERROR);195break;196case ACK_TYPE_ERROR:197close_transaction(t, card, RCODE_TYPE_ERROR);198break;199default:200/*201* In this case the ack is really a juju specific202* rcode, so just forward that to the callback.203*/204close_transaction(t, card, status);205break;206}207}208209static void fw_fill_request(struct fw_packet *packet, int tcode, int tlabel,210int destination_id, int source_id, int generation, int speed,211unsigned long long offset, void *payload, size_t length)212{213int ext_tcode;214215if (tcode == TCODE_STREAM_DATA) {216packet->header[0] =217HEADER_DATA_LENGTH(length) |218destination_id |219HEADER_TCODE(TCODE_STREAM_DATA);220packet->header_length = 4;221packet->payload = payload;222packet->payload_length = length;223224goto common;225}226227if (tcode > 0x10) {228ext_tcode = tcode & ~0x10;229tcode = TCODE_LOCK_REQUEST;230} else231ext_tcode = 0;232233packet->header[0] =234HEADER_RETRY(RETRY_X) |235HEADER_TLABEL(tlabel) |236HEADER_TCODE(tcode) |237HEADER_DESTINATION(destination_id);238packet->header[1] =239HEADER_OFFSET_HIGH(offset >> 32) | HEADER_SOURCE(source_id);240packet->header[2] =241offset;242243switch (tcode) {244case TCODE_WRITE_QUADLET_REQUEST:245packet->header[3] = *(u32 *)payload;246packet->header_length = 16;247packet->payload_length = 0;248break;249250case TCODE_LOCK_REQUEST:251case TCODE_WRITE_BLOCK_REQUEST:252packet->header[3] =253HEADER_DATA_LENGTH(length) |254HEADER_EXTENDED_TCODE(ext_tcode);255packet->header_length = 16;256packet->payload = payload;257packet->payload_length = length;258break;259260case TCODE_READ_QUADLET_REQUEST:261packet->header_length = 12;262packet->payload_length = 0;263break;264265case TCODE_READ_BLOCK_REQUEST:266packet->header[3] =267HEADER_DATA_LENGTH(length) |268HEADER_EXTENDED_TCODE(ext_tcode);269packet->header_length = 16;270packet->payload_length = 0;271break;272273default:274WARN(1, "wrong tcode %d\n", tcode);275}276common:277packet->speed = speed;278packet->generation = generation;279packet->ack = 0;280packet->payload_mapped = false;281}282283static int allocate_tlabel(struct fw_card *card)284{285int tlabel;286287tlabel = card->current_tlabel;288while (card->tlabel_mask & (1ULL << tlabel)) {289tlabel = (tlabel + 1) & 0x3f;290if (tlabel == card->current_tlabel)291return -EBUSY;292}293294card->current_tlabel = (tlabel + 1) & 0x3f;295card->tlabel_mask |= 1ULL << tlabel;296297return tlabel;298}299300/**301* fw_send_request() - submit a request packet for transmission302* @card: interface to send the request at303* @t: transaction instance to which the request belongs304* @tcode: transaction code305* @destination_id: destination node ID, consisting of bus_ID and phy_ID306* @generation: bus generation in which request and response are valid307* @speed: transmission speed308* @offset: 48bit wide offset into destination's address space309* @payload: data payload for the request subaction310* @length: length of the payload, in bytes311* @callback: function to be called when the transaction is completed312* @callback_data: data to be passed to the transaction completion callback313*314* Submit a request packet into the asynchronous request transmission queue.315* Can be called from atomic context. If you prefer a blocking API, use316* fw_run_transaction() in a context that can sleep.317*318* In case of lock requests, specify one of the firewire-core specific %TCODE_319* constants instead of %TCODE_LOCK_REQUEST in @tcode.320*321* Make sure that the value in @destination_id is not older than the one in322* @generation. Otherwise the request is in danger to be sent to a wrong node.323*324* In case of asynchronous stream packets i.e. %TCODE_STREAM_DATA, the caller325* needs to synthesize @destination_id with fw_stream_packet_destination_id().326* It will contain tag, channel, and sy data instead of a node ID then.327*328* The payload buffer at @data is going to be DMA-mapped except in case of329* @length <= 8 or of local (loopback) requests. Hence make sure that the330* buffer complies with the restrictions of the streaming DMA mapping API.331* @payload must not be freed before the @callback is called.332*333* In case of request types without payload, @data is NULL and @length is 0.334*335* After the transaction is completed successfully or unsuccessfully, the336* @callback will be called. Among its parameters is the response code which337* is either one of the rcodes per IEEE 1394 or, in case of internal errors,338* the firewire-core specific %RCODE_SEND_ERROR. The other firewire-core339* specific rcodes (%RCODE_CANCELLED, %RCODE_BUSY, %RCODE_GENERATION,340* %RCODE_NO_ACK) denote transaction timeout, busy responder, stale request341* generation, or missing ACK respectively.342*343* Note some timing corner cases: fw_send_request() may complete much earlier344* than when the request packet actually hits the wire. On the other hand,345* transaction completion and hence execution of @callback may happen even346* before fw_send_request() returns.347*/348void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode,349int destination_id, int generation, int speed,350unsigned long long offset, void *payload, size_t length,351fw_transaction_callback_t callback, void *callback_data)352{353unsigned long flags;354int tlabel;355356/*357* Allocate tlabel from the bitmap and put the transaction on358* the list while holding the card spinlock.359*/360361spin_lock_irqsave(&card->lock, flags);362363tlabel = allocate_tlabel(card);364if (tlabel < 0) {365spin_unlock_irqrestore(&card->lock, flags);366callback(card, RCODE_SEND_ERROR, NULL, 0, callback_data);367return;368}369370t->node_id = destination_id;371t->tlabel = tlabel;372t->card = card;373t->is_split_transaction = false;374setup_timer(&t->split_timeout_timer,375split_transaction_timeout_callback, (unsigned long)t);376t->callback = callback;377t->callback_data = callback_data;378379fw_fill_request(&t->packet, tcode, t->tlabel,380destination_id, card->node_id, generation,381speed, offset, payload, length);382t->packet.callback = transmit_complete_callback;383384list_add_tail(&t->link, &card->transaction_list);385386spin_unlock_irqrestore(&card->lock, flags);387388card->driver->send_request(card, &t->packet);389}390EXPORT_SYMBOL(fw_send_request);391392struct transaction_callback_data {393struct completion done;394void *payload;395int rcode;396};397398static void transaction_callback(struct fw_card *card, int rcode,399void *payload, size_t length, void *data)400{401struct transaction_callback_data *d = data;402403if (rcode == RCODE_COMPLETE)404memcpy(d->payload, payload, length);405d->rcode = rcode;406complete(&d->done);407}408409/**410* fw_run_transaction() - send request and sleep until transaction is completed411*412* Returns the RCODE. See fw_send_request() for parameter documentation.413* Unlike fw_send_request(), @data points to the payload of the request or/and414* to the payload of the response. DMA mapping restrictions apply to outbound415* request payloads of >= 8 bytes but not to inbound response payloads.416*/417int fw_run_transaction(struct fw_card *card, int tcode, int destination_id,418int generation, int speed, unsigned long long offset,419void *payload, size_t length)420{421struct transaction_callback_data d;422struct fw_transaction t;423424init_timer_on_stack(&t.split_timeout_timer);425init_completion(&d.done);426d.payload = payload;427fw_send_request(card, &t, tcode, destination_id, generation, speed,428offset, payload, length, transaction_callback, &d);429wait_for_completion(&d.done);430destroy_timer_on_stack(&t.split_timeout_timer);431432return d.rcode;433}434EXPORT_SYMBOL(fw_run_transaction);435436static DEFINE_MUTEX(phy_config_mutex);437static DECLARE_COMPLETION(phy_config_done);438439static void transmit_phy_packet_callback(struct fw_packet *packet,440struct fw_card *card, int status)441{442complete(&phy_config_done);443}444445static struct fw_packet phy_config_packet = {446.header_length = 12,447.header[0] = TCODE_LINK_INTERNAL << 4,448.payload_length = 0,449.speed = SCODE_100,450.callback = transmit_phy_packet_callback,451};452453void fw_send_phy_config(struct fw_card *card,454int node_id, int generation, int gap_count)455{456long timeout = DIV_ROUND_UP(HZ, 10);457u32 data = PHY_IDENTIFIER(PHY_PACKET_CONFIG);458459if (node_id != FW_PHY_CONFIG_NO_NODE_ID)460data |= PHY_CONFIG_ROOT_ID(node_id);461462if (gap_count == FW_PHY_CONFIG_CURRENT_GAP_COUNT) {463gap_count = card->driver->read_phy_reg(card, 1);464if (gap_count < 0)465return;466467gap_count &= 63;468if (gap_count == 63)469return;470}471data |= PHY_CONFIG_GAP_COUNT(gap_count);472473mutex_lock(&phy_config_mutex);474475phy_config_packet.header[1] = data;476phy_config_packet.header[2] = ~data;477phy_config_packet.generation = generation;478INIT_COMPLETION(phy_config_done);479480card->driver->send_request(card, &phy_config_packet);481wait_for_completion_timeout(&phy_config_done, timeout);482483mutex_unlock(&phy_config_mutex);484}485486static struct fw_address_handler *lookup_overlapping_address_handler(487struct list_head *list, unsigned long long offset, size_t length)488{489struct fw_address_handler *handler;490491list_for_each_entry(handler, list, link) {492if (handler->offset < offset + length &&493offset < handler->offset + handler->length)494return handler;495}496497return NULL;498}499500static bool is_enclosing_handler(struct fw_address_handler *handler,501unsigned long long offset, size_t length)502{503return handler->offset <= offset &&504offset + length <= handler->offset + handler->length;505}506507static struct fw_address_handler *lookup_enclosing_address_handler(508struct list_head *list, unsigned long long offset, size_t length)509{510struct fw_address_handler *handler;511512list_for_each_entry(handler, list, link) {513if (is_enclosing_handler(handler, offset, length))514return handler;515}516517return NULL;518}519520static DEFINE_SPINLOCK(address_handler_lock);521static LIST_HEAD(address_handler_list);522523const struct fw_address_region fw_high_memory_region =524{ .start = 0x000100000000ULL, .end = 0xffffe0000000ULL, };525EXPORT_SYMBOL(fw_high_memory_region);526527#if 0528const struct fw_address_region fw_low_memory_region =529{ .start = 0x000000000000ULL, .end = 0x000100000000ULL, };530const struct fw_address_region fw_private_region =531{ .start = 0xffffe0000000ULL, .end = 0xfffff0000000ULL, };532const struct fw_address_region fw_csr_region =533{ .start = CSR_REGISTER_BASE,534.end = CSR_REGISTER_BASE | CSR_CONFIG_ROM_END, };535const struct fw_address_region fw_unit_space_region =536{ .start = 0xfffff0000900ULL, .end = 0x1000000000000ULL, };537#endif /* 0 */538539static bool is_in_fcp_region(u64 offset, size_t length)540{541return offset >= (CSR_REGISTER_BASE | CSR_FCP_COMMAND) &&542offset + length <= (CSR_REGISTER_BASE | CSR_FCP_END);543}544545/**546* fw_core_add_address_handler() - register for incoming requests547* @handler: callback548* @region: region in the IEEE 1212 node space address range549*550* region->start, ->end, and handler->length have to be quadlet-aligned.551*552* When a request is received that falls within the specified address range,553* the specified callback is invoked. The parameters passed to the callback554* give the details of the particular request.555*556* Return value: 0 on success, non-zero otherwise.557*558* The start offset of the handler's address region is determined by559* fw_core_add_address_handler() and is returned in handler->offset.560*561* Address allocations are exclusive, except for the FCP registers.562*/563int fw_core_add_address_handler(struct fw_address_handler *handler,564const struct fw_address_region *region)565{566struct fw_address_handler *other;567unsigned long flags;568int ret = -EBUSY;569570if (region->start & 0xffff000000000003ULL ||571region->start >= region->end ||572region->end > 0x0001000000000000ULL ||573handler->length & 3 ||574handler->length == 0)575return -EINVAL;576577spin_lock_irqsave(&address_handler_lock, flags);578579handler->offset = region->start;580while (handler->offset + handler->length <= region->end) {581if (is_in_fcp_region(handler->offset, handler->length))582other = NULL;583else584other = lookup_overlapping_address_handler585(&address_handler_list,586handler->offset, handler->length);587if (other != NULL) {588handler->offset += other->length;589} else {590list_add_tail(&handler->link, &address_handler_list);591ret = 0;592break;593}594}595596spin_unlock_irqrestore(&address_handler_lock, flags);597598return ret;599}600EXPORT_SYMBOL(fw_core_add_address_handler);601602/**603* fw_core_remove_address_handler() - unregister an address handler604*/605void fw_core_remove_address_handler(struct fw_address_handler *handler)606{607unsigned long flags;608609spin_lock_irqsave(&address_handler_lock, flags);610list_del(&handler->link);611spin_unlock_irqrestore(&address_handler_lock, flags);612}613EXPORT_SYMBOL(fw_core_remove_address_handler);614615struct fw_request {616struct fw_packet response;617u32 request_header[4];618int ack;619u32 length;620u32 data[0];621};622623static void free_response_callback(struct fw_packet *packet,624struct fw_card *card, int status)625{626struct fw_request *request;627628request = container_of(packet, struct fw_request, response);629kfree(request);630}631632int fw_get_response_length(struct fw_request *r)633{634int tcode, ext_tcode, data_length;635636tcode = HEADER_GET_TCODE(r->request_header[0]);637638switch (tcode) {639case TCODE_WRITE_QUADLET_REQUEST:640case TCODE_WRITE_BLOCK_REQUEST:641return 0;642643case TCODE_READ_QUADLET_REQUEST:644return 4;645646case TCODE_READ_BLOCK_REQUEST:647data_length = HEADER_GET_DATA_LENGTH(r->request_header[3]);648return data_length;649650case TCODE_LOCK_REQUEST:651ext_tcode = HEADER_GET_EXTENDED_TCODE(r->request_header[3]);652data_length = HEADER_GET_DATA_LENGTH(r->request_header[3]);653switch (ext_tcode) {654case EXTCODE_FETCH_ADD:655case EXTCODE_LITTLE_ADD:656return data_length;657default:658return data_length / 2;659}660661default:662WARN(1, "wrong tcode %d\n", tcode);663return 0;664}665}666667void fw_fill_response(struct fw_packet *response, u32 *request_header,668int rcode, void *payload, size_t length)669{670int tcode, tlabel, extended_tcode, source, destination;671672tcode = HEADER_GET_TCODE(request_header[0]);673tlabel = HEADER_GET_TLABEL(request_header[0]);674source = HEADER_GET_DESTINATION(request_header[0]);675destination = HEADER_GET_SOURCE(request_header[1]);676extended_tcode = HEADER_GET_EXTENDED_TCODE(request_header[3]);677678response->header[0] =679HEADER_RETRY(RETRY_1) |680HEADER_TLABEL(tlabel) |681HEADER_DESTINATION(destination);682response->header[1] =683HEADER_SOURCE(source) |684HEADER_RCODE(rcode);685response->header[2] = 0;686687switch (tcode) {688case TCODE_WRITE_QUADLET_REQUEST:689case TCODE_WRITE_BLOCK_REQUEST:690response->header[0] |= HEADER_TCODE(TCODE_WRITE_RESPONSE);691response->header_length = 12;692response->payload_length = 0;693break;694695case TCODE_READ_QUADLET_REQUEST:696response->header[0] |=697HEADER_TCODE(TCODE_READ_QUADLET_RESPONSE);698if (payload != NULL)699response->header[3] = *(u32 *)payload;700else701response->header[3] = 0;702response->header_length = 16;703response->payload_length = 0;704break;705706case TCODE_READ_BLOCK_REQUEST:707case TCODE_LOCK_REQUEST:708response->header[0] |= HEADER_TCODE(tcode + 2);709response->header[3] =710HEADER_DATA_LENGTH(length) |711HEADER_EXTENDED_TCODE(extended_tcode);712response->header_length = 16;713response->payload = payload;714response->payload_length = length;715break;716717default:718WARN(1, "wrong tcode %d\n", tcode);719}720721response->payload_mapped = false;722}723EXPORT_SYMBOL(fw_fill_response);724725static u32 compute_split_timeout_timestamp(struct fw_card *card,726u32 request_timestamp)727{728unsigned int cycles;729u32 timestamp;730731cycles = card->split_timeout_cycles;732cycles += request_timestamp & 0x1fff;733734timestamp = request_timestamp & ~0x1fff;735timestamp += (cycles / 8000) << 13;736timestamp |= cycles % 8000;737738return timestamp;739}740741static struct fw_request *allocate_request(struct fw_card *card,742struct fw_packet *p)743{744struct fw_request *request;745u32 *data, length;746int request_tcode;747748request_tcode = HEADER_GET_TCODE(p->header[0]);749switch (request_tcode) {750case TCODE_WRITE_QUADLET_REQUEST:751data = &p->header[3];752length = 4;753break;754755case TCODE_WRITE_BLOCK_REQUEST:756case TCODE_LOCK_REQUEST:757data = p->payload;758length = HEADER_GET_DATA_LENGTH(p->header[3]);759break;760761case TCODE_READ_QUADLET_REQUEST:762data = NULL;763length = 4;764break;765766case TCODE_READ_BLOCK_REQUEST:767data = NULL;768length = HEADER_GET_DATA_LENGTH(p->header[3]);769break;770771default:772fw_error("ERROR - corrupt request received - %08x %08x %08x\n",773p->header[0], p->header[1], p->header[2]);774return NULL;775}776777request = kmalloc(sizeof(*request) + length, GFP_ATOMIC);778if (request == NULL)779return NULL;780781request->response.speed = p->speed;782request->response.timestamp =783compute_split_timeout_timestamp(card, p->timestamp);784request->response.generation = p->generation;785request->response.ack = 0;786request->response.callback = free_response_callback;787request->ack = p->ack;788request->length = length;789if (data)790memcpy(request->data, data, length);791792memcpy(request->request_header, p->header, sizeof(p->header));793794return request;795}796797void fw_send_response(struct fw_card *card,798struct fw_request *request, int rcode)799{800if (WARN_ONCE(!request, "invalid for FCP address handlers"))801return;802803/* unified transaction or broadcast transaction: don't respond */804if (request->ack != ACK_PENDING ||805HEADER_DESTINATION_IS_BROADCAST(request->request_header[0])) {806kfree(request);807return;808}809810if (rcode == RCODE_COMPLETE)811fw_fill_response(&request->response, request->request_header,812rcode, request->data,813fw_get_response_length(request));814else815fw_fill_response(&request->response, request->request_header,816rcode, NULL, 0);817818card->driver->send_response(card, &request->response);819}820EXPORT_SYMBOL(fw_send_response);821822static void handle_exclusive_region_request(struct fw_card *card,823struct fw_packet *p,824struct fw_request *request,825unsigned long long offset)826{827struct fw_address_handler *handler;828unsigned long flags;829int tcode, destination, source;830831destination = HEADER_GET_DESTINATION(p->header[0]);832source = HEADER_GET_SOURCE(p->header[1]);833tcode = HEADER_GET_TCODE(p->header[0]);834if (tcode == TCODE_LOCK_REQUEST)835tcode = 0x10 + HEADER_GET_EXTENDED_TCODE(p->header[3]);836837spin_lock_irqsave(&address_handler_lock, flags);838handler = lookup_enclosing_address_handler(&address_handler_list,839offset, request->length);840spin_unlock_irqrestore(&address_handler_lock, flags);841842/*843* FIXME: lookup the fw_node corresponding to the sender of844* this request and pass that to the address handler instead845* of the node ID. We may also want to move the address846* allocations to fw_node so we only do this callback if the847* upper layers registered it for this node.848*/849850if (handler == NULL)851fw_send_response(card, request, RCODE_ADDRESS_ERROR);852else853handler->address_callback(card, request,854tcode, destination, source,855p->generation, offset,856request->data, request->length,857handler->callback_data);858}859860static void handle_fcp_region_request(struct fw_card *card,861struct fw_packet *p,862struct fw_request *request,863unsigned long long offset)864{865struct fw_address_handler *handler;866unsigned long flags;867int tcode, destination, source;868869if ((offset != (CSR_REGISTER_BASE | CSR_FCP_COMMAND) &&870offset != (CSR_REGISTER_BASE | CSR_FCP_RESPONSE)) ||871request->length > 0x200) {872fw_send_response(card, request, RCODE_ADDRESS_ERROR);873874return;875}876877tcode = HEADER_GET_TCODE(p->header[0]);878destination = HEADER_GET_DESTINATION(p->header[0]);879source = HEADER_GET_SOURCE(p->header[1]);880881if (tcode != TCODE_WRITE_QUADLET_REQUEST &&882tcode != TCODE_WRITE_BLOCK_REQUEST) {883fw_send_response(card, request, RCODE_TYPE_ERROR);884885return;886}887888spin_lock_irqsave(&address_handler_lock, flags);889list_for_each_entry(handler, &address_handler_list, link) {890if (is_enclosing_handler(handler, offset, request->length))891handler->address_callback(card, NULL, tcode,892destination, source,893p->generation, offset,894request->data,895request->length,896handler->callback_data);897}898spin_unlock_irqrestore(&address_handler_lock, flags);899900fw_send_response(card, request, RCODE_COMPLETE);901}902903void fw_core_handle_request(struct fw_card *card, struct fw_packet *p)904{905struct fw_request *request;906unsigned long long offset;907908if (p->ack != ACK_PENDING && p->ack != ACK_COMPLETE)909return;910911if (TCODE_IS_LINK_INTERNAL(HEADER_GET_TCODE(p->header[0]))) {912fw_cdev_handle_phy_packet(card, p);913return;914}915916request = allocate_request(card, p);917if (request == NULL) {918/* FIXME: send statically allocated busy packet. */919return;920}921922offset = ((u64)HEADER_GET_OFFSET_HIGH(p->header[1]) << 32) |923p->header[2];924925if (!is_in_fcp_region(offset, request->length))926handle_exclusive_region_request(card, p, request, offset);927else928handle_fcp_region_request(card, p, request, offset);929930}931EXPORT_SYMBOL(fw_core_handle_request);932933void fw_core_handle_response(struct fw_card *card, struct fw_packet *p)934{935struct fw_transaction *t;936unsigned long flags;937u32 *data;938size_t data_length;939int tcode, tlabel, source, rcode;940941tcode = HEADER_GET_TCODE(p->header[0]);942tlabel = HEADER_GET_TLABEL(p->header[0]);943source = HEADER_GET_SOURCE(p->header[1]);944rcode = HEADER_GET_RCODE(p->header[1]);945946spin_lock_irqsave(&card->lock, flags);947list_for_each_entry(t, &card->transaction_list, link) {948if (t->node_id == source && t->tlabel == tlabel) {949if (!try_cancel_split_timeout(t)) {950spin_unlock_irqrestore(&card->lock, flags);951goto timed_out;952}953list_del_init(&t->link);954card->tlabel_mask &= ~(1ULL << t->tlabel);955break;956}957}958spin_unlock_irqrestore(&card->lock, flags);959960if (&t->link == &card->transaction_list) {961timed_out:962fw_notify("Unsolicited response (source %x, tlabel %x)\n",963source, tlabel);964return;965}966967/*968* FIXME: sanity check packet, is length correct, does tcodes969* and addresses match.970*/971972switch (tcode) {973case TCODE_READ_QUADLET_RESPONSE:974data = (u32 *) &p->header[3];975data_length = 4;976break;977978case TCODE_WRITE_RESPONSE:979data = NULL;980data_length = 0;981break;982983case TCODE_READ_BLOCK_RESPONSE:984case TCODE_LOCK_RESPONSE:985data = p->payload;986data_length = HEADER_GET_DATA_LENGTH(p->header[3]);987break;988989default:990/* Should never happen, this is just to shut up gcc. */991data = NULL;992data_length = 0;993break;994}995996/*997* The response handler may be executed while the request handler998* is still pending. Cancel the request handler.999*/1000card->driver->cancel_packet(card, &t->packet);10011002t->callback(card, rcode, data, data_length, t->callback_data);1003}1004EXPORT_SYMBOL(fw_core_handle_response);10051006static const struct fw_address_region topology_map_region =1007{ .start = CSR_REGISTER_BASE | CSR_TOPOLOGY_MAP,1008.end = CSR_REGISTER_BASE | CSR_TOPOLOGY_MAP_END, };10091010static void handle_topology_map(struct fw_card *card, struct fw_request *request,1011int tcode, int destination, int source, int generation,1012unsigned long long offset, void *payload, size_t length,1013void *callback_data)1014{1015int start;10161017if (!TCODE_IS_READ_REQUEST(tcode)) {1018fw_send_response(card, request, RCODE_TYPE_ERROR);1019return;1020}10211022if ((offset & 3) > 0 || (length & 3) > 0) {1023fw_send_response(card, request, RCODE_ADDRESS_ERROR);1024return;1025}10261027start = (offset - topology_map_region.start) / 4;1028memcpy(payload, &card->topology_map[start], length);10291030fw_send_response(card, request, RCODE_COMPLETE);1031}10321033static struct fw_address_handler topology_map = {1034.length = 0x400,1035.address_callback = handle_topology_map,1036};10371038static const struct fw_address_region registers_region =1039{ .start = CSR_REGISTER_BASE,1040.end = CSR_REGISTER_BASE | CSR_CONFIG_ROM, };10411042static void update_split_timeout(struct fw_card *card)1043{1044unsigned int cycles;10451046cycles = card->split_timeout_hi * 8000 + (card->split_timeout_lo >> 19);10471048cycles = max(cycles, 800u); /* minimum as per the spec */1049cycles = min(cycles, 3u * 8000u); /* maximum OHCI timeout */10501051card->split_timeout_cycles = cycles;1052card->split_timeout_jiffies = DIV_ROUND_UP(cycles * HZ, 8000);1053}10541055static void handle_registers(struct fw_card *card, struct fw_request *request,1056int tcode, int destination, int source, int generation,1057unsigned long long offset, void *payload, size_t length,1058void *callback_data)1059{1060int reg = offset & ~CSR_REGISTER_BASE;1061__be32 *data = payload;1062int rcode = RCODE_COMPLETE;1063unsigned long flags;10641065switch (reg) {1066case CSR_PRIORITY_BUDGET:1067if (!card->priority_budget_implemented) {1068rcode = RCODE_ADDRESS_ERROR;1069break;1070}1071/* else fall through */10721073case CSR_NODE_IDS:1074/*1075* per IEEE 1394-2008 8.3.22.3, not IEEE 1394.1-2004 3.2.81076* and 9.6, but interoperable with IEEE 1394.1-2004 bridges1077*/1078/* fall through */10791080case CSR_STATE_CLEAR:1081case CSR_STATE_SET:1082case CSR_CYCLE_TIME:1083case CSR_BUS_TIME:1084case CSR_BUSY_TIMEOUT:1085if (tcode == TCODE_READ_QUADLET_REQUEST)1086*data = cpu_to_be32(card->driver->read_csr(card, reg));1087else if (tcode == TCODE_WRITE_QUADLET_REQUEST)1088card->driver->write_csr(card, reg, be32_to_cpu(*data));1089else1090rcode = RCODE_TYPE_ERROR;1091break;10921093case CSR_RESET_START:1094if (tcode == TCODE_WRITE_QUADLET_REQUEST)1095card->driver->write_csr(card, CSR_STATE_CLEAR,1096CSR_STATE_BIT_ABDICATE);1097else1098rcode = RCODE_TYPE_ERROR;1099break;11001101case CSR_SPLIT_TIMEOUT_HI:1102if (tcode == TCODE_READ_QUADLET_REQUEST) {1103*data = cpu_to_be32(card->split_timeout_hi);1104} else if (tcode == TCODE_WRITE_QUADLET_REQUEST) {1105spin_lock_irqsave(&card->lock, flags);1106card->split_timeout_hi = be32_to_cpu(*data) & 7;1107update_split_timeout(card);1108spin_unlock_irqrestore(&card->lock, flags);1109} else {1110rcode = RCODE_TYPE_ERROR;1111}1112break;11131114case CSR_SPLIT_TIMEOUT_LO:1115if (tcode == TCODE_READ_QUADLET_REQUEST) {1116*data = cpu_to_be32(card->split_timeout_lo);1117} else if (tcode == TCODE_WRITE_QUADLET_REQUEST) {1118spin_lock_irqsave(&card->lock, flags);1119card->split_timeout_lo =1120be32_to_cpu(*data) & 0xfff80000;1121update_split_timeout(card);1122spin_unlock_irqrestore(&card->lock, flags);1123} else {1124rcode = RCODE_TYPE_ERROR;1125}1126break;11271128case CSR_MAINT_UTILITY:1129if (tcode == TCODE_READ_QUADLET_REQUEST)1130*data = card->maint_utility_register;1131else if (tcode == TCODE_WRITE_QUADLET_REQUEST)1132card->maint_utility_register = *data;1133else1134rcode = RCODE_TYPE_ERROR;1135break;11361137case CSR_BROADCAST_CHANNEL:1138if (tcode == TCODE_READ_QUADLET_REQUEST)1139*data = cpu_to_be32(card->broadcast_channel);1140else if (tcode == TCODE_WRITE_QUADLET_REQUEST)1141card->broadcast_channel =1142(be32_to_cpu(*data) & BROADCAST_CHANNEL_VALID) |1143BROADCAST_CHANNEL_INITIAL;1144else1145rcode = RCODE_TYPE_ERROR;1146break;11471148case CSR_BUS_MANAGER_ID:1149case CSR_BANDWIDTH_AVAILABLE:1150case CSR_CHANNELS_AVAILABLE_HI:1151case CSR_CHANNELS_AVAILABLE_LO:1152/*1153* FIXME: these are handled by the OHCI hardware and1154* the stack never sees these request. If we add1155* support for a new type of controller that doesn't1156* handle this in hardware we need to deal with these1157* transactions.1158*/1159BUG();1160break;11611162default:1163rcode = RCODE_ADDRESS_ERROR;1164break;1165}11661167fw_send_response(card, request, rcode);1168}11691170static struct fw_address_handler registers = {1171.length = 0x400,1172.address_callback = handle_registers,1173};11741175MODULE_AUTHOR("Kristian Hoegsberg <[email protected]>");1176MODULE_DESCRIPTION("Core IEEE1394 transaction logic");1177MODULE_LICENSE("GPL");11781179static const u32 vendor_textual_descriptor[] = {1180/* textual descriptor leaf () */11810x00060000,11820x00000000,11830x00000000,11840x4c696e75, /* L i n u */11850x78204669, /* x F i */11860x72657769, /* r e w i */11870x72650000, /* r e */1188};11891190static const u32 model_textual_descriptor[] = {1191/* model descriptor leaf () */11920x00030000,11930x00000000,11940x00000000,11950x4a756a75, /* J u j u */1196};11971198static struct fw_descriptor vendor_id_descriptor = {1199.length = ARRAY_SIZE(vendor_textual_descriptor),1200.immediate = 0x03d00d1e,1201.key = 0x81000000,1202.data = vendor_textual_descriptor,1203};12041205static struct fw_descriptor model_id_descriptor = {1206.length = ARRAY_SIZE(model_textual_descriptor),1207.immediate = 0x17000001,1208.key = 0x81000000,1209.data = model_textual_descriptor,1210};12111212static int __init fw_core_init(void)1213{1214int ret;12151216fw_workqueue = alloc_workqueue("firewire",1217WQ_NON_REENTRANT | WQ_MEM_RECLAIM, 0);1218if (!fw_workqueue)1219return -ENOMEM;12201221ret = bus_register(&fw_bus_type);1222if (ret < 0) {1223destroy_workqueue(fw_workqueue);1224return ret;1225}12261227fw_cdev_major = register_chrdev(0, "firewire", &fw_device_ops);1228if (fw_cdev_major < 0) {1229bus_unregister(&fw_bus_type);1230destroy_workqueue(fw_workqueue);1231return fw_cdev_major;1232}12331234fw_core_add_address_handler(&topology_map, &topology_map_region);1235fw_core_add_address_handler(®isters, ®isters_region);1236fw_core_add_descriptor(&vendor_id_descriptor);1237fw_core_add_descriptor(&model_id_descriptor);12381239return 0;1240}12411242static void __exit fw_core_cleanup(void)1243{1244unregister_chrdev(fw_cdev_major, "firewire");1245bus_unregister(&fw_bus_type);1246destroy_workqueue(fw_workqueue);1247idr_destroy(&fw_device_idr);1248}12491250module_init(fw_core_init);1251module_exit(fw_core_cleanup);125212531254