📄 pcilynx.c
字号:
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;
#if 0 /* has been removed from ieee1394 core */
d = (what == hpsb_iso ? &lynx->iso_send : &lynx->async);
#else
d = &lynx->async;
#endif
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_move_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;
pcl.buffer[0].control = packet->speed_code << 14 | packet->header_size;
#ifndef __BIG_ENDIAN
pcl.buffer[0].control |= 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;
#if 0 /* has been removed from ieee1394 core */
case hpsb_iso:
pcl.buffer[0].control |= PCL_CMD_XMT | PCL_ISOMODE;
break;
#endif
case hpsb_raw:
pcl.buffer[0].control |= PCL_CMD_UNFXMT;
break;
}
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 -EOVERFLOW;
}
switch (packet->type) {
case hpsb_async:
case hpsb_raw:
d = &lynx->async;
break;
#if 0 /* has been removed from ieee1394 core */
case hpsb_iso:
d = &lynx->iso_send;
break;
#endif
default:
PRINT(KERN_ERR, lynx->id, "invalid packet type %d",
packet->type);
return -EINVAL;
}
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 0;
}
/* 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;
u32 ack;
struct hpsb_packet *packet;
PRINT(KERN_INFO, lynx->id, "cancelling async packet, that was already in PCL");
get_pcl(lynx, lynx->async.pcl, &pcl);
packet = driver_packet(lynx->async.pcl_queue.next);
list_del_init(&packet->driver_list);
pci_unmap_single(lynx->dev, lynx->async.header_dma,
packet->header_size, PCI_DMA_TODEVICE);
if (packet->data_size) {
pci_unmap_single(lynx->dev, lynx->async.data_dma,
packet->data_size, PCI_DMA_TODEVICE);
}
spin_unlock_irqrestore(&lynx->async.queue_lock, flags);
if (pcl.pcl_status & DMA_CHAN_STAT_PKTCMPL) {
if (pcl.pcl_status & DMA_CHAN_STAT_SPECIALACK) {
ack = (pcl.pcl_status >> 15) & 0xf;
PRINTD(KERN_INFO, lynx->id, "special ack %d", ack);
ack = (ack == 1 ? ACKX_TIMEOUT : ACKX_SEND_ERROR);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -