📄 ohci1394.c
字号:
(noswap ? data : le32_to_cpu(data))static const int TCODE_SIZE[16] = {20, 0, 16, -1, 16, 20, 20, 0, -1, 0, -1, 0, -1, -1, 16, -1};/* * Determine the length of a packet in the buffer * Optimization suggested by Pascal Drolet <pascal.drolet@informission.ca> */static __inline__ int packet_length(struct dma_rcv_ctx *d, int idx, quadlet_t *buf_ptr, int offset, unsigned char tcode, int noswap){ int length = -1; if (d->ctx < 2) { /* Async Receive Response/Request */ length = TCODE_SIZE[tcode]; if (length == 0) { if (offset + 12 >= d->buf_size) { length = (cond_le32_to_cpu(d->buf_cpu[(idx + 1) % d->num_desc] [3 - ((d->buf_size - offset) >> 2)], noswap) >> 16); } else { length = (cond_le32_to_cpu(buf_ptr[3], noswap) >> 16); } length += 20; } } else if (d->ctx == 2) { /* Iso receive */ /* Assumption: buffer fill mode with header/trailer */ length = (cond_le32_to_cpu(buf_ptr[0], noswap) >> 16) + 8; } if (length > 0 && length % 4) length += 4 - (length % 4); return length;}/* Tasklet that processes dma receive buffers */static void dma_rcv_tasklet (unsigned long data){ struct dma_rcv_ctx *d = (struct dma_rcv_ctx*)data; struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci); unsigned int split_left, idx, offset, rescount; unsigned char tcode; int length, bytes_left, ack; unsigned long flags; quadlet_t *buf_ptr; char *split_ptr; char msg[256]; spin_lock_irqsave(&d->lock, flags); idx = d->buf_ind; offset = d->buf_offset; buf_ptr = d->buf_cpu[idx] + offset/4; dma_cache_wback_inv(&(d->prg_cpu[idx]->status), sizeof(d->prg_cpu[idx]->status)); rescount = le32_to_cpu(d->prg_cpu[idx]->status) & 0xffff; bytes_left = d->buf_size - rescount - offset; dma_cache_wback_inv(buf_ptr, bytes_left); while (bytes_left > 0) { tcode = (cond_le32_to_cpu(buf_ptr[0], ohci->no_swap_incoming) >> 4) & 0xf; /* packet_length() will return < 4 for an error */ length = packet_length(d, idx, buf_ptr, offset, tcode, ohci->no_swap_incoming); if (length < 4) { /* something is wrong */ sprintf(msg,"Unexpected tcode 0x%x(0x%08x) in AR ctx=%d, length=%d", tcode, cond_le32_to_cpu(buf_ptr[0], ohci->no_swap_incoming), d->ctx, length); ohci1394_stop_context(ohci, d->ctrlClear, msg); spin_unlock_irqrestore(&d->lock, flags); return; } /* The first case is where we have a packet that crosses * over more than one descriptor. The next case is where * it's all in the first descriptor. */ if ((offset + length) > d->buf_size) { DBGMSG(ohci->id,"Split packet rcv'd"); if (length > d->split_buf_size) { ohci1394_stop_context(ohci, d->ctrlClear, "Split packet size exceeded"); d->buf_ind = idx; d->buf_offset = offset; spin_unlock_irqrestore(&d->lock, flags); return; } if (le32_to_cpu(d->prg_cpu[(idx+1)%d->num_desc]->status) == d->buf_size) { /* Other part of packet not written yet. * this should never happen I think * anyway we'll get it on the next call. */ PRINT(KERN_INFO, ohci->id, "Got only half a packet!"); d->buf_ind = idx; d->buf_offset = offset; spin_unlock_irqrestore(&d->lock, flags); return; } split_left = length; split_ptr = (char *)d->spb; memcpy(split_ptr,buf_ptr,d->buf_size-offset); split_left -= d->buf_size-offset; split_ptr += d->buf_size-offset; insert_dma_buffer(d, idx); idx = (idx+1) % d->num_desc; buf_ptr = d->buf_cpu[idx]; dma_cache_wback_inv(buf_ptr, d->buf_size); offset=0; while (split_left >= d->buf_size) { memcpy(split_ptr,buf_ptr,d->buf_size); split_ptr += d->buf_size; split_left -= d->buf_size; insert_dma_buffer(d, idx); idx = (idx+1) % d->num_desc; buf_ptr = d->buf_cpu[idx]; dma_cache_wback_inv(buf_ptr, d->buf_size); } if (split_left > 0) { memcpy(split_ptr, buf_ptr, split_left); offset = split_left; buf_ptr += offset/4; } } else { DBGMSG(ohci->id,"Single packet rcv'd"); memcpy(d->spb, buf_ptr, length); offset += length; buf_ptr += length/4; if (offset==d->buf_size) { insert_dma_buffer(d, idx); idx = (idx+1) % d->num_desc; buf_ptr = d->buf_cpu[idx]; offset=0; } } /* We get one phy packet to the async descriptor for each * bus reset. We always ignore it. */ if (tcode != OHCI1394_TCODE_PHY) { if (!ohci->no_swap_incoming) packet_swab(d->spb, tcode, (length - 4) >> 2); DBGMSG(ohci->id, "Packet received from node" " %d ack=0x%02X spd=%d tcode=0x%X" " length=%d ctx=%d tlabel=%d", (d->spb[1]>>16)&0x3f, (cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>16)&0x1f, (cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>21)&0x3, tcode, length, d->ctx, (cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>10)&0x3f); ack = (((cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>16)&0x1f) == 0x11) ? 1 : 0; hpsb_packet_received(ohci->host, d->spb, length-4, ack); }#ifdef OHCI1394_DEBUG else PRINT (KERN_DEBUG, ohci->id, "Got phy packet ctx=%d ... discarded", d->ctx);#endif dma_cache_wback_inv(&(d->prg_cpu[idx]->status), sizeof(d->prg_cpu[idx]->status)); rescount = le32_to_cpu(d->prg_cpu[idx]->status) & 0xffff; bytes_left = d->buf_size - rescount - offset; } d->buf_ind = idx; d->buf_offset = offset; spin_unlock_irqrestore(&d->lock, flags);}/* Bottom half that processes sent packets */static void dma_trm_tasklet (unsigned long data){ struct dma_trm_ctx *d = (struct dma_trm_ctx*)data; struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci); struct hpsb_packet *packet, *nextpacket; unsigned long flags; u32 ack; size_t datasize; spin_lock_irqsave(&d->lock, flags); if (d->fifo_first == NULL) {#if 0 ohci1394_stop_context(ohci, d->ctrlClear, "Packet sent ack received but queue is empty");#endif spin_unlock_irqrestore(&d->lock, flags); return; } while (d->fifo_first) { packet = d->fifo_first; datasize = d->fifo_first->data_size; if (datasize && packet->type != hpsb_raw) ack = le32_to_cpu( d->prg_cpu[d->sent_ind]->end.status) >> 16; else ack = le32_to_cpu( d->prg_cpu[d->sent_ind]->begin.status) >> 16; if (ack == 0) /* this packet hasn't been sent yet*/ break;#ifdef OHCI1394_DEBUG if (datasize) DBGMSG(ohci->id, "Packet sent to node %d tcode=0x%X tLabel=" "0x%02X ack=0x%X spd=%d dataLength=%d ctx=%d", (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[1]) >>16)&0x3f, (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0]) >>4)&0xf, (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0]) >>10)&0x3f, ack&0x1f, (ack>>5)&0x3, le32_to_cpu(d->prg_cpu[d->sent_ind]->data[3]) >>16, d->ctx); else DBGMSG(ohci->id, "Packet sent to node %d tcode=0x%X tLabel=" "0x%02X ack=0x%X spd=%d data=0x%08X ctx=%d", (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[1]) >>16)&0x3f, (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0]) >>4)&0xf, (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0]) >>10)&0x3f, ack&0x1f, (ack>>5)&0x3, le32_to_cpu(d->prg_cpu[d->sent_ind]->data[3]), d->ctx);#endif nextpacket = packet->xnext; hpsb_packet_sent(ohci->host, packet, ack & 0xf); if (datasize) { pci_unmap_single(ohci->dev, cpu_to_le32(d->prg_cpu[d->sent_ind]->end.address), datasize, PCI_DMA_TODEVICE); OHCI_DMA_FREE("single Xmit data packet"); } d->sent_ind = (d->sent_ind+1)%d->num_desc; d->free_prgs++; d->fifo_first = nextpacket; } if (d->fifo_first == NULL) d->fifo_last = NULL; dma_trm_flush(ohci, d); spin_unlock_irqrestore(&d->lock, flags);}static int free_dma_rcv_ctx(struct dma_rcv_ctx **d){ int i; struct ti_ohci *ohci; if (*d==NULL) return -1; ohci = (struct ti_ohci *)(*d)->ohci; DBGMSG(ohci->id, "Freeing dma_rcv_ctx %d",(*d)->ctx); ohci1394_stop_context(ohci, (*d)->ctrlClear, NULL); tasklet_kill(&(*d)->task); if ((*d)->buf_cpu) { for (i=0; i<(*d)->num_desc; i++) if ((*d)->buf_cpu[i] && (*d)->buf_bus[i]) { pci_free_consistent( ohci->dev, (*d)->buf_size, (*d)->buf_cpu[i], (*d)->buf_bus[i]); OHCI_DMA_FREE("consistent dma_rcv buf[%d]", i); } kfree((*d)->buf_cpu); kfree((*d)->buf_bus); } if ((*d)->prg_cpu) { for (i=0; i<(*d)->num_desc; i++) if ((*d)->prg_cpu[i] && (*d)->prg_bus[i]) { pci_free_consistent( ohci->dev, sizeof(struct dma_cmd), (*d)->prg_cpu[i], (*d)->prg_bus[i]); OHCI_DMA_FREE("consistent dma_rcv prg[%d]", i); } kfree((*d)->prg_cpu); kfree((*d)->prg_bus); } if ((*d)->spb) kfree((*d)->spb); kfree(*d); *d = NULL; return 0;}static struct dma_rcv_ctx *alloc_dma_rcv_ctx(struct ti_ohci *ohci, int ctx, int num_desc, int buf_size, int split_buf_size, int ctrlSet, int ctrlClear, int cmdPtr){ struct dma_rcv_ctx *d=NULL; int i; d = (struct dma_rcv_ctx *)kmalloc(sizeof(struct dma_rcv_ctx), GFP_KERNEL); if (d == NULL) { PRINT(KERN_ERR, ohci->id, "Failed to allocate dma_rcv_ctx"); return NULL; } memset (d, 0, sizeof (struct dma_rcv_ctx)); d->ohci = (void *)ohci; d->ctx = ctx; d->num_desc = num_desc; d->buf_size = buf_size; d->split_buf_size = split_buf_size; d->ctrlSet = ctrlSet; d->ctrlClear = ctrlClear; d->cmdPtr = cmdPtr; d->buf_cpu = NULL; d->buf_bus = NULL; d->prg_cpu = NULL; d->prg_bus = NULL; d->spb = NULL; d->buf_cpu = kmalloc(d->num_desc * sizeof(quadlet_t*), GFP_KERNEL); d->buf_bus = kmalloc(d->num_desc * sizeof(dma_addr_t), GFP_KERNEL); if (d->buf_cpu == NULL || d->buf_bus == NULL) { PRINT(KERN_ERR, ohci->id, "Failed to allocate dma buffer"); free_dma_rcv_ctx(&d); return NULL; } memset(d->buf_cpu, 0, d->num_desc * sizeof(quadlet_t*)); memset(d->buf_bus, 0, d->num_desc * sizeof(dma_addr_t)); d->prg_cpu = kmalloc(d->num_desc * sizeof(struct dma_cmd*), GFP_KERNEL); d->prg_bus = kmalloc(d->num_desc * sizeof(dma_addr_t), GFP_KERNEL); if (d->prg_cpu == NULL || d->prg_bus == NULL) { PRINT(KERN_ERR, ohci->id, "Failed to allocate dma prg"); free_dma_rcv_ctx(&d); return NULL; } memset(d->prg_cpu, 0, d->num_desc * sizeof(struct dma_cmd*)); memset(d->prg_bus, 0, d->num_desc * sizeof(dma_addr_t)); d->spb = kmalloc(d->split_buf_size, GFP_KERNEL); if (d->spb == NULL) { PRINT(KERN_ERR, ohci->id, "Failed to allocate split buffer"); free_dma_rcv_ctx(&d); return NULL; } for (i=0; i<d->num_desc; i++) { d->buf_cpu[i] = pci_alloc_consistent(ohci->dev, d->buf_size, d->buf_bus+i); OHCI_DMA_ALLOC("consistent dma_rcv buf[%d]", i); if (d->buf_cpu[i] != NULL) { memset(d->buf_cpu[i], 0, d->buf_size); } else { PRINT(KERN_ERR, ohci->id, "Failed to allocate dma buffer"); free_dma_rcv_ctx(&d); return NULL; } d->prg_cpu[i] = pci_alloc_consistent(ohci->dev, sizeof(struct dma_cmd), d->prg_bus+i); OHCI_DMA_ALLOC("consistent dma_rcv prg[%d]", i); if (d->prg_cpu[i] != NULL) { memset(d->prg_cpu[i], 0, sizeof(struct dma_cmd)); } else { PRINT(KERN_ERR, ohci->id, "Failed to allocate dma prg"); free_dma_rcv_ctx(&d); return NULL; } } spin_lock_init(&d->lock); /* initialize tasklet */ tasklet_init (&d->task, dma_rcv_tasklet, (unsigned long)d); return d;}static int free_dma_trm_ctx(struct dma_trm_ctx **d){ struct ti_ohci *ohci; int i; if (*d==NULL) return -1; ohci = (struct ti_ohci *)(*d)->ohci; DBGMSG(ohci->id, "Freeing dma_trm_ctx %d",(*d)->ctx); ohci1394_stop_context(ohci, (*d)->ctrlClear, NULL); tasklet_kill(&(*d)->task); if ((*d)->prg_cpu) { for (i=0; i<(*d)->num_desc; i++) if ((*d)->prg_cpu[i] && (*d)->prg_bus[i]) { pci_free_consistent( ohci->dev, sizeof(struct at_dma_prg), (*d)->prg_cpu[i], (*d)->prg_bus[i]); OHCI_DMA_FREE("consistent dma_trm prg[%d]", i); } kfree((*d)->prg_cpu); kfree((*d)->prg_bus); } kfree(*d); *d = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -