ieee1394_core.c
来自「linux 内核源代码」· C语言 代码 · 共 1,378 行 · 第 1/3 页
C
1,378 行
} else { 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 DEFINE_SPINLOCK(pending_packets_lock);/** * 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] = 0static 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];
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?