📄 ohci1394.c
字号:
static void initialize_dma_trm_ctx(struct dma_trm_ctx *d){ struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci); /* Stop the context */ ohci1394_stop_context(ohci, d->ctrlClear, NULL); d->prg_ind = 0; d->sent_ind = 0; d->free_prgs = d->num_desc; d->branchAddrPtr = NULL; d->fifo_first = NULL; d->fifo_last = NULL; d->pending_first = NULL; d->pending_last = NULL; DBGMSG(ohci->id, "Transmit DMA ctx=%d initialized", d->ctx);}/* Count the number of available iso contexts */static int get_nb_iso_ctx(struct ti_ohci *ohci, int reg){ int i,ctx=0; u32 tmp; reg_write(ohci, reg, 0xffffffff); tmp = reg_read(ohci, reg); DBGMSG(ohci->id,"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;}static void ohci_init_config_rom(struct ti_ohci *ohci);/* Global initialization */static int ohci_initialize(struct hpsb_host *host){ struct ti_ohci *ohci=host->hostdata; int retval, i; quadlet_t buf; spin_lock_init(&ohci->phy_reg_lock); spin_lock_init(&ohci->event_lock); /* Soft reset */ if ((retval = ohci_soft_reset(ohci)) < 0) return retval; /* Put some defaults to these undefined bus options */ buf = reg_read(ohci, OHCI1394_BusOptions); buf |= 0x60000000; /* Enable CMC and ISC */ buf &= ~0x00ff0000; /* XXX: Set cyc_clk_acc to zero for now */ buf &= ~0x98000000; /* Disable PMC, IRMC and BMC */ reg_write(ohci, OHCI1394_BusOptions, buf); /* Set Link Power Status (LPS) */ reg_write(ohci, OHCI1394_HCControlSet, 0x00080000); /* After enabling LPS, we need to wait for the connection * between phy and link to be established. This should be * signaled by the LPS bit becoming 1, but this happens * immediately. There seems to be no consistent way to wait * for this, but 50ms seems to be enough. */ mdelay(50); /* Set the bus number */ reg_write(ohci, OHCI1394_NodeID, 0x0000ffc0); /* Enable posted writes */ reg_write(ohci, OHCI1394_HCControlSet, 0x00040000); /* Clear link control register */ reg_write(ohci, OHCI1394_LinkControlClear, 0xffffffff); /* Enable cycle timer and cycle master */ reg_write(ohci, OHCI1394_LinkControlSet, 0x00300000); /* Clear interrupt registers */ reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff); reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff); /* Set up self-id dma buffer */ reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->selfid_buf_bus); /* enable self-id dma */ reg_write(ohci, OHCI1394_LinkControlSet, 0x00000200); /* Set the Config ROM mapping register */ reg_write(ohci, OHCI1394_ConfigROMmap, ohci->csr_config_rom_bus); /* Initialize the Config ROM */ ohci_init_config_rom(ohci); /* Now get our max packet size */ ohci->max_packet_size = 1<<(((reg_read(ohci, OHCI1394_BusOptions)>>12)&0xf)+1); /* Don't accept phy packets into AR request context */ reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400); /* Initialize IR dma */ ohci->nb_iso_rcv_ctx = get_nb_iso_ctx(ohci, OHCI1394_IsoRecvIntMaskSet); DBGMSG(ohci->id, "%d iso receive contexts available", ohci->nb_iso_rcv_ctx); for (i=0;i<ohci->nb_iso_rcv_ctx;i++) { reg_write(ohci, OHCI1394_IsoRcvContextControlClear+32*i, 0xffffffff); reg_write(ohci, OHCI1394_IsoRcvContextMatch+32*i, 0); reg_write(ohci, OHCI1394_IsoRcvCommandPtr+32*i, 0); } /* Set bufferFill, isochHeader, multichannel for IR context */ reg_write(ohci, OHCI1394_IsoRcvContextControlSet, 0xd0000000); /* Set the context match register to match on all tags */ reg_write(ohci, OHCI1394_IsoRcvContextMatch, 0xf0000000); /* Clear the interrupt mask */ reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff); reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff); /* Initialize IT dma */ ohci->nb_iso_xmit_ctx = get_nb_iso_ctx(ohci, OHCI1394_IsoXmitIntMaskSet); DBGMSG(ohci->id, "%d iso transmit contexts available", ohci->nb_iso_xmit_ctx); for (i=0;i<ohci->nb_iso_xmit_ctx;i++) { reg_write(ohci, OHCI1394_IsoXmitContextControlClear+32*i, 0xffffffff); reg_write(ohci, OHCI1394_IsoXmitCommandPtr+32*i, 0); } /* Clear the interrupt mask */ reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff); reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff); /* Clear the multi channel mask high and low registers */ reg_write(ohci, OHCI1394_IRMultiChanMaskHiClear, 0xffffffff); reg_write(ohci, OHCI1394_IRMultiChanMaskLoClear, 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); /* Initialize IR dma */ initialize_dma_rcv_ctx(ohci->ir_context, 1); /* Initialize IT dma */ initialize_dma_trm_ctx(ohci->it_context); /* Set up isoRecvIntMask to generate interrupts for context 0 (thanks to Michael Greger for seeing that I forgot this) */ reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 0x00000001); /* Set up isoXmitIntMask to generate interrupts for context 0 */ reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 0x00000001); /* * Accept AT requests from all nodes. This probably * will have to be controlled from the subsystem * on a per node basis. */ reg_write(ohci,OHCI1394_AsReqFilterHiSet, 0x80000000); /* 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, 0x40000000); /* Enable interrupts */ reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_masterIntEnable | OHCI1394_busReset | OHCI1394_selfIDComplete | OHCI1394_RSPkt | OHCI1394_RQPkt | OHCI1394_respTxComplete | OHCI1394_reqTxComplete | OHCI1394_isochRx | OHCI1394_isochTx | OHCI1394_unrecoverableError ); /* Enable link */ reg_write(ohci, OHCI1394_HCControlSet, 0x00020000); buf = reg_read(ohci, OHCI1394_Version); PRINT(KERN_INFO, ohci->id, "OHCI-1394 %d.%d (PCI): IRQ=[%d] MMIO=[%lx-%lx]" " Max Packet=[%d]", ((((buf) >> 16) & 0xf) + (((buf) >> 20) & 0xf) * 10), ((((buf) >> 4) & 0xf) + ((buf) & 0xf) * 10), ohci->dev->irq, pci_resource_start(ohci->dev, 0), pci_resource_start(ohci->dev, 0) + pci_resource_len(ohci->dev, 0), ohci->max_packet_size); return 1;}static void ohci_remove(struct hpsb_host *host){ struct ti_ohci *ohci; if (host != NULL) { ohci = host->hostdata; remove_card(ohci); }}/* * Insert a packet in the AT 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(ohci->id, "Inserting packet for node %d, tlabel=%d, tcode=0x%x, speed=%d", 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->ctx==1) { /* * 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(ohci->id, "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] = packet->header[0]; d->prg_cpu[idx]->data[2] = packet->header[1]; } else { d->prg_cpu[idx]->data[0] = packet->speed_code<<16 | (packet->header[0] & 0xFFFF); 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]; packet_swab(d->prg_cpu[idx]->data, packet->tcode, packet->header_size>>2); } if (packet->data_size) { /* block transmit */ 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. */ if (cross_bound((unsigned long)packet->data, packet->data_size)>0) { /* FIXME: do something about it */ PRINT(KERN_ERR, ohci->id, __FUNCTION__ ": packet data addr: %p size %Zd bytes " "cross page boundary", packet->data, 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)); OHCI_DMA_ALLOC("single, block transmit packet"); 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; packet_swab(d->prg_cpu[idx]->data, packet->tcode, packet->header_size>>2); 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)); OHCI_DMA_ALLOC("single, iso transmit packet"); d->prg_cpu[idx]->end.branchAddress = 0; d->prg_cpu[idx]->end.status = 0; DBGMSG(ohci->id, "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 */ if (d->fifo_last) { d->fifo_last->xnext = packet; d->fifo_last = packet; } else { d->fifo_first = packet; d->fifo_last = packet; } d->prg_ind = (d->prg_ind+1)%d->num_desc;}/* * This function fills the AT FIFO with the (eventual) pending packets * and runs or wakes up the AT DMA prg if necessary. * * The function MUST be called with the d->lock held. */ static int dma_trm_flush(struct ti_ohci *ohci, struct dma_trm_ctx *d){ int idx,z; if (d->pending_first == NULL || d->free_prgs == 0) return 0; idx = d->prg_ind; z = (d->pending_first->data_size) ? 3 : 2; /* insert the packets into the at dma fifo */ while (d->free_prgs>0 && d->pending_first) { insert_packet(ohci, d, d->pending_first); d->pending_first = d->pending_first->xnext; } if (d->pending_first == NULL) d->pending_last = NULL; else PRINT(KERN_INFO, ohci->id, "Transmit DMA FIFO ctx=%d is full... waiting",d->ctx); /* 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)) { DBGMSG(ohci->id,"Starting transmit DMA ctx=%d",d->ctx); reg_write(ohci, d->cmdPtr, d->prg_bus[idx]|z); run_context(ohci, d->ctrlSet, NULL); } else { /* Wake up the dma context if necessary */ if (!(reg_read(ohci, d->ctrlSet) & 0x400)) { DBGMSG(ohci->id,"Waking transmit DMA ctx=%d",d->ctx); reg_write(ohci, d->ctrlSet, 0x1000); } } return 1;}/* Transmission of an async 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 char tcode; unsigned long flags; if (packet->data_size > ohci->max_packet_size) { PRINT(KERN_ERR, ohci->id, "Transmit packet size %Zd is too big", packet->data_size); return 0; } packet->xnext = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -