📄 ieee1394_core.c
字号:
HPSB_NOTICE("Stopping out-of-control reset loop");
HPSB_NOTICE("Warning - topology map and speed map will not be valid");
host->reset_retries = 0;
}
} else {
host->reset_retries = 0;
build_speed_map(host, host->node_count);
}
HPSB_VERBOSE("selfid_complete called with successful SelfID stage "
"... irm_id: 0x%X node_id: 0x%X",host->irm_id,host->node_id);
/* irm_id is kept up to date by check_selfids() */
if (host->irm_id == host->node_id) {
host->is_irm = 1;
} else {
host->is_busmgr = 0;
host->is_irm = 0;
}
if (isroot) {
host->driver->devctl(host, ACT_CYCLE_MASTER, 1);
host->is_cycmst = 1;
}
atomic_inc(&host->generation);
host->in_bus_reset = 0;
highlevel_host_reset(host);
}
static spinlock_t pending_packets_lock = SPIN_LOCK_UNLOCKED;
/**
* hpsb_packet_sent - notify core of sending a packet
*
* For host driver module usage. Safe to call from within a transmit packet
* routine.
*
* Notify core of sending a packet. Ackcode is the ack code returned for async
* transmits or ACKX_SEND_ERROR if the transmission failed completely; ACKX_NONE
* for other cases (internal errors that don't justify a panic).
*/
void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet,
int ackcode)
{
unsigned long flags;
spin_lock_irqsave(&pending_packets_lock, flags);
packet->ack_code = ackcode;
if (packet->no_waiter || packet->state == hpsb_complete) {
/* if packet->no_waiter, must not have a tlabel allocated */
spin_unlock_irqrestore(&pending_packets_lock, flags);
hpsb_free_packet(packet);
return;
}
atomic_dec(&packet->refcnt); /* drop HC's reference */
/* here the packet must be on the host->pending_packets queue */
if (ackcode != ACK_PENDING || !packet->expect_response) {
packet->state = hpsb_complete;
list_del_init(&packet->queue);
spin_unlock_irqrestore(&pending_packets_lock, flags);
queue_packet_complete(packet);
return;
}
packet->state = hpsb_pending;
packet->sendtime = jiffies;
spin_unlock_irqrestore(&pending_packets_lock, flags);
mod_timer(&host->timeout, jiffies + host->timeout_interval);
}
/**
* hpsb_send_phy_config - transmit a PHY configuration packet on the bus
* @host: host that PHY config packet gets sent through
* @rootid: root whose force_root bit should get set (-1 = don't set force_root)
* @gapcnt: gap count value to set (-1 = don't set gap count)
*
* This function sends a PHY config packet on the bus through the specified
* host.
*
* Return value: 0 for success or negative error number otherwise.
*/
int hpsb_send_phy_config(struct hpsb_host *host, int rootid, int gapcnt)
{
struct hpsb_packet *packet;
quadlet_t d = 0;
int retval = 0;
if (rootid >= ALL_NODES || rootid < -1 || gapcnt > 0x3f || gapcnt < -1 ||
(rootid == -1 && gapcnt == -1)) {
HPSB_DEBUG("Invalid Parameter: rootid = %d gapcnt = %d",
rootid, gapcnt);
return -EINVAL;
}
if (rootid != -1)
d |= PHYPACKET_PHYCONFIG_R | rootid << PHYPACKET_PORT_SHIFT;
if (gapcnt != -1)
d |= PHYPACKET_PHYCONFIG_T | gapcnt << PHYPACKET_GAPCOUNT_SHIFT;
packet = hpsb_make_phypacket(host, d);
if (!packet)
return -ENOMEM;
packet->generation = get_hpsb_generation(host);
retval = hpsb_send_packet_and_wait(packet);
hpsb_free_packet(packet);
return retval;
}
/**
* hpsb_send_packet - transmit a packet on the bus
* @packet: packet to send
*
* The packet is sent through the host specified in the packet->host field.
* Before sending, the packet's transmit speed is automatically determined
* using the local speed map when it is an async, non-broadcast packet.
*
* Possibilities for failure are that host is either not initialized, in bus
* reset, the packet's generation number doesn't match the current generation
* number or the host reports a transmit error.
*
* Return value: 0 on success, negative errno on failure.
*/
int hpsb_send_packet(struct hpsb_packet *packet)
{
struct hpsb_host *host = packet->host;
if (host->is_shutdown)
return -EINVAL;
if (host->in_bus_reset ||
(packet->generation != get_hpsb_generation(host)))
return -EAGAIN;
packet->state = hpsb_queued;
/* This just seems silly to me */
WARN_ON(packet->no_waiter && packet->expect_response);
if (!packet->no_waiter || packet->expect_response) {
unsigned long flags;
atomic_inc(&packet->refcnt);
/* Set the initial "sendtime" to 10 seconds from now, to
prevent premature expiry. If a packet takes more than
10 seconds to hit the wire, we have bigger problems :) */
packet->sendtime = jiffies + 10 * HZ;
spin_lock_irqsave(&pending_packets_lock, flags);
list_add_tail(&packet->queue, &host->pending_packets);
spin_unlock_irqrestore(&pending_packets_lock, flags);
}
if (packet->node_id == host->node_id) {
/* it is a local request, so handle it locally */
quadlet_t *data;
size_t size = packet->data_size + packet->header_size;
data = kmalloc(size, GFP_ATOMIC);
if (!data) {
HPSB_ERR("unable to allocate memory for concatenating header and data");
return -ENOMEM;
}
memcpy(data, packet->header, packet->header_size);
if (packet->data_size)
memcpy(((u8*)data) + packet->header_size, packet->data, packet->data_size);
dump_packet("send packet local", packet->header, packet->header_size, -1);
hpsb_packet_sent(host, packet, packet->expect_response ? ACK_PENDING : ACK_COMPLETE);
hpsb_packet_received(host, data, size, 0);
kfree(data);
return 0;
}
if (packet->type == hpsb_async &&
NODEID_TO_NODE(packet->node_id) != ALL_NODES)
packet->speed_code =
host->speed[NODEID_TO_NODE(packet->node_id)];
dump_packet("send packet", packet->header, packet->header_size, packet->speed_code);
return host->driver->transmit_packet(host, packet);
}
/* We could just use complete() directly as the packet complete
* callback, but this is more typesafe, in the sense that we get a
* compiler error if the prototype for complete() changes. */
static void complete_packet(void *data)
{
complete((struct completion *) data);
}
/**
* hpsb_send_packet_and_wait - enqueue packet, block until transaction completes
* @packet: packet to send
*
* Return value: 0 on success, negative errno on failure.
*/
int hpsb_send_packet_and_wait(struct hpsb_packet *packet)
{
struct completion done;
int retval;
init_completion(&done);
hpsb_set_packet_complete_task(packet, complete_packet, &done);
retval = hpsb_send_packet(packet);
if (retval == 0)
wait_for_completion(&done);
return retval;
}
static void send_packet_nocare(struct hpsb_packet *packet)
{
if (hpsb_send_packet(packet) < 0) {
hpsb_free_packet(packet);
}
}
static size_t packet_size_to_data_size(size_t packet_size, size_t header_size,
size_t buffer_size, int tcode)
{
size_t ret = packet_size <= header_size ? 0 : packet_size - header_size;
if (unlikely(ret > buffer_size))
ret = buffer_size;
if (unlikely(ret + header_size != packet_size))
HPSB_ERR("unexpected packet size %zd (tcode %d), bug?",
packet_size, tcode);
return ret;
}
static void handle_packet_response(struct hpsb_host *host, int tcode,
quadlet_t *data, size_t size)
{
struct hpsb_packet *packet;
int tlabel = (data[0] >> 10) & 0x3f;
size_t header_size;
unsigned long flags;
spin_lock_irqsave(&pending_packets_lock, flags);
list_for_each_entry(packet, &host->pending_packets, queue)
if (packet->tlabel == tlabel &&
packet->node_id == (data[1] >> 16))
goto found;
spin_unlock_irqrestore(&pending_packets_lock, flags);
HPSB_DEBUG("unsolicited response packet received - %s",
"no tlabel match");
dump_packet("contents", data, 16, -1);
return;
found:
switch (packet->tcode) {
case TCODE_WRITEQ:
case TCODE_WRITEB:
if (unlikely(tcode != TCODE_WRITE_RESPONSE))
break;
header_size = 12;
size = 0;
goto dequeue;
case TCODE_READQ:
if (unlikely(tcode != TCODE_READQ_RESPONSE))
break;
header_size = 16;
size = 0;
goto dequeue;
case TCODE_READB:
if (unlikely(tcode != TCODE_READB_RESPONSE))
break;
header_size = 16;
size = packet_size_to_data_size(size, header_size,
packet->allocated_data_size,
tcode);
goto dequeue;
case TCODE_LOCK_REQUEST:
if (unlikely(tcode != TCODE_LOCK_RESPONSE))
break;
header_size = 16;
size = packet_size_to_data_size(min(size, (size_t)(16 + 8)),
header_size,
packet->allocated_data_size,
tcode);
goto dequeue;
}
spin_unlock_irqrestore(&pending_packets_lock, flags);
HPSB_DEBUG("unsolicited response packet received - %s",
"tcode mismatch");
dump_packet("contents", data, 16, -1);
return;
dequeue:
list_del_init(&packet->queue);
spin_unlock_irqrestore(&pending_packets_lock, flags);
if (packet->state == hpsb_queued) {
packet->sendtime = jiffies;
packet->ack_code = ACK_PENDING;
}
packet->state = hpsb_complete;
memcpy(packet->header, data, header_size);
if (size)
memcpy(packet->data, data + 4, size);
queue_packet_complete(packet);
}
static struct hpsb_packet *create_reply_packet(struct hpsb_host *host,
quadlet_t *data, size_t dsize)
{
struct hpsb_packet *p;
p = hpsb_alloc_packet(dsize);
if (unlikely(p == NULL)) {
/* FIXME - send data_error response */
HPSB_ERR("out of memory, cannot send response packet");
return NULL;
}
p->type = hpsb_async;
p->state = hpsb_unused;
p->host = host;
p->node_id = data[1] >> 16;
p->tlabel = (data[0] >> 10) & 0x3f;
p->no_waiter = 1;
p->generation = get_hpsb_generation(host);
if (dsize % 4)
p->data[dsize / 4] = 0;
return p;
}
#define PREP_ASYNC_HEAD_RCODE(tc) \
packet->tcode = tc; \
packet->header[0] = (packet->node_id << 16) | (packet->tlabel << 10) \
| (1 << 8) | (tc << 4); \
packet->header[1] = (packet->host->node_id << 16) | (rcode << 12); \
packet->header[2] = 0
static void fill_async_readquad_resp(struct hpsb_packet *packet, int rcode,
quadlet_t data)
{
PREP_ASYNC_HEAD_RCODE(TCODE_READQ_RESPONSE);
packet->header[3] = data;
packet->header_size = 16;
packet->data_size = 0;
}
static void fill_async_readblock_resp(struct hpsb_packet *packet, int rcode,
int length)
{
if (rcode != RCODE_COMPLETE)
length = 0;
PREP_ASYNC_HEAD_RCODE(TCODE_READB_RESPONSE);
packet->header[3] = length << 16;
packet->header_size = 16;
packet->data_size = length + (length % 4 ? 4 - (length % 4) : 0);
}
static void fill_async_write_resp(struct hpsb_packet *packet, int rcode)
{
PREP_ASYNC_HEAD_RCODE(TCODE_WRITE_RESPONSE);
packet->header_size = 12;
packet->data_size = 0;
}
static void fill_async_lock_resp(struct hpsb_packet *packet, int rcode, int extcode,
int length)
{
if (rcode != RCODE_COMPLETE)
length = 0;
PREP_ASYNC_HEAD_RCODE(TCODE_LOCK_RESPONSE);
packet->header[3] = (length << 16) | extcode;
packet->header_size = 16;
packet->data_size = length;
}
static void handle_incoming_packet(struct hpsb_host *host, int tcode,
quadlet_t *data, size_t size,
int write_acked)
{
struct hpsb_packet *packet;
int length, rcode, extcode;
quadlet_t buffer;
nodeid_t source = data[1] >> 16;
nodeid_t dest = data[0] >> 16;
u16 flags = (u16) data[0];
u64 addr;
/* FIXME?
* Out-of-bounds lengths are left for highlevel_read|write to cap. */
switch (tcode) {
case TCODE_WRITEQ:
addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
rcode = highlevel_write(host, source, dest, data + 3,
addr, 4, flags);
goto handle_write_request;
case TCODE_WRITEB:
addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
rcode = highlevel_write(host, source, dest, data + 4,
addr, data[3] >> 16, flags);
handle_write_request:
if (rcode < 0 || write_acked ||
NODEID_TO_NODE(data[0] >> 16) == NODE_MASK)
return;
/* not a broadcast write, reply */
packet = create_reply_packet(host, data, 0);
if (packet) {
fill_async_write_resp(packet, rcode);
send_packet_nocare(packet);
}
return;
case TCODE_READQ:
addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
rcode = highlevel_read(host, source, &buffer, addr, 4, flags);
if (rcode < 0)
return;
packet = create_reply_packet(host, data, 0);
if (packet) {
fill_async_readquad_resp(packet, rcode, buffer);
send_packet_nocare(packet);
}
return;
case TCODE_READB:
length = data[3] >> 16;
packet = create_reply_packet(host, data, length);
if (!packet)
return;
addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
rcode = highlevel_read(host, source, packet->data, addr,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -