📄 ohci1394.c
字号:
/* Decide wether we have an iso, a request, or a response packet */ tcode = (packet->header[0]>>4)&0xf; if (tcode == TCODE_ISO_DATA) d = ohci->it_context; else 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 the 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: DBGMSG(ohci->id, "devctl: Bus reset requested%s", ((host->attempt_root || attempt_root) ? " and attempting to become root" : "")); set_phy_reg_mask (ohci, 1, 0x40 | ((host->attempt_root || attempt_root) ? 0x80 : 0)); 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 %d is 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 %d is 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 %d is 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 unlisten channel %d is not used", arg); spin_unlock_irqrestore(&ohci->IR_channel_lock, flags); return -EFAULT; } ohci->ISO_channel_usage &= ~mask; if (arg>31) reg_write(ohci, OHCI1394_IRMultiChanMaskHiClear, 1<<(arg-32)); else reg_write(ohci, OHCI1394_IRMultiChanMaskLoClear, 1<<arg); spin_unlock_irqrestore(&ohci->IR_channel_lock, flags); DBGMSG(ohci->id, "Listening disabled on channel %d", arg); break; } default: PRINT_G(KERN_ERR, "ohci_devctl cmd %d not implemented yet", cmd); break; } return retval;}/*************************************** * IEEE-1394 functionality section END * ***************************************//******************************************************** * Global stuff (interrupt handler, init/shutdown code) * ********************************************************/static void dma_trm_reset(struct dma_trm_ctx *d){ struct ti_ohci *ohci; unsigned long flags; struct hpsb_packet *nextpacket; if (d==NULL) { PRINT_G(KERN_ERR, "dma_trm_reset called with NULL arg"); return; } ohci = (struct ti_ohci *)(d->ohci); ohci1394_stop_context(ohci, d->ctrlClear, NULL); spin_lock_irqsave(&d->lock,flags); /* Is there still any packet pending in the fifo ? */ while(d->fifo_first) { PRINT(KERN_INFO, ohci->id, "AT dma reset ctx=%d, aborting transmission", d->ctx); nextpacket = d->fifo_first->xnext; hpsb_packet_sent(ohci->host, d->fifo_first, ACKX_ABORTED); d->fifo_first = nextpacket; } d->fifo_first = d->fifo_last = NULL; /* is there still any packet pending ? */ while(d->pending_first) { PRINT(KERN_INFO, ohci->id, "AT dma reset ctx=%d, aborting transmission", d->ctx); nextpacket = d->pending_first->xnext; hpsb_packet_sent(ohci->host, d->pending_first, ACKX_ABORTED); d->pending_first = nextpacket; } d->pending_first = d->pending_last = NULL; d->branchAddrPtr=NULL; d->sent_ind = d->prg_ind; d->free_prgs = d->num_desc; spin_unlock_irqrestore(&d->lock,flags);}static void ohci_irq_handler(int irq, void *dev_id, struct pt_regs *regs_are_unused){ quadlet_t event, node_id; struct ti_ohci *ohci = (struct ti_ohci *)dev_id; struct hpsb_host *host = ohci->host; int phyid = -1, isroot = 0; unsigned long flags; /* Read and clear the interrupt event register. Don't clear * the busReset event, though, this is done when we get the * selfIDComplete interrupt. */ spin_lock_irqsave(&ohci->event_lock, flags); event = reg_read(ohci, OHCI1394_IntEventClear); reg_write(ohci, OHCI1394_IntEventClear, event & ~OHCI1394_busReset); spin_unlock_irqrestore(&ohci->event_lock, flags); if (!event) return; DBGMSG(ohci->id, "IntEvent: %08x", event); /* Die right here an now */ if (event & OHCI1394_unrecoverableError) { PRINT(KERN_ERR, ohci->id, "Unrecoverable error, shutting down card!"); remove_card(ohci); return; } if (event & OHCI1394_busReset) { /* The busReset event bit can't be cleared during the * selfID phase, so we disable busReset interrupts, to * avoid burying the cpu in interrupt requests. */ spin_lock_irqsave(&ohci->event_lock, flags); reg_write(ohci, OHCI1394_IntMaskClear, OHCI1394_busReset); if (ohci->dev->vendor == PCI_VENDOR_ID_APPLE && ohci->dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW) { udelay(10); while(reg_read(ohci, OHCI1394_IntEventSet) & OHCI1394_busReset) { reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset); spin_unlock_irqrestore(&ohci->event_lock, flags); udelay(10); spin_lock_irqsave(&ohci->event_lock, flags); } } spin_unlock_irqrestore(&ohci->event_lock, flags); if (!host->in_bus_reset) { DBGMSG(ohci->id, "irq_handler: Bus reset requested%s", ((host->attempt_root || attempt_root) ? " and attempting to become root" : "")); /* Subsystem call */ hpsb_bus_reset(ohci->host); } event &= ~OHCI1394_busReset; } /* XXX: We need a way to also queue the OHCI1394_reqTxComplete, * but for right now we simply run it upon reception, to make sure * we get sent acks before response packets. This sucks mainly * because it halts the interrupt handler. */ if (event & OHCI1394_reqTxComplete) { struct dma_trm_ctx *d = ohci->at_req_context; DBGMSG(ohci->id, "Got reqTxComplete interrupt " "status=0x%08X", reg_read(ohci, d->ctrlSet)); if (reg_read(ohci, d->ctrlSet) & 0x800) ohci1394_stop_context(ohci, d->ctrlClear, "reqTxComplete"); else dma_trm_tasklet ((unsigned long)d); event &= ~OHCI1394_reqTxComplete; } if (event & OHCI1394_respTxComplete) { struct dma_trm_ctx *d = ohci->at_resp_context; DBGMSG(ohci->id, "Got respTxComplete interrupt " "status=0x%08X", reg_read(ohci, d->ctrlSet)); if (reg_read(ohci, d->ctrlSet) & 0x800) ohci1394_stop_context(ohci, d->ctrlClear, "respTxComplete"); else tasklet_schedule(&d->task); event &= ~OHCI1394_respTxComplete; } if (event & OHCI1394_RQPkt) { struct dma_rcv_ctx *d = ohci->ar_req_context; DBGMSG(ohci->id, "Got RQPkt interrupt status=0x%08X", reg_read(ohci, d->ctrlSet)); if (reg_read(ohci, d->ctrlSet) & 0x800) ohci1394_stop_context(ohci, d->ctrlClear, "RQPkt"); else tasklet_schedule(&d->task); event &= ~OHCI1394_RQPkt; } if (event & OHCI1394_RSPkt) { struct dma_rcv_ctx *d = ohci->ar_resp_context; DBGMSG(ohci->id, "Got RSPkt interrupt status=0x%08X", reg_read(ohci, d->ctrlSet)); if (reg_read(ohci, d->ctrlSet) & 0x800) ohci1394_stop_context(ohci, d->ctrlClear, "RSPkt"); else tasklet_schedule(&d->task); event &= ~OHCI1394_RSPkt; } if (event & OHCI1394_isochRx) { quadlet_t isoRecvIntEvent; struct dma_rcv_ctx *d = ohci->ir_context; isoRecvIntEvent = reg_read(ohci, OHCI1394_IsoRecvIntEventSet); reg_write(ohci, OHCI1394_IsoRecvIntEventClear, isoRecvIntEvent); DBGMSG(ohci->id, "Got isochRx interrupt " "status=0x%08X isoRecvIntEvent=%08x", reg_read(ohci, d->ctrlSet), isoRecvIntEvent); if (isoRecvIntEvent & 0x1) { if (reg_read(ohci, d->ctrlSet) & 0x800) ohci1394_stop_context(ohci, d->ctrlClear, "isochRx"); else tasklet_schedule(&d->task); } if (ohci->video_tmpl) ohci->video_tmpl->irq_handler(ohci->id, isoRecvIntEvent, 0); event &= ~OHCI1394_isochRx; } if (event & OHCI1394_isochTx) { quadlet_t isoXmitIntEvent; struct dma_trm_ctx *d = ohci->it_context; isoXmitIntEvent = reg_read(ohci, OHCI1394_IsoXmitIntEventSet); reg_write(ohci, OHCI1394_IsoXmitIntEventClear, isoXmitIntEvent); DBGMSG(ohci->id, "Got isochTx interrupt " "status=0x%08x isoXmitIntEvent=%08x", reg_read(ohci, d->ctrlSet), isoXmitIntEvent); if (ohci->video_tmpl) ohci->video_tmpl->irq_handler(ohci->id, 0, isoXmitIntEvent); if (isoXmitIntEvent & 0x1) { if (reg_read(ohci, d->ctrlSet) & 0x800) ohci1394_stop_context(ohci, d->ctrlClear, "isochTx"); else tasklet_schedule(&d->task); } event &= ~OHCI1394_isochTx; } if (event & OHCI1394_selfIDComplete) { if (host->in_bus_reset) { node_id = reg_read(ohci, OHCI1394_NodeID); /* If our nodeid is not valid, give a msec delay * to let it settle in and try again. */ if (!(node_id & 0x80000000)) { mdelay(1); node_id = reg_read(ohci, OHCI1394_NodeID); } if (node_id & 0x80000000) { /* NodeID valid */ phyid = node_id & 0x0000003f; isroot = (node_id & 0x40000000) != 0; DBGMSG(ohci->id, "SelfID interrupt received " "(phyid %d, %s)", phyid, (isroot ? "root" : "not root")); handle_selfid(ohci, host, phyid, isroot); } else { PRINT(KERN_ERR, ohci->id, "SelfID interrupt received, but " "NodeID is not valid: %08X", node_id); } /* Accept Physical requests from all nodes. */ reg_write(ohci,OHCI1394_AsReqFilterHiSet, 0xffffffff); reg_write(ohci,OHCI1394_AsReqFilterLoSet, 0xffffffff); /* Turn on phys dma reception. We should * probably manage the filtering somehow, * instead of blindly turning it on. */ reg_write(ohci,OHCI1394_PhyReqFilterHiSet, 0xffffffff); reg_write(ohci,OHCI1394_PhyReqFilterLoSet, 0xffffffff); reg_write(ohci,OHCI1394_PhyUpperBound, 0xffff0000); } else PRINT(KERN_ERR, ohci->id, "SelfID received outside of bus reset sequence"); /* Finally, we clear the busReset event and reenable * the busReset interrupt. */ spin_lock_irqsave(&ohci->event_lock, flags); reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset); reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset); spin_unlock_irqrestore(&ohci->event_lock, flags); event &= ~OHCI1394_selfIDComplete; } /* Make sure we handle everything, just in case we accidentally * enabled an interrupt that we didn't write a handler for. */ if (event) PRINT(KERN_ERR, ohci->id, "Unhandled interrupt(s) 0x%08x", event);}/* Put the buffer back into the dma context */static void insert_dma_buffer(struct dma_rcv_ctx *d, int idx){ struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci); DBGMSG(ohci->id, "Inserting dma buf ctx=%d idx=%d", d->ctx, idx); d->prg_cpu[idx]->status = cpu_to_le32(d->buf_size); d->prg_cpu[idx]->branchAddress &= le32_to_cpu(0xfffffff0); idx = (idx + d->num_desc - 1 ) % d->num_desc; d->prg_cpu[idx]->branchAddress |= le32_to_cpu(0x00000001); /* wake up the dma context if necessary */ if (!(reg_read(ohci, d->ctrlSet) & 0x400)) { PRINT(KERN_INFO, ohci->id, "Waking dma ctx=%d ... processing is probably too slow", d->ctx); reg_write(ohci, d->ctrlSet, 0x1000); }}#define cond_le32_to_cpu(data, noswap) \
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -