/* * Only valid for transactions that are potentially pending (ie have * been sent).
*/ int fw_cancel_transaction(struct fw_card *card, struct fw_transaction *transaction)
{
u32 tstamp;
/* * Cancel the packet transmission if it's still queued. That * will call the packet transmission callback which cancels * the transaction.
*/
if (card->driver->cancel_packet(card, &transaction->packet) == 0) return 0;
/* * If the request packet has already been sent, we need to see * if the transaction is still pending and remove it in that case.
*/
if (transaction->packet.ack == 0) { // The timestamp is reused since it was just read now.
tstamp = transaction->packet.timestamp;
} else {
u32 curr_cycle_time = 0;
switch (status) { case ACK_COMPLETE:
close_transaction(t, card, RCODE_COMPLETE, packet->timestamp); break; case ACK_PENDING:
{
t->split_timeout_cycle =
compute_split_timeout_timestamp(card, packet->timestamp) & 0xffff;
start_split_transaction_timeout(t, card); break;
} case ACK_BUSY_X: case ACK_BUSY_A: case ACK_BUSY_B:
close_transaction(t, card, RCODE_BUSY, packet->timestamp); break; case ACK_DATA_ERROR:
close_transaction(t, card, RCODE_DATA_ERROR, packet->timestamp); break; case ACK_TYPE_ERROR:
close_transaction(t, card, RCODE_TYPE_ERROR, packet->timestamp); break; default: /* * In this case the ack is really a juju specific * rcode, so just forward that to the callback.
*/
close_transaction(t, card, status, packet->timestamp); break;
}
}
staticvoid fw_fill_request(struct fw_packet *packet, int tcode, int tlabel, int destination_id, int source_id, int generation, int speed, unsignedlonglong offset, void *payload, size_t length)
{ int ext_tcode;
if (tcode == TCODE_STREAM_DATA) { // The value of destination_id argument should include tag, channel, and sy fields // as isochronous packet header has.
packet->header[0] = destination_id;
isoc_header_set_data_length(packet->header, length);
isoc_header_set_tcode(packet->header, TCODE_STREAM_DATA);
packet->header_length = 4;
packet->payload = payload;
packet->payload_length = length;
/** * __fw_send_request() - submit a request packet for transmission to generate callback for response * subaction with or without time stamp. * @card: interface to send the request at * @t: transaction instance to which the request belongs * @tcode: transaction code * @destination_id: destination node ID, consisting of bus_ID and phy_ID * @generation: bus generation in which request and response are valid * @speed: transmission speed * @offset: 48bit wide offset into destination's address space * @payload: data payload for the request subaction * @length: length of the payload, in bytes * @callback: union of two functions whether to receive time stamp or not for response * subaction. * @with_tstamp: Whether to receive time stamp or not for response subaction. * @callback_data: data to be passed to the transaction completion callback * * Submit a request packet into the asynchronous request transmission queue. * Can be called from atomic context. If you prefer a blocking API, use * fw_run_transaction() in a context that can sleep. * * In case of lock requests, specify one of the firewire-core specific %TCODE_ * constants instead of %TCODE_LOCK_REQUEST in @tcode. * * Make sure that the value in @destination_id is not older than the one in * @generation. Otherwise the request is in danger to be sent to a wrong node. * * In case of asynchronous stream packets i.e. %TCODE_STREAM_DATA, the caller * needs to synthesize @destination_id with fw_stream_packet_destination_id(). * It will contain tag, channel, and sy data instead of a node ID then. * * The payload buffer at @data is going to be DMA-mapped except in case of * @length <= 8 or of local (loopback) requests. Hence make sure that the * buffer complies with the restrictions of the streaming DMA mapping API. * @payload must not be freed before the @callback is called. * * In case of request types without payload, @data is NULL and @length is 0. * * After the transaction is completed successfully or unsuccessfully, the * @callback will be called. Among its parameters is the response code which * is either one of the rcodes per IEEE 1394 or, in case of internal errors, * the firewire-core specific %RCODE_SEND_ERROR. The other firewire-core * specific rcodes (%RCODE_CANCELLED, %RCODE_BUSY, %RCODE_GENERATION, * %RCODE_NO_ACK) denote transaction timeout, busy responder, stale request * generation, or missing ACK respectively. * * Note some timing corner cases: fw_send_request() may complete much earlier * than when the request packet actually hits the wire. On the other hand, * transaction completion and hence execution of @callback may happen even * before fw_send_request() returns.
*/ void __fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode, int destination_id, int generation, int speed, unsignedlonglong offset, void *payload, size_t length, union fw_transaction_callback callback, bool with_tstamp, void *callback_data)
{ unsignedlong flags; int tlabel;
/* * Allocate tlabel from the bitmap and put the transaction on * the list while holding the card spinlock.
*/
spin_lock_irqsave(&card->lock, flags);
tlabel = allocate_tlabel(card); if (tlabel < 0) {
spin_unlock_irqrestore(&card->lock, flags); if (!with_tstamp) {
callback.without_tstamp(card, RCODE_SEND_ERROR, NULL, 0, callback_data);
} else { // Timestamping on behalf of hardware.
u32 curr_cycle_time = 0;
u32 tstamp;
/** * fw_run_transaction() - send request and sleep until transaction is completed * @card: card interface for this request * @tcode: transaction code * @destination_id: destination node ID, consisting of bus_ID and phy_ID * @generation: bus generation in which request and response are valid * @speed: transmission speed * @offset: 48bit wide offset into destination's address space * @payload: data payload for the request subaction * @length: length of the payload, in bytes * * Returns the RCODE. See fw_send_request() for parameter documentation. * Unlike fw_send_request(), @data points to the payload of the request or/and * to the payload of the response. DMA mapping restrictions apply to outbound * request payloads of >= 8 bytes but not to inbound response payloads.
*/ int fw_run_transaction(struct fw_card *card, int tcode, int destination_id, int generation, int speed, unsignedlonglong offset, void *payload, size_t length)
{ struct transaction_callback_data d; struct fw_transaction t;
/** * fw_core_add_address_handler() - register for incoming requests * @handler: callback * @region: region in the IEEE 1212 node space address range * * region->start, ->end, and handler->length have to be quadlet-aligned. * * When a request is received that falls within the specified address range, the specified callback * is invoked. The parameters passed to the callback give the details of the particular request. * The callback is invoked in the workqueue context in most cases. However, if the request is * initiated by the local node, the callback is invoked in the initiator's context. * * To be called in process context. * Return value: 0 on success, non-zero otherwise. * * The start offset of the handler's address region is determined by * fw_core_add_address_handler() and is returned in handler->offset. * * Address allocations are exclusive, except for the FCP registers.
*/ int fw_core_add_address_handler(struct fw_address_handler *handler, conststruct fw_address_region *region)
{ struct fw_address_handler *other; int ret = -EBUSY;
/** * fw_core_remove_address_handler() - unregister an address handler * @handler: callback * * To be called in process context. * * When fw_core_remove_address_handler() returns, @handler->callback() is * guaranteed to not run on any CPU anymore.
*/ void fw_core_remove_address_handler(struct fw_address_handler *handler)
{
scoped_guard(spinlock, &address_handler_list_lock)
list_del_rcu(&handler->link);
synchronize_rcu();
if (!put_address_handler(handler))
wait_for_completion(&handler->done);
}
EXPORT_SYMBOL(fw_core_remove_address_handler);
/** * fw_send_response: - send response packet for asynchronous transaction. * @card: interface to send the response at. * @request: firewire request data for the transaction. * @rcode: response code to send. * * Submit a response packet into the asynchronous response transmission queue. The @request * is going to be released when the transmission successfully finishes later.
*/ void fw_send_response(struct fw_card *card, struct fw_request *request, int rcode)
{
u32 *data = NULL; unsignedint data_length = 0;
/* unified transaction or broadcast transaction: don't respond */ if (request->ack != ACK_PENDING ||
HEADER_DESTINATION_IS_BROADCAST(request->request_header)) {
fw_request_put(request); return;
}
if (rcode == RCODE_COMPLETE) {
data = request->data;
data_length = fw_get_response_length(request);
}
/** * fw_get_request_speed() - returns speed at which the @request was received * @request: firewire request data
*/ int fw_get_request_speed(struct fw_request *request)
{ return request->response.speed;
}
EXPORT_SYMBOL(fw_get_request_speed);
/** * fw_request_get_timestamp: Get timestamp of the request. * @request: The opaque pointer to request structure. * * Get timestamp when 1394 OHCI controller receives the asynchronous request subaction. The * timestamp consists of the low order 3 bits of second field and the full 13 bits of count * field of isochronous cycle time register. * * Returns: timestamp of the request.
*/
u32 fw_request_get_timestamp(conststruct fw_request *request)
{ return request->timestamp;
}
EXPORT_SYMBOL_GPL(fw_request_get_timestamp);
buffer_on_kernel_heap =
krealloc_array(buffer_on_kernel_heap, next_size, sizeof(*buffer_on_kernel_heap), GFP_ATOMIC); // FCP is used for purposes unrelated to significant system // resources (e.g. storage or networking), so allocation // failures are not considered so critical. if (!buffer_on_kernel_heap) break;
if (handlers == buffer_on_kernel_stack) {
memcpy(buffer_on_kernel_heap, buffer_on_kernel_stack, sizeof(buffer_on_kernel_stack));
}
// FIXME: sanity check packet, is length correct, does tcodes // and addresses match to the transaction request queried later. // // For the tracepoints event, let us decode the header here against the concern.
switch (tcode) { case TCODE_READ_QUADLET_RESPONSE:
data = (u32 *) &p->header[3];
data_length = 4; break;
case TCODE_WRITE_RESPONSE:
data = NULL;
data_length = 0; break;
case TCODE_READ_BLOCK_RESPONSE: case TCODE_LOCK_RESPONSE:
data = p->payload;
data_length = async_header_get_data_length(p->header); break;
default: /* Should never happen, this is just to shut up gcc. */
data = NULL;
data_length = 0; break;
}
/* * The response handler may be executed while the request handler * is still pending. Cancel the request handler.
*/
card->driver->cancel_packet(card, &t->packet);
staticvoid handle_registers(struct fw_card *card, struct fw_request *request, int tcode, int destination, int source, int generation, unsignedlonglong offset, void *payload, size_t length, void *callback_data)
{ int reg = offset & ~CSR_REGISTER_BASE;
__be32 *data = payload; int rcode = RCODE_COMPLETE;
switch (reg) { case CSR_PRIORITY_BUDGET: if (!card->priority_budget_implemented) {
rcode = RCODE_ADDRESS_ERROR; break;
}
fallthrough;
case CSR_NODE_IDS: /* * per IEEE 1394-2008 8.3.22.3, not IEEE 1394.1-2004 3.2.8 * and 9.6, but interoperable with IEEE 1394.1-2004 bridges
*/
fallthrough;
case CSR_STATE_CLEAR: case CSR_STATE_SET: case CSR_CYCLE_TIME: case CSR_BUS_TIME: case CSR_BUSY_TIMEOUT: if (tcode == TCODE_READ_QUADLET_REQUEST)
*data = cpu_to_be32(card->driver->read_csr(card, reg)); elseif (tcode == TCODE_WRITE_QUADLET_REQUEST)
card->driver->write_csr(card, reg, be32_to_cpu(*data)); else
rcode = RCODE_TYPE_ERROR; break;
case CSR_RESET_START: if (tcode == TCODE_WRITE_QUADLET_REQUEST)
card->driver->write_csr(card, CSR_STATE_CLEAR,
CSR_STATE_BIT_ABDICATE); else
rcode = RCODE_TYPE_ERROR; break;
case CSR_SPLIT_TIMEOUT_HI: if (tcode == TCODE_READ_QUADLET_REQUEST) {
*data = cpu_to_be32(card->split_timeout_hi);
} elseif (tcode == TCODE_WRITE_QUADLET_REQUEST) {
guard(spinlock_irqsave)(&card->lock);
case CSR_BUS_MANAGER_ID: case CSR_BANDWIDTH_AVAILABLE: case CSR_CHANNELS_AVAILABLE_HI: case CSR_CHANNELS_AVAILABLE_LO: /* * FIXME: these are handled by the OHCI hardware and * the stack never sees these request. If we add * support for a new type of controller that doesn't * handle this in hardware we need to deal with these * transactions.
*/
BUG(); break;
staticvoid handle_low_memory(struct fw_card *card, struct fw_request *request, int tcode, int destination, int source, int generation, unsignedlonglong offset, void *payload, size_t length, void *callback_data)
{ /* * This catches requests not handled by the physical DMA unit, * i.e., wrong transaction types or unauthorized source nodes.
*/
fw_send_response(card, request, RCODE_TYPE_ERROR);
}
staticconst u32 vendor_textual_descriptor[] = { /* textual descriptor leaf () */
0x00060000,
0x00000000,
0x00000000,
0x4c696e75, /* L i n u */
0x78204669, /* x F i */
0x72657769, /* r e w i */
0x72650000, /* r e */
};
staticconst u32 model_textual_descriptor[] = { /* model descriptor leaf () */
0x00030000,
0x00000000,
0x00000000,
0x4a756a75, /* J u j u */
};
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.