📄 ohci1394.c
字号:
reg_write(ohci, reg, 0xffffffff);
tmp = reg_read(ohci, reg);
DBGMSG("Iso contexts reg: %08x implemented: %08x", reg, tmp);
/* Count the number of contexts */
for (i=0; i<32; i++) {
if (tmp & 1) ctx++;
tmp >>= 1;
}
return ctx;
}
/* Global initialization */
static void ohci_initialize(struct ti_ohci *ohci)
{
quadlet_t buf;
int num_ports, i;
spin_lock_init(&ohci->phy_reg_lock);
/* Put some defaults to these undefined bus options */
buf = reg_read(ohci, OHCI1394_BusOptions);
buf |= 0x60000000; /* Enable CMC and ISC */
if (hpsb_disable_irm)
buf &= ~0x80000000;
else
buf |= 0x80000000; /* Enable IRMC */
buf &= ~0x00ff0000; /* XXX: Set cyc_clk_acc to zero for now */
buf &= ~0x18000000; /* Disable PMC and BMC */
reg_write(ohci, OHCI1394_BusOptions, buf);
/* Set the bus number */
reg_write(ohci, OHCI1394_NodeID, 0x0000ffc0);
/* Enable posted writes */
reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_postedWriteEnable);
/* Clear link control register */
reg_write(ohci, OHCI1394_LinkControlClear, 0xffffffff);
/* Enable cycle timer and cycle master and set the IRM
* contender bit in our self ID packets if appropriate. */
reg_write(ohci, OHCI1394_LinkControlSet,
OHCI1394_LinkControl_CycleTimerEnable |
OHCI1394_LinkControl_CycleMaster);
i = get_phy_reg(ohci, 4) | PHY_04_LCTRL;
if (hpsb_disable_irm)
i &= ~PHY_04_CONTENDER;
else
i |= PHY_04_CONTENDER;
set_phy_reg(ohci, 4, i);
/* Set up self-id dma buffer */
reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->selfid_buf_bus);
/* enable self-id */
reg_write(ohci, OHCI1394_LinkControlSet, OHCI1394_LinkControl_RcvSelfID);
/* Set the Config ROM mapping register */
reg_write(ohci, OHCI1394_ConfigROMmap, ohci->csr_config_rom_bus);
/* Now get our max packet size */
ohci->max_packet_size =
1<<(((reg_read(ohci, OHCI1394_BusOptions)>>12)&0xf)+1);
/* Clear the interrupt mask */
reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff);
reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff);
/* Clear the interrupt mask */
reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff);
reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff);
/* Initialize AR dma */
initialize_dma_rcv_ctx(&ohci->ar_req_context, 0);
initialize_dma_rcv_ctx(&ohci->ar_resp_context, 0);
/* Initialize AT dma */
initialize_dma_trm_ctx(&ohci->at_req_context);
initialize_dma_trm_ctx(&ohci->at_resp_context);
/* Accept AR requests from all nodes */
reg_write(ohci, OHCI1394_AsReqFilterHiSet, 0x80000000);
/* Set the address range of the physical response unit.
* Most controllers do not implement it as a writable register though.
* They will keep a hardwired offset of 0x00010000 and show 0x0 as
* register content.
* To actually enable physical responses is the job of our interrupt
* handler which programs the physical request filter. */
reg_write(ohci, OHCI1394_PhyUpperBound,
OHCI1394_PHYS_UPPER_BOUND_PROGRAMMED >> 16);
DBGMSG("physUpperBoundOffset=%08x",
reg_read(ohci, OHCI1394_PhyUpperBound));
/* Specify AT retries */
reg_write(ohci, OHCI1394_ATRetries,
OHCI1394_MAX_AT_REQ_RETRIES |
(OHCI1394_MAX_AT_RESP_RETRIES<<4) |
(OHCI1394_MAX_PHYS_RESP_RETRIES<<8));
/* We don't want hardware swapping */
reg_write(ohci, OHCI1394_HCControlClear, OHCI1394_HCControl_noByteSwap);
/* Enable interrupts */
reg_write(ohci, OHCI1394_IntMaskSet,
OHCI1394_unrecoverableError |
OHCI1394_masterIntEnable |
OHCI1394_busReset |
OHCI1394_selfIDComplete |
OHCI1394_RSPkt |
OHCI1394_RQPkt |
OHCI1394_respTxComplete |
OHCI1394_reqTxComplete |
OHCI1394_isochRx |
OHCI1394_isochTx |
OHCI1394_postedWriteErr |
OHCI1394_cycleTooLong |
OHCI1394_cycleInconsistent);
/* Enable link */
reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_linkEnable);
buf = reg_read(ohci, OHCI1394_Version);
PRINT(KERN_INFO, "OHCI-1394 %d.%d (PCI): IRQ=[%d] "
"MMIO=[%llx-%llx] Max Packet=[%d] IR/IT contexts=[%d/%d]",
((((buf) >> 16) & 0xf) + (((buf) >> 20) & 0xf) * 10),
((((buf) >> 4) & 0xf) + ((buf) & 0xf) * 10), ohci->dev->irq,
(unsigned long long)pci_resource_start(ohci->dev, 0),
(unsigned long long)pci_resource_start(ohci->dev, 0) + OHCI1394_REGISTER_SIZE - 1,
ohci->max_packet_size,
ohci->nb_iso_rcv_ctx, ohci->nb_iso_xmit_ctx);
/* Check all of our ports to make sure that if anything is
* connected, we enable that port. */
num_ports = get_phy_reg(ohci, 2) & 0xf;
for (i = 0; i < num_ports; i++) {
unsigned int status;
set_phy_reg(ohci, 7, i);
status = get_phy_reg(ohci, 8);
if (status & 0x20)
set_phy_reg(ohci, 8, status & ~1);
}
/* Serial EEPROM Sanity check. */
if ((ohci->max_packet_size < 512) ||
(ohci->max_packet_size > 4096)) {
/* Serial EEPROM contents are suspect, set a sane max packet
* size and print the raw contents for bug reports if verbose
* debug is enabled. */
#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
int i;
#endif
PRINT(KERN_DEBUG, "Serial EEPROM has suspicious values, "
"attempting to set max_packet_size to 512 bytes");
reg_write(ohci, OHCI1394_BusOptions,
(reg_read(ohci, OHCI1394_BusOptions) & 0xf007) | 0x8002);
ohci->max_packet_size = 512;
#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
PRINT(KERN_DEBUG, " EEPROM Present: %d",
(reg_read(ohci, OHCI1394_Version) >> 24) & 0x1);
reg_write(ohci, OHCI1394_GUID_ROM, 0x80000000);
for (i = 0;
((i < 1000) &&
(reg_read(ohci, OHCI1394_GUID_ROM) & 0x80000000)); i++)
udelay(10);
for (i = 0; i < 0x20; i++) {
reg_write(ohci, OHCI1394_GUID_ROM, 0x02000000);
PRINT(KERN_DEBUG, " EEPROM %02x: %02x", i,
(reg_read(ohci, OHCI1394_GUID_ROM) >> 16) & 0xff);
}
#endif
}
}
/*
* Insert a packet in the DMA fifo and generate the DMA prg
* FIXME: rewrite the program in order to accept packets crossing
* page boundaries.
* check also that a single dma descriptor doesn't cross a
* page boundary.
*/
static void insert_packet(struct ti_ohci *ohci,
struct dma_trm_ctx *d, struct hpsb_packet *packet)
{
u32 cycleTimer;
int idx = d->prg_ind;
DBGMSG("Inserting packet for node " NODE_BUS_FMT
", tlabel=%d, tcode=0x%x, speed=%d",
NODE_BUS_ARGS(ohci->host, packet->node_id), packet->tlabel,
packet->tcode, packet->speed_code);
d->prg_cpu[idx]->begin.address = 0;
d->prg_cpu[idx]->begin.branchAddress = 0;
if (d->type == DMA_CTX_ASYNC_RESP) {
/*
* For response packets, we need to put a timeout value in
* the 16 lower bits of the status... let's try 1 sec timeout
*/
cycleTimer = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
d->prg_cpu[idx]->begin.status = cpu_to_le32(
(((((cycleTimer>>25)&0x7)+1)&0x7)<<13) |
((cycleTimer&0x01fff000)>>12));
DBGMSG("cycleTimer: %08x timeStamp: %08x",
cycleTimer, d->prg_cpu[idx]->begin.status);
} else
d->prg_cpu[idx]->begin.status = 0;
if ( (packet->type == hpsb_async) || (packet->type == hpsb_raw) ) {
if (packet->type == hpsb_raw) {
d->prg_cpu[idx]->data[0] = cpu_to_le32(OHCI1394_TCODE_PHY<<4);
d->prg_cpu[idx]->data[1] = cpu_to_le32(packet->header[0]);
d->prg_cpu[idx]->data[2] = cpu_to_le32(packet->header[1]);
} else {
d->prg_cpu[idx]->data[0] = packet->speed_code<<16 |
(packet->header[0] & 0xFFFF);
if (packet->tcode == TCODE_ISO_DATA) {
/* Sending an async stream packet */
d->prg_cpu[idx]->data[1] = packet->header[0] & 0xFFFF0000;
} else {
/* Sending a normal async request or response */
d->prg_cpu[idx]->data[1] =
(packet->header[1] & 0xFFFF) |
(packet->header[0] & 0xFFFF0000);
d->prg_cpu[idx]->data[2] = packet->header[2];
d->prg_cpu[idx]->data[3] = packet->header[3];
}
header_le32_to_cpu(d->prg_cpu[idx]->data, packet->tcode);
}
if (packet->data_size) { /* block transmit */
if (packet->tcode == TCODE_STREAM_DATA){
d->prg_cpu[idx]->begin.control =
cpu_to_le32(DMA_CTL_OUTPUT_MORE |
DMA_CTL_IMMEDIATE | 0x8);
} else {
d->prg_cpu[idx]->begin.control =
cpu_to_le32(DMA_CTL_OUTPUT_MORE |
DMA_CTL_IMMEDIATE | 0x10);
}
d->prg_cpu[idx]->end.control =
cpu_to_le32(DMA_CTL_OUTPUT_LAST |
DMA_CTL_IRQ |
DMA_CTL_BRANCH |
packet->data_size);
/*
* Check that the packet data buffer
* does not cross a page boundary.
*
* XXX Fix this some day. eth1394 seems to trigger
* it, but ignoring it doesn't seem to cause a
* problem.
*/
#if 0
if (cross_bound((unsigned long)packet->data,
packet->data_size)>0) {
/* FIXME: do something about it */
PRINT(KERN_ERR,
"%s: packet data addr: %p size %Zd bytes "
"cross page boundary", __FUNCTION__,
packet->data, packet->data_size);
}
#endif
d->prg_cpu[idx]->end.address = cpu_to_le32(
pci_map_single(ohci->dev, packet->data,
packet->data_size,
PCI_DMA_TODEVICE));
d->prg_cpu[idx]->end.branchAddress = 0;
d->prg_cpu[idx]->end.status = 0;
if (d->branchAddrPtr)
*(d->branchAddrPtr) =
cpu_to_le32(d->prg_bus[idx] | 0x3);
d->branchAddrPtr =
&(d->prg_cpu[idx]->end.branchAddress);
} else { /* quadlet transmit */
if (packet->type == hpsb_raw)
d->prg_cpu[idx]->begin.control =
cpu_to_le32(DMA_CTL_OUTPUT_LAST |
DMA_CTL_IMMEDIATE |
DMA_CTL_IRQ |
DMA_CTL_BRANCH |
(packet->header_size + 4));
else
d->prg_cpu[idx]->begin.control =
cpu_to_le32(DMA_CTL_OUTPUT_LAST |
DMA_CTL_IMMEDIATE |
DMA_CTL_IRQ |
DMA_CTL_BRANCH |
packet->header_size);
if (d->branchAddrPtr)
*(d->branchAddrPtr) =
cpu_to_le32(d->prg_bus[idx] | 0x2);
d->branchAddrPtr =
&(d->prg_cpu[idx]->begin.branchAddress);
}
} else { /* iso packet */
d->prg_cpu[idx]->data[0] = packet->speed_code<<16 |
(packet->header[0] & 0xFFFF);
d->prg_cpu[idx]->data[1] = packet->header[0] & 0xFFFF0000;
header_le32_to_cpu(d->prg_cpu[idx]->data, packet->tcode);
d->prg_cpu[idx]->begin.control =
cpu_to_le32(DMA_CTL_OUTPUT_MORE |
DMA_CTL_IMMEDIATE | 0x8);
d->prg_cpu[idx]->end.control =
cpu_to_le32(DMA_CTL_OUTPUT_LAST |
DMA_CTL_UPDATE |
DMA_CTL_IRQ |
DMA_CTL_BRANCH |
packet->data_size);
d->prg_cpu[idx]->end.address = cpu_to_le32(
pci_map_single(ohci->dev, packet->data,
packet->data_size, PCI_DMA_TODEVICE));
d->prg_cpu[idx]->end.branchAddress = 0;
d->prg_cpu[idx]->end.status = 0;
DBGMSG("Iso xmit context info: header[%08x %08x]\n"
" begin=%08x %08x %08x %08x\n"
" %08x %08x %08x %08x\n"
" end =%08x %08x %08x %08x",
d->prg_cpu[idx]->data[0], d->prg_cpu[idx]->data[1],
d->prg_cpu[idx]->begin.control,
d->prg_cpu[idx]->begin.address,
d->prg_cpu[idx]->begin.branchAddress,
d->prg_cpu[idx]->begin.status,
d->prg_cpu[idx]->data[0],
d->prg_cpu[idx]->data[1],
d->prg_cpu[idx]->data[2],
d->prg_cpu[idx]->data[3],
d->prg_cpu[idx]->end.control,
d->prg_cpu[idx]->end.address,
d->prg_cpu[idx]->end.branchAddress,
d->prg_cpu[idx]->end.status);
if (d->branchAddrPtr)
*(d->branchAddrPtr) = cpu_to_le32(d->prg_bus[idx] | 0x3);
d->branchAddrPtr = &(d->prg_cpu[idx]->end.branchAddress);
}
d->free_prgs--;
/* queue the packet in the appropriate context queue */
list_add_tail(&packet->driver_list, &d->fifo_list);
d->prg_ind = (d->prg_ind + 1) % d->num_desc;
}
/*
* This function fills the FIFO with the (eventual) pending packets
* and runs or wakes up the DMA prg if necessary.
*
* The function MUST be called with the d->lock held.
*/
static void dma_trm_flush(struct ti_ohci *ohci, struct dma_trm_ctx *d)
{
struct hpsb_packet *packet, *ptmp;
int idx = d->prg_ind;
int z = 0;
/* insert the packets into the dma fifo */
list_for_each_entry_safe(packet, ptmp, &d->pending_list, driver_list) {
if (!d->free_prgs)
break;
/* For the first packet only */
if (!z)
z = (packet->data_size) ? 3 : 2;
/* Insert the packet */
list_del_init(&packet->driver_list);
insert_packet(ohci, d, packet);
}
/* Nothing must have been done, either no free_prgs or no packets */
if (z == 0)
return;
/* Is the context running ? (should be unless it is
the first packet to be sent in this context) */
if (!(reg_read(ohci, d->ctrlSet) & 0x8000)) {
u32 nodeId = reg_read(ohci, OHCI1394_NodeID);
DBGMSG("Starting transmit DMA ctx=%d",d->ctx);
reg_write(ohci, d->cmdPtr, d->prg_bus[idx] | z);
/* Check that the node id is valid, and not 63 */
if (!(nodeId & 0x80000000) || (nodeId & 0x3f) == 63)
PRINT(KERN_ERR, "Running dma failed because Node ID is not valid");
else
reg_write(ohci, d->ctrlSet, 0x8000);
} else {
/* Wake up the dma context if necessary */
if (!(reg_read(ohci, d->ctrlSet) & 0x400))
DBGMSG("Waking transmit DMA ctx=%d",d->ctx);
/* do this always, to avoid race condition */
reg_write(ohci, d->ctrlSet, 0x1000);
}
return;
}
/* Transmission of an async or iso packet */
static int ohci_transmit(struct hpsb_host *host, struct hpsb_packet *packet)
{
struct ti_ohci *ohci = host->hostdata;
struct dma_trm_ctx *d;
unsigned long flags;
if (packet->data_size > ohci->max_packet_size) {
PRINT(KERN_ERR,
"Transmit packet size %Zd is too big",
packet->data_size);
return -EOVERFLOW;
}
if (packet->type == hpsb_raw)
d = &ohci->at_req_context;
else if ((packet->tcode & 0x02) && (packet->tcode != TCODE_ISO_DATA))
d = &ohci->at_resp_context;
else
d = &ohci->at_req_context;
spin_lock_irqsave(&d->lock,flags);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -