📄 pcilynx.c
字号:
lsid |= (phyreg[1] & 0x3f) << 16; /* gap count */ lsid |= (phyreg[2] & 0xc0) << 8; /* max speed */ lsid |= (phyreg[6] & 0x01) << 11; /* contender (phy dependent) */ /* lsid |= 1 << 11; *//* set contender (hack) */ lsid |= (phyreg[6] & 0x10) >> 3; /* initiated reset */ for (i = 0; i < (phyreg[2] & 0xf); i++) { /* ports */ if (phyreg[3 + i] & 0x4) { lsid |= (((phyreg[3 + i] & 0x8) | 0x10) >> 3) << (6 - i*2); } else { lsid |= 1 << (6 - i*2); } } cpu_to_be32s(&lsid); PRINT(KERN_DEBUG, lynx->id, "generated own selfid 0x%x", lsid); return lsid;}static void handle_selfid(struct ti_lynx *lynx, struct hpsb_host *host){ quadlet_t *q = lynx->rcv_page; int phyid, isroot, size; quadlet_t lsid = 0; int i; if (lynx->phy_reg0 == -1 || lynx->selfid_size == -1) return; size = lynx->selfid_size; phyid = lynx->phy_reg0; i = (size > 16 ? 16 : size) / 4 - 1; while (i >= 0) { cpu_to_be32s(&q[i]); i--; } if (!lynx->phyic.reg_1394a) { lsid = generate_own_selfid(lynx, host); } isroot = (phyid & 2) != 0; phyid >>= 2; PRINT(KERN_INFO, lynx->id, "SelfID process finished (phyid %d, %s)", phyid, (isroot ? "root" : "not root")); reg_write(lynx, LINK_ID, (0xffc0 | phyid) << 16); if (!lynx->phyic.reg_1394a && !size) { hpsb_selfid_received(host, lsid); } while (size > 0) { struct selfid *sid = (struct selfid *)q; if (!lynx->phyic.reg_1394a && !sid->extended && (sid->phy_id == (phyid + 1))) { hpsb_selfid_received(host, lsid); } if (q[0] == ~q[1]) { PRINT(KERN_DEBUG, lynx->id, "SelfID packet 0x%x rcvd", q[0]); hpsb_selfid_received(host, q[0]); } else { PRINT(KERN_INFO, lynx->id, "inconsistent selfid 0x%x/0x%x", q[0], q[1]); } q += 2; size -= 8; } if (!lynx->phyic.reg_1394a && isroot && phyid != 0) { hpsb_selfid_received(host, lsid); } hpsb_selfid_complete(host, phyid, isroot); if (host->in_bus_reset) return; /* in bus reset again */ if (isroot) reg_set_bits(lynx, LINK_CONTROL, LINK_CONTROL_CYCMASTER); //FIXME: I do not think, we need this here reg_set_bits(lynx, LINK_CONTROL, LINK_CONTROL_RCV_CMP_VALID | LINK_CONTROL_TX_ASYNC_EN | LINK_CONTROL_RX_ASYNC_EN | LINK_CONTROL_CYCTIMEREN);}/* This must be called with the respective queue_lock held. */static void send_next(struct ti_lynx *lynx, int what){ struct ti_pcl pcl; struct lynx_send_data *d; struct hpsb_packet *packet; d = (what == hpsb_iso ? &lynx->iso_send : &lynx->async); if (!list_empty(&d->pcl_queue)) { PRINT(KERN_ERR, lynx->id, "trying to queue a new packet in nonempty fifo"); BUG(); } packet = driver_packet(d->queue.next); list_del(&packet->driver_list); list_add_tail(&packet->driver_list, &d->pcl_queue); d->header_dma = pci_map_single(lynx->dev, packet->header, packet->header_size, PCI_DMA_TODEVICE); if (packet->data_size) { d->data_dma = pci_map_single(lynx->dev, packet->data, packet->data_size, PCI_DMA_TODEVICE); } else { d->data_dma = 0; } pcl.next = PCL_NEXT_INVALID; pcl.async_error_next = PCL_NEXT_INVALID; pcl.pcl_status = 0;#ifdef __BIG_ENDIAN pcl.buffer[0].control = packet->speed_code << 14 | packet->header_size;#else pcl.buffer[0].control = packet->speed_code << 14 | packet->header_size | PCL_BIGENDIAN;#endif pcl.buffer[0].pointer = d->header_dma; pcl.buffer[1].control = PCL_LAST_BUFF | packet->data_size; pcl.buffer[1].pointer = d->data_dma; switch (packet->type) { case hpsb_async: pcl.buffer[0].control |= PCL_CMD_XMT; break; case hpsb_iso: pcl.buffer[0].control |= PCL_CMD_XMT | PCL_ISOMODE; break; case hpsb_raw: pcl.buffer[0].control |= PCL_CMD_UNFXMT; break; } if (!packet->data_be) { pcl.buffer[1].control |= PCL_BIGENDIAN; } put_pcl(lynx, d->pcl, &pcl); run_pcl(lynx, d->pcl_start, d->channel);}/* called from subsystem core */static int lynx_transmit(struct hpsb_host *host, struct hpsb_packet *packet){ struct ti_lynx *lynx = host->hostdata; struct lynx_send_data *d; unsigned long flags; if (packet->data_size >= 4096) { PRINT(KERN_ERR, lynx->id, "transmit packet data too big (%Zd)", packet->data_size); return 0; } switch (packet->type) { case hpsb_async: case hpsb_raw: d = &lynx->async; break; case hpsb_iso: d = &lynx->iso_send; break; default: PRINT(KERN_ERR, lynx->id, "invalid packet type %d", packet->type); return 0; } if (packet->tcode == TCODE_WRITEQ || packet->tcode == TCODE_READQ_RESPONSE) { cpu_to_be32s(&packet->header[3]); } spin_lock_irqsave(&d->queue_lock, flags); list_add_tail(&packet->driver_list, &d->queue); if (list_empty(&d->pcl_queue)) send_next(lynx, packet->type); spin_unlock_irqrestore(&d->queue_lock, flags); return 1;}/* called from subsystem core */static int lynx_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg){ struct ti_lynx *lynx = host->hostdata; int retval = 0; struct hpsb_packet *packet; LIST_HEAD(packet_list); unsigned long flags; int phy_reg; switch (cmd) { case RESET_BUS: if (reg_read(lynx, LINK_INT_STATUS) & LINK_INT_PHY_BUSRESET) { retval = 0; break; } switch (arg) { case SHORT_RESET: if (lynx->phyic.reg_1394a) { phy_reg = get_phy_reg(lynx, 5); if (phy_reg == -1) { PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed"); retval = -1; break; } phy_reg |= 0x40; PRINT(KERN_INFO, lynx->id, "resetting bus (short bus reset) on request"); lynx->selfid_size = -1; lynx->phy_reg0 = -1; set_phy_reg(lynx, 5, phy_reg); /* set ISBR */ break; } else { PRINT(KERN_INFO, lynx->id, "cannot do short bus reset, because of old phy"); /* fall through to long bus reset */ } case LONG_RESET: phy_reg = get_phy_reg(lynx, 1); if (phy_reg == -1) { PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed"); retval = -1; break; } phy_reg |= 0x40; PRINT(KERN_INFO, lynx->id, "resetting bus (long bus reset) on request"); lynx->selfid_size = -1; lynx->phy_reg0 = -1; set_phy_reg(lynx, 1, phy_reg); /* clear RHB, set IBR */ break; case SHORT_RESET_NO_FORCE_ROOT: if (lynx->phyic.reg_1394a) { phy_reg = get_phy_reg(lynx, 1); if (phy_reg == -1) { PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed"); retval = -1; break; } if (phy_reg & 0x80) { phy_reg &= ~0x80; set_phy_reg(lynx, 1, phy_reg); /* clear RHB */ } phy_reg = get_phy_reg(lynx, 5); if (phy_reg == -1) { PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed"); retval = -1; break; } phy_reg |= 0x40; PRINT(KERN_INFO, lynx->id, "resetting bus (short bus reset, no force_root) on request"); lynx->selfid_size = -1; lynx->phy_reg0 = -1; set_phy_reg(lynx, 5, phy_reg); /* set ISBR */ break; } else { PRINT(KERN_INFO, lynx->id, "cannot do short bus reset, because of old phy"); /* fall through to long bus reset */ } case LONG_RESET_NO_FORCE_ROOT: phy_reg = get_phy_reg(lynx, 1); if (phy_reg == -1) { PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed"); retval = -1; break; } phy_reg &= ~0x80; phy_reg |= 0x40; PRINT(KERN_INFO, lynx->id, "resetting bus (long bus reset, no force_root) on request"); lynx->selfid_size = -1; lynx->phy_reg0 = -1; set_phy_reg(lynx, 1, phy_reg); /* clear RHB, set IBR */ break; case SHORT_RESET_FORCE_ROOT: if (lynx->phyic.reg_1394a) { phy_reg = get_phy_reg(lynx, 1); if (phy_reg == -1) { PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed"); retval = -1; break; } if (!(phy_reg & 0x80)) { phy_reg |= 0x80; set_phy_reg(lynx, 1, phy_reg); /* set RHB */ } phy_reg = get_phy_reg(lynx, 5); if (phy_reg == -1) { PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed"); retval = -1; break; } phy_reg |= 0x40; PRINT(KERN_INFO, lynx->id, "resetting bus (short bus reset, force_root set) on request"); lynx->selfid_size = -1; lynx->phy_reg0 = -1; set_phy_reg(lynx, 5, phy_reg); /* set ISBR */ break; } else { PRINT(KERN_INFO, lynx->id, "cannot do short bus reset, because of old phy"); /* fall through to long bus reset */ } case LONG_RESET_FORCE_ROOT: phy_reg = get_phy_reg(lynx, 1); if (phy_reg == -1) { PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed"); retval = -1; break; } phy_reg |= 0xc0; PRINT(KERN_INFO, lynx->id, "resetting bus (long bus reset, force_root set) on request"); lynx->selfid_size = -1; lynx->phy_reg0 = -1; set_phy_reg(lynx, 1, phy_reg); /* set IBR and RHB */ break; default: PRINT(KERN_ERR, lynx->id, "unknown argument for reset_bus command %d", arg); retval = -1; } break; case GET_CYCLE_COUNTER: retval = reg_read(lynx, CYCLE_TIMER); break; case SET_CYCLE_COUNTER: reg_write(lynx, CYCLE_TIMER, arg); break; case SET_BUS_ID: reg_write(lynx, LINK_ID, (arg << 22) | (reg_read(lynx, LINK_ID) & 0x003f0000)); break; case ACT_CYCLE_MASTER: if (arg) { reg_set_bits(lynx, LINK_CONTROL, LINK_CONTROL_CYCMASTER); } else { reg_clear_bits(lynx, LINK_CONTROL, LINK_CONTROL_CYCMASTER); } break; case CANCEL_REQUESTS: spin_lock_irqsave(&lynx->async.queue_lock, flags); reg_write(lynx, DMA_CHAN_CTRL(CHANNEL_ASYNC_SEND), 0); list_splice(&lynx->async.queue, &packet_list); INIT_LIST_HEAD(&lynx->async.queue); if (list_empty(&lynx->async.pcl_queue)) { spin_unlock_irqrestore(&lynx->async.queue_lock, flags); PRINTD(KERN_DEBUG, lynx->id, "no async packet in PCL to cancel"); } else { struct ti_pcl pcl;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -