📄 ohci1394.c
字号:
/* Soft reset */ if ((retval=ohci_soft_reset(ohci))<0) return retval; /* * Delay after soft reset to make sure everything has settled * down (sanity) */ mdelay(100); /* Set Link Power Status (LPS) */ reg_write(ohci, OHCI1394_HCControlSet, 0x00080000); /* * Delay after setting LPS in order to make sure link/phy * communication is established */ mdelay(100); /* 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 configuration ROM mapping register */ reg_write(ohci, OHCI1394_ConfigROMmap, ohci->csr_config_rom_bus); /* Set bus options */ reg_write(ohci, OHCI1394_BusOptions, cpu_to_be32(ohci->csr_config_rom_cpu[2]));#if 0 /* Write the GUID into the csr config rom */ ohci->csr_config_rom_cpu[3] = be32_to_cpu(reg_read(ohci, OHCI1394_GUIDHi)); ohci->csr_config_rom_cpu[4] = be32_to_cpu(reg_read(ohci, OHCI1394_GUIDLo));#endif /* Write the config ROM header */ reg_write(ohci, OHCI1394_ConfigROMhdr, cpu_to_be32(ohci->csr_config_rom_cpu[0])); ohci->max_packet_size = 1<<(((reg_read(ohci, OHCI1394_BusOptions)>>12)&0xf)+1); PRINT(KERN_INFO, ohci->id, "max packet size = %d bytes", ohci->max_packet_size); /* 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); PRINT(KERN_INFO, 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); PRINT(KERN_INFO, 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); initialize_dma_rcv_ctx(ohci->ar_resp_context); /* 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); /* 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); /* * 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));#ifndef __BIG_ENDIAN reg_write(ohci, OHCI1394_HCControlClear, 0x40000000);#else reg_write(ohci, OHCI1394_HCControlSet, 0x40000000);#endif /* Enable interrupts */ reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_masterIntEnable | OHCI1394_phyRegRcvd | OHCI1394_busReset | OHCI1394_selfIDComplete | OHCI1394_RSPkt | OHCI1394_RQPkt | OHCI1394_ARRS | OHCI1394_ARRQ | OHCI1394_respTxComplete | OHCI1394_reqTxComplete | OHCI1394_isochRx | OHCI1394_isochTx ); /* Enable link */ reg_write(ohci, OHCI1394_HCControlSet, 0x00020000); 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; 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 = (((((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 == raw) { d->prg_cpu[idx]->data[0] = 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]; } if (packet->data_size) { /* block transmit */ d->prg_cpu[idx]->begin.control = OUTPUT_MORE_IMMEDIATE | 0x10; d->prg_cpu[idx]->end.control = OUTPUT_LAST | packet->data_size; /* * FIXME: check that the packet data buffer * do 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 %d bytes " "cross page boundary", packet->data, packet->data_size); } d->prg_cpu[idx]->end.address = 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) = d->prg_bus[idx] | 0x3; d->branchAddrPtr = &(d->prg_cpu[idx]->end.branchAddress); } else { /* quadlet transmit */ if (packet->type == raw) d->prg_cpu[idx]->begin.control = OUTPUT_LAST_IMMEDIATE|(packet->header_size+4); else d->prg_cpu[idx]->begin.control = OUTPUT_LAST_IMMEDIATE|packet->header_size; if (d->branchAddrPtr) *(d->branchAddrPtr) = d->prg_bus[idx] | 0x2; d->branchAddrPtr = &(d->prg_cpu[idx]->begin.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 wake 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, "AT DMA FIFO ctx=%d 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 AT DMA ctx=%d",d->ctx); reg_write(ohci, d->cmdPtr, d->prg_bus[idx]|z); run_context(ohci, d->ctrlSet, NULL); } else { DBGMSG(ohci->id,"Waking AT DMA ctx=%d",d->ctx); /* wake up the dma context if necessary */ if (!(reg_read(ohci, d->ctrlSet) & 0x400)) 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 = %d too big", packet->data_size); return 0; } packet->xnext = NULL; /* Decide wether we have a request or a response packet */ tcode = (packet->header[0]>>4)&0xf; if (tcode & 0x02) d = ohci->at_resp_context; else d = ohci->at_req_context; spin_lock_irqsave(&d->lock,flags); /* queue the packet for later insertion into to dma fifo */ if (d->pending_last) { d->pending_last->xnext = packet; d->pending_last = packet; } else { d->pending_first = packet; d->pending_last = packet; } dma_trm_flush(ohci, d); spin_unlock_irqrestore(&d->lock,flags); return 1;}static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg){ struct ti_ohci *ohci = host->hostdata; int retval = 0; unsigned long flags; switch (cmd) { case RESET_BUS: /* * FIXME: this flag might be necessary in some case */ PRINT(KERN_INFO, ohci->id, "resetting bus on request%s", ((host->attempt_root || attempt_root) ? " and attempting to become root" : "")); reg_write(ohci, OHCI1394_PhyControl, (host->attempt_root || attempt_root) ? 0x000041ff : 0x0000417f); break; case GET_CYCLE_COUNTER: retval = reg_read(ohci, OHCI1394_IsochronousCycleTimer); break; case SET_CYCLE_COUNTER: reg_write(ohci, OHCI1394_IsochronousCycleTimer, arg); break; case SET_BUS_ID: PRINT(KERN_ERR, ohci->id, "devctl command SET_BUS_ID err"); break; case ACT_CYCLE_MASTER: if (arg) { /* check if we are root and other nodes are present */ u32 nodeId = reg_read(ohci, OHCI1394_NodeID); if ((nodeId & (1<<30)) && (nodeId & 0x3f)) { /* * enable cycleTimer, cycleMaster */ DBGMSG(ohci->id, "Cycle master enabled"); reg_write(ohci, OHCI1394_LinkControlSet, 0x00300000); } } else { /* disable cycleTimer, cycleMaster, cycleSource */ reg_write(ohci, OHCI1394_LinkControlClear, 0x00700000); } break; case CANCEL_REQUESTS: DBGMSG(ohci->id, "Cancel request received"); dma_trm_reset(ohci->at_req_context); dma_trm_reset(ohci->at_resp_context); break; case MODIFY_USAGE: if (arg) { MOD_INC_USE_COUNT; } else { MOD_DEC_USE_COUNT; } break; case ISO_LISTEN_CHANNEL: { u64 mask; if (arg<0 || arg>63) { PRINT(KERN_ERR, ohci->id, __FUNCTION__ "IS0_LISTEN_CHANNEL channel %d out of range", arg); return -EFAULT; } mask = (u64)0x1<<arg; spin_lock_irqsave(&ohci->IR_channel_lock, flags); if (ohci->ISO_channel_usage & mask) { PRINT(KERN_ERR, ohci->id, __FUNCTION__ "IS0_LISTEN_CHANNEL channel %d already used", arg); spin_unlock_irqrestore(&ohci->IR_channel_lock, flags); return -EFAULT; } ohci->ISO_channel_usage |= mask; if (arg>31) reg_write(ohci, OHCI1394_IRMultiChanMaskHiSet, 1<<(arg-32)); else reg_write(ohci, OHCI1394_IRMultiChanMaskLoSet, 1<<arg); spin_unlock_irqrestore(&ohci->IR_channel_lock, flags); DBGMSG(ohci->id, "listening enabled on channel %d", arg); break; } case ISO_UNLISTEN_CHANNEL: { u64 mask; if (arg<0 || arg>63) { PRINT(KERN_ERR, ohci->id, __FUNCTION__ "IS0_UNLISTEN_CHANNEL channel %d out of range", arg); return -EFAULT; } mask = (u64)0x1<<arg; spin_lock_irqsave(&ohci->IR_channel_lock, flags);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -