[Linux1394-cvslog] rev 549 - branches/gasp
Brought to you by:
aeb,
bencollins
From: SVN U. <ben...@li...> - 2002-08-09 05:11:20
|
Author: bencollins Date: 2002-08-09 09:58:52 -0400 (Fri, 09 Aug 2002) New Revision: 549 Modified: branches/gasp/amdtp.c branches/gasp/csr.c branches/gasp/csr.h branches/gasp/dv1394.c branches/gasp/eth1394.c branches/gasp/eth1394.h branches/gasp/highlevel.c branches/gasp/highlevel.h branches/gasp/hosts.c branches/gasp/hosts.h branches/gasp/ieee1394.h branches/gasp/ieee1394_core.c branches/gasp/ieee1394_transactions.c branches/gasp/ieee1394_transactions.h branches/gasp/nodemgr.c branches/gasp/ohci1394.c branches/gasp/ohci1394.h branches/gasp/raw1394.c branches/gasp/video1394.c Log: Apply GASP patch from Steve Kinneberg Modified: branches/gasp/ieee1394_core.c ============================================================================== --- branches/gasp/ieee1394_core.c (original) +++ branches/gasp/ieee1394_core.c 2002-08-09 09:58:55.000000000 -0400 @@ -160,6 +160,8 @@ abort_requests(host); host->in_bus_reset = 1; + host->is_irm = 0; + host->is_busmgr = 0; host->irm_id = -1; host->busmgr_id = -1; host->node_count = 0; @@ -349,9 +351,6 @@ /* irm_id is kept up to date by check_selfids() */ if (host->irm_id == host->node_id) { host->is_irm = 1; - host->is_busmgr = 1; - host->busmgr_id = host->node_id; - host->csr.bus_manager_id = host->node_id; } host->reset_retries = 0; @@ -419,7 +418,8 @@ packet->state = hpsb_queued; - if (packet->type == hpsb_async && packet->node_id != ALL_NODES) { + if (packet->type == hpsb_async && packet->tcode != TCODE_STREAM_DATA && + packet->node_id != ALL_NODES) { packet->speed_code = host->speed_map[(host->node_id & NODE_MASK) * 64 + (packet->node_id & NODE_MASK)]; @@ -1074,23 +1074,27 @@ EXPORT_SYMBOL(fill_async_lock_resp); EXPORT_SYMBOL(fill_iso_packet); EXPORT_SYMBOL(fill_phy_packet); +EXPORT_SYMBOL(fill_async_stream_packet); EXPORT_SYMBOL(hpsb_make_readqpacket); EXPORT_SYMBOL(hpsb_make_readbpacket); EXPORT_SYMBOL(hpsb_make_writeqpacket); EXPORT_SYMBOL(hpsb_make_writebpacket); EXPORT_SYMBOL(hpsb_make_lockpacket); +EXPORT_SYMBOL(hpsb_make_lock64packet); EXPORT_SYMBOL(hpsb_make_phypacket); EXPORT_SYMBOL(hpsb_packet_success); EXPORT_SYMBOL(hpsb_make_packet); EXPORT_SYMBOL(hpsb_read); EXPORT_SYMBOL(hpsb_write); EXPORT_SYMBOL(hpsb_lock); +EXPORT_SYMBOL(hpsb_lock64); +EXPORT_SYMBOL(hpsb_send_gasp); EXPORT_SYMBOL(hpsb_register_highlevel); EXPORT_SYMBOL(hpsb_unregister_highlevel); EXPORT_SYMBOL(hpsb_register_addrspace); -EXPORT_SYMBOL(hpsb_listen_channel); -EXPORT_SYMBOL(hpsb_unlisten_channel); +EXPORT_SYMBOL(highlevel_channel_open); +EXPORT_SYMBOL(highlevel_channel_close); EXPORT_SYMBOL(highlevel_read); EXPORT_SYMBOL(highlevel_write); EXPORT_SYMBOL(highlevel_lock); Modified: branches/gasp/ohci1394.c ============================================================================== --- branches/gasp/ohci1394.c (original) +++ branches/gasp/ohci1394.c 2002-08-09 09:58:55.000000000 -0400 @@ -31,9 +31,9 @@ * * Things implemented, but still in test phase: * . Iso Transmit + * . Async Stream Packets * * Things not implemented: - * . Async Stream Packets * . DMA error recovery * * Known bugs: @@ -170,6 +170,13 @@ static void ohci1394_pci_remove(struct pci_dev *pdev); +static struct dma_rcv_ctx *alloc_dma_rcv_ctx(struct ti_ohci *ohci, + enum context_type type, + int ctx, int num_desc, + int buf_size, int split_buf_size, + int context_base); +static int free_dma_rcv_ctx(struct dma_rcv_ctx **d); + static inline void ohci1394_run_irq_hooks(struct ti_ohci *ohci, quadlet_t isoRecvEvent, quadlet_t isoXmitEvent); @@ -198,7 +205,7 @@ }; /* Swap headers */ -static inline void packet_swab(quadlet_t *data, int tcode, int len) +static inline void packet_swab(quadlet_t *data, int tcode) { if (tcode > TCODE_LOCK_RESPONSE || hdr_sizes[tcode] == 0) return; @@ -206,7 +213,7 @@ } #else /* Don't waste cycles on same sex byte swaps */ -#define packet_swab(w,x,y) +#define packet_swab(w,x) #define block_swab32(x,y) #endif /* !LITTLE_ENDIAN */ @@ -422,15 +429,56 @@ d->buf_ind = 0; d->buf_offset = 0; - /* Tell the controller where the first AR program is */ + /* Tell the controller where the first dma receive program is */ + reg_write(ohci, d->cmdPtr, d->prg_bus[0] | 0x1); + + /* Run dma receive context */ + reg_write(ohci, d->ctrlSet, 0x00008000); + + DBGMSG(ohci->id, "Receive DMA ctx=%d initialized", d->ctx); +} + +/* ISO packet-per-buffer mode needs different settings */ +static void initialize_dma_rcv_ppb_ctx(struct dma_rcv_ctx *d) +{ + struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci); + int i; + + ohci1394_stop_context(ohci, d->ctrlClear, NULL); + + for (i=0; i<d->num_desc; i++) { + u32 c; + + c = DMA_CTL_INPUT_LAST | DMA_CTL_UPDATE | DMA_CTL_BRANCH | DMA_CTL_IRQ; + + d->prg_cpu[i]->control = cpu_to_le32(c | d->buf_size); + + /* End of descriptor list? */ + if (i + 1 < d->num_desc) { + d->prg_cpu[i]->branchAddress = + cpu_to_le32((d->prg_bus[i+1] & 0xfffffff0) | 1); + } else { + d->prg_cpu[i]->branchAddress = + cpu_to_le32((d->prg_bus[0] & 0xfffffff0) | 1); + } + + d->prg_cpu[i]->address = cpu_to_le32(d->buf_bus[i]); + d->prg_cpu[i]->status = cpu_to_le32(d->buf_size); + } + + d->buf_ind = 0; + d->buf_offset = 4; /* packet-per-buffer does things differently :P */ + + /* Tell the controller where the first dma receive program is */ reg_write(ohci, d->cmdPtr, d->prg_bus[0] | 0x1); - /* Run AR context */ + /* Run dma receive context */ reg_write(ohci, d->ctrlSet, 0x00008000); DBGMSG(ohci->id, "Receive DMA ctx=%d initialized", d->ctx); } + /* Initialize the dma transmit context */ static void initialize_dma_trm_ctx(struct dma_trm_ctx *d) { @@ -579,7 +627,7 @@ initialize_dma_trm_ctx(ohci->at_resp_context); /* Initialize IR dma */ - initialize_dma_rcv_ctx(ohci->ir_context, 1); + initialize_dma_rcv_ctx(ohci->ir_context[0], 1); /* Initialize IT dma */ initialize_dma_trm_ctx(ohci->it_context); @@ -610,6 +658,7 @@ /* Enable interrupts */ reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_masterIntEnable | + OHCI1394_unrecoverableError | OHCI1394_busReset | OHCI1394_selfIDComplete | OHCI1394_RSPkt | @@ -676,19 +725,31 @@ } 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->tcode == TCODE_STREAM_DATA){ + /* Sending an asynchronous stream packet */ + d->prg_cpu[idx]->data[1] = packet->header[0] & 0xFFFF0000; + } else { + /* Sending a normal asynchronous request or response packet */ + 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); } if (packet->data_size) { /* block transmit */ - d->prg_cpu[idx]->begin.control = - cpu_to_le32(DMA_CTL_OUTPUT_MORE | - DMA_CTL_IMMEDIATE | 0x10); + 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 | @@ -747,7 +808,7 @@ 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); + packet_swab(d->prg_cpu[idx]->data, packet->tcode); d->prg_cpu[idx]->begin.control = cpu_to_le32(DMA_CTL_OUTPUT_MORE | @@ -861,7 +922,8 @@ /* 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; + if ((tcode == TCODE_ISO_DATA) && (packet->type == hpsb_iso)) + d = ohci->it_context; else if (tcode & 0x02) d = ohci->at_resp_context; else d = ohci->at_req_context; @@ -892,9 +954,13 @@ switch (cmd) { case RESET_BUS: + /* should probably remove the attempt_root module parameter + * because proper operation of the 1394 bus doesn't need it */ DBGMSG(ohci->id, "devctl: Bus reset requested%s", - attempt_root ? " and attempting to become root" : ""); - set_phy_reg_mask (ohci, 1, 0x40 | (attempt_root ? 0x80 : 0)); + (arg == 1 || attempt_root) ? + " and attempting to become root" : ""); + set_phy_reg_mask (ohci, 1, 0x40 | ((arg = 1 || attempt_root) ? + 0x80 : 0)); break; case GET_CYCLE_COUNTER: @@ -944,71 +1010,103 @@ case ISO_LISTEN_CHANNEL: { - u64 mask; - - if (arg<0 || arg>63) { - PRINT(KERN_ERR, ohci->id, - "%s: IS0 listen channel %d is out of range", - __FUNCTION__, arg); - return -EFAULT; - } + int channel = arg & ISO_LISTEN_CHANNEL_MASK; + int context; - mask = (u64)0x1<<arg; - spin_lock_irqsave(&ohci->IR_channel_lock, flags); - if (ohci->ISO_channel_usage & mask) { - PRINT(KERN_ERR, ohci->id, - "%s: IS0 listen channel %d is already used", - __FUNCTION__, arg); - spin_unlock_irqrestore(&ohci->IR_channel_lock, flags); - return -EFAULT; - } - - ohci->ISO_channel_usage |= mask; + if(ohci->ir_channel_to_ctx[channel] != OHCI1394_IR_CTX_UNALLOCED) { + if((ohci->ir_channel_to_ctx[channel] == 0) && + (arg & ISO_LISTEN_SINGLE_PACKET)) + PRINT(KERN_ERR, ohci->id, + "Attempting to listen to channel in packet-" + "per-buffer mode when channel already being " + "listened to in buffer-fill mode"); + /* already listening to requested channel, nothing to do */ + spin_unlock_irqrestore(&ohci->IR_channel_lock, flags); + break; + } - if (arg>31) - reg_write(ohci, OHCI1394_IRMultiChanMaskHiSet, - 1<<(arg-32)); - else - reg_write(ohci, OHCI1394_IRMultiChanMaskLoSet, - 1<<arg); + if(arg & ISO_LISTEN_SINGLE_PACKET) { + if(ohci->ir_ctx_usage == ~0x0) { + PRINT(KERN_ERR, ohci->id, + "Cannot listen to ISO channel %d, " + "all contexts are in use", + channel); + spin_unlock_irqrestore(&ohci->IR_channel_lock, flags); + return -EBUSY; /* all contexts in use */ + } + + context = ffz(ohci->ir_ctx_usage); + DBGMSG(ohci->id, "using context: %d", context); + + ohci->ir_context[context] = + alloc_dma_rcv_ctx(ohci, DMA_CTX_ISO, context, + IR_NUM_DESC, IR_BUF_SIZE, + IR_SPLIT_BUF_SIZE, + OHCI1394_IsoRcvContextBase + + (0x20 * context)); + if(ohci->ir_context[context] == NULL) { + PRINT(KERN_ERR, ohci->id, + "Cannot listen to ISO channel %d, " + "requested context %d not available", + channel, context); + spin_unlock_irqrestore(&ohci->IR_channel_lock, flags); + return -EBUSY; + } + + /* Set packet-per-buffer, isochHeader, for IR context */ + reg_write(ohci, OHCI1394_IsoRcvContextControlSet + (0x20 * context), + 0x40000000); + + /* Set the context match register to match on all tags */ + reg_write(ohci, OHCI1394_IsoRcvContextMatch + (0x20 * context), + 0x8000001f); + + /* Initialize IR dma */ + initialize_dma_rcv_ppb_ctx(ohci->ir_context[context]); + + reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 0x1 << context); + } else { + context = 0; + if (channel>31) + reg_write(ohci, OHCI1394_IRMultiChanMaskHiSet, + 1<<(channel-32)); + else + reg_write(ohci, OHCI1394_IRMultiChanMaskLoSet, + 1<<channel); + } + ohci->ir_channel_to_ctx[channel] = context; spin_unlock_irqrestore(&ohci->IR_channel_lock, flags); - DBGMSG(ohci->id, "Listening enabled on channel %d", arg); + DBGMSG(ohci->id, "Listening enabled on channel %d", channel); break; } case ISO_UNLISTEN_CHANNEL: { - u64 mask; - - if (arg<0 || arg>63) { - PRINT(KERN_ERR, ohci->id, - "%s: IS0 unlisten channel %d is out of range", - __FUNCTION__, arg); - return -EFAULT; - } + int context = ohci->ir_channel_to_ctx[arg]; - mask = (u64)0x1<<arg; - spin_lock_irqsave(&ohci->IR_channel_lock, flags); - if (!(ohci->ISO_channel_usage & mask)) { - PRINT(KERN_ERR, ohci->id, - "%s: IS0 unlisten channel %d is not used", - __FUNCTION__, arg); - spin_unlock_irqrestore(&ohci->IR_channel_lock, flags); - return -EFAULT; - } - - ohci->ISO_channel_usage &= ~mask; + if(context == OHCI1394_IR_CTX_UNALLOCED) { + /* already not listening to requested channel, nothing to do */ + spin_unlock_irqrestore(&ohci->IR_channel_lock, flags); + break; + } - if (arg>31) - reg_write(ohci, OHCI1394_IRMultiChanMaskHiClear, - 1<<(arg-32)); - else - reg_write(ohci, OHCI1394_IRMultiChanMaskLoClear, - 1<<arg); + if (context == 0) { + if (arg>31) + reg_write(ohci, OHCI1394_IRMultiChanMaskHiClear, + 1<<(arg-32)); + else + reg_write(ohci, OHCI1394_IRMultiChanMaskLoClear, + 1<<arg); + } else { + /* Free IR dma */ + reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0x1 << context); + free_dma_rcv_ctx(&ohci->ir_context[context]); + ohci->ir_channel_to_ctx[arg] = OHCI1394_IR_CTX_UNALLOCED; + } spin_unlock_irqrestore(&ohci->IR_channel_lock, flags); DBGMSG(ohci->id, "Listening disabled on channel %d", arg); @@ -1096,10 +1194,64 @@ 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!"); - return; + int ctx; + PRINT(KERN_ERR, ohci->id, "Unrecoverable error!"); + if(reg_read(ohci, OHCI1394_AsReqTrContextControlSet) & 0x800) + { + PRINT(KERN_ERR, ohci->id, "Async Req Tx Context died. "); + PRINT(KERN_ERR, ohci->id, " control : %#010x" + " command ptr: %#010x", + reg_read(ohci, OHCI1394_AsReqTrContextControlSet), + reg_read(ohci, OHCI1394_AsReqTrCommandPtr)); + } + if(reg_read(ohci, OHCI1394_AsRspTrContextControlSet) & 0x800) + { + PRINT(KERN_ERR, ohci->id, "Async Rsp Tx Context died. "); + PRINT(KERN_ERR, ohci->id, " control : %#010x" + " command ptr: %#010x", + reg_read(ohci, OHCI1394_AsRspTrContextControlSet), + reg_read(ohci, OHCI1394_AsRspTrCommandPtr)); + } + if(reg_read(ohci, OHCI1394_AsReqRcvContextControlSet) & 0x800) + { + PRINT(KERN_ERR, ohci->id, "Async Req Rcv Context died. "); + PRINT(KERN_ERR, ohci->id, " control : %#010x" + " command ptr: %#010x", + reg_read(ohci, OHCI1394_AsReqRcvContextControlSet), + reg_read(ohci, OHCI1394_AsReqRcvCommandPtr)); + } + if(reg_read(ohci, OHCI1394_AsRspRcvContextControlSet) & 0x800) + { + PRINT(KERN_ERR, ohci->id, "Async Rsp Rcv Context died. "); + PRINT(KERN_ERR, ohci->id, " control : %#010x" + " command ptr: %#010x", + reg_read(ohci, OHCI1394_AsRspRcvContextControlSet), + reg_read(ohci, OHCI1394_AsRspRcvCommandPtr)); + } + for(ctx = 0; ctx < ohci->nb_iso_xmit_ctx; ctx++) { + if(reg_read(ohci, OHCI1394_IsoXmitContextControlSet + (16 * ctx)) & 0x800) + { + PRINT(KERN_ERR, ohci->id, "Async Iso Xmit %d Context died. ", ctx); + PRINT(KERN_ERR, ohci->id, " control : %#010x" + " command ptr: %#010x", + reg_read(ohci, OHCI1394_IsoXmitContextControlSet + (16 * ctx)), + reg_read(ohci, OHCI1394_IsoXmitCommandPtr + (16 * ctx))); + } + } + for(ctx = 0; ctx < ohci->nb_iso_rcv_ctx; ctx++) { + if(reg_read(ohci, OHCI1394_IsoRcvContextControlSet + (32 * ctx)) & 0x800) + { + PRINT(KERN_ERR, ohci->id, "Async Iso Recv %d Context died. ", ctx); + PRINT(KERN_ERR, ohci->id, " control : %#010x" + " command ptr: %#010x " + " match: %#010x", + reg_read(ohci, OHCI1394_IsoRcvContextControlSet + (32 * ctx)), + reg_read(ohci, OHCI1394_IsoRcvCommandPtr + (32 * ctx)), + reg_read(ohci, OHCI1394_IsoRcvContextMatch + (32 * ctx))); + } + } + event &= ~OHCI1394_unrecoverableError; } if (event & OHCI1394_cycleInconsistent) { @@ -1186,15 +1338,25 @@ } if (event & OHCI1394_isochRx) { quadlet_t isoRecvIntEvent; - struct dma_rcv_ctx *d = ohci->ir_context; + struct dma_rcv_ctx *d = ohci->ir_context[0]; + int i; + 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) { + DBGMSG(ohci->id, "Got isochRx interrupt isoRecvIntEvent=%08x", + isoRecvIntEvent); + + for (i = 0; i < ohci->nb_iso_rcv_ctx; i++) { + if (!test_bit(i, &ohci->ir_ctx_usage) || + !test_bit(i, &isoRecvIntEvent)) { + continue; + } + d = ohci->ir_context[i]; + DBGMSG(ohci->id, " Handling context %d: status = %08x", + i, reg_read(ohci, d->ctrlSet)); + if (reg_read(ohci, d->ctrlSet) & 0x800) ohci1394_stop_context(ohci, d->ctrlClear, "isochRx"); @@ -1375,9 +1537,16 @@ quadlet_t *buf_ptr; char *split_ptr; char msg[256]; + int ppb_mode; spin_lock_irqsave(&d->lock, flags); + /* ppb_mode is a hack to deal with the time stamp being at the + * begining of a receive packet in packet-per-buffer mode (gotta love + * inconsistancy) */ + ppb_mode = ((d->type == DMA_CTX_ISO) && + ((reg_read(ohci, d->cmdPtr) & (1 << 31)) != (1 << 31))); + idx = d->buf_ind; offset = d->buf_offset; buf_ptr = d->buf_cpu[idx] + offset/4; @@ -1450,17 +1619,22 @@ memcpy(split_ptr, buf_ptr, split_left); offset = split_left; buf_ptr += offset/4; + if(ppb_mode) + insert_dma_buffer(d, idx); } } 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) { + if (offset==d->buf_size || ppb_mode) { insert_dma_buffer(d, idx); idx = (idx+1) % d->num_desc; buf_ptr = d->buf_cpu[idx]; - offset=0; + if(ppb_mode) + offset=4; + else + offset=0; } } @@ -1468,7 +1642,7 @@ * bus reset. We always ignore it. */ if (tcode != OHCI1394_TCODE_PHY) { if (!ohci->no_swap_incoming) - packet_swab(d->spb, tcode, (length - 4) >> 2); + packet_swab(d->spb, tcode); DBGMSG(ohci->id, "Packet received from node" " %d ack=0x%02X spd=%d tcode=0x%X" " length=%d ctx=%d tlabel=%d", @@ -1547,33 +1721,46 @@ } #ifdef OHCI1394_DEBUG - if (datasize) + if (((le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0]) + >> 4) & 0xf) == TCODE_STREAM_DATA) { 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, + "Packet sent via Async stream tcode=0x%X " + "ack=0x%X spd=%d dataLength=%d ctx=%d", (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]) + le32_to_cpu(d->prg_cpu[d->sent_ind]->data[1]) >>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]) + } else { + 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]) + (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0]) >>4)&0xf, - (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0]) + (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); + 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; @@ -2187,12 +2374,12 @@ ohci->it_ctx_usage = 0; /* IR DMA context */ - ohci->ir_context = + ohci->ir_context[0] = alloc_dma_rcv_ctx(ohci, DMA_CTX_ISO, 0, IR_NUM_DESC, IR_BUF_SIZE, IR_SPLIT_BUF_SIZE, OHCI1394_IsoRcvContextBase); - if (ohci->ir_context == NULL) + if (ohci->ir_context[0] == NULL) FAIL(-ENOMEM, "Failed to allocate IR context"); @@ -2204,7 +2391,7 @@ if (ohci->it_context == NULL) FAIL(-ENOMEM, "Failed to allocate IT context"); - ohci->ISO_channel_usage = 0; + memset(ohci->ir_channel_to_ctx, OHCI1394_IR_CTX_UNALLOCED, sizeof(char) * 64); spin_lock_init(&ohci->IR_channel_lock); for(i = 0; i < OHCI1394_MAX_IRQ_HOOKS; i++) { @@ -2255,7 +2442,7 @@ free_dma_trm_ctx(&ohci->at_resp_context); /* Free IR dma */ - free_dma_rcv_ctx(&ohci->ir_context); + free_dma_rcv_ctx(&ohci->ir_context[0]); /* Free IT dma */ free_dma_trm_ctx(&ohci->it_context); Modified: branches/gasp/amdtp.c ============================================================================== --- branches/gasp/amdtp.c (original) +++ branches/gasp/amdtp.c 2002-08-09 09:58:55.000000000 -0400 @@ -924,6 +924,7 @@ static int stream_configure(struct stream *s, int cmd, struct amdtp_ioctl *cfg) { const int transfer_delay = 9000; + int oldchan; if (cfg->format <= AMDTP_FORMAT_IEC958_AC3) s->format = cfg->format; @@ -1003,6 +1004,7 @@ s->opcr = NULL; } + oldchan = s->iso_channel; switch(cmd) { case AMDTP_IOC_PLUG: s->opcr = cmp_register_opcr(s->host->host, cfg->u.plug, @@ -1019,6 +1021,10 @@ return -EINVAL; break; } + if (oldchan != s->iso_channel) { + highlevel_channel_close(s->host->host, oldchan); + highlevel_channel_open(s->host->host, s->iso_channel, ISOCH_RESERVE); + } /* The ioctl settings were all valid, so we realloc the packet * lists to make sure the packet size is big enough. Modified: branches/gasp/ohci1394.h ============================================================================== --- branches/gasp/ohci1394.h (original) +++ branches/gasp/ohci1394.h 2002-08-09 09:58:55.000000000 -0400 @@ -56,6 +56,8 @@ #define OHCI1394_SI_DMA_BUF_SIZE 8192 /* length of the selfid buffer */ +#define OHCI1394_IR_CTX_UNALLOCED (1 << 5) + /* PCI configuration space addresses */ #define OHCI1394_PCI_HCI_Control 0x40 @@ -180,18 +182,17 @@ struct dma_trm_ctx *at_req_context; /* iso receive */ - struct dma_rcv_ctx *ir_context; + struct dma_rcv_ctx *ir_context[32]; spinlock_t IR_channel_lock; int nb_iso_rcv_ctx; unsigned long ir_ctx_usage; /* use test_and_set_bit() for atomicity */ + char ir_channel_to_ctx[64]; /* map channel number to context */ /* iso transmit */ struct dma_trm_ctx *it_context; int nb_iso_xmit_ctx; unsigned long it_ctx_usage; /* use test_and_set_bit() for atomicity */ - u64 ISO_channel_usage; - /* IEEE-1394 part follows */ struct hpsb_host *host; @@ -289,6 +290,9 @@ #define OHCI1394_IsoRecvIntEventClear 0x0A4 #define OHCI1394_IsoRecvIntMaskSet 0x0A8 #define OHCI1394_IsoRecvIntMaskClear 0x0AC +#define OHCI1394_InitialBandwidthAvailable 0x0B0 +#define OHCI1394_InitialChannelsAvailableHi 0x0B4 +#define OHCI1394_InitialChannelsAvailableLo 0x0B8 #define OHCI1394_FairnessControl 0x0DC #define OHCI1394_LinkControlSet 0x0E0 #define OHCI1394_LinkControlClear 0x0E4 Modified: branches/gasp/raw1394.c ============================================================================== --- branches/gasp/raw1394.c (original) +++ branches/gasp/raw1394.c 2002-08-09 09:58:55.000000000 -0400 @@ -538,7 +538,7 @@ req->req.error = RAW1394_ERROR_ALREADY; } else { fi->listen_channels |= 1ULL << channel; - hpsb_listen_channel(hl_handle, fi->host, channel); + highlevel_channel_open(fi->host, channel, ISOCH_RDONLY); fi->iso_buffer = int2ptr(req->req.recvb); fi->iso_buffer_length = req->req.length; } @@ -547,7 +547,7 @@ channel = ~channel; if (fi->listen_channels & (1ULL << channel)) { - hpsb_unlisten_channel(hl_handle, fi->host, channel); + highlevel_channel_close(fi->host, channel); fi->listen_channels &= ~(1ULL << channel); } else { req->req.error = RAW1394_ERROR_INVALID_ARG; @@ -944,7 +944,7 @@ for (i = 0; i < 64; i++) { if (fi->listen_channels & (1ULL << i)) { - hpsb_unlisten_channel(hl_handle, fi->host, i); + highlevel_channel_close(fi->host, i); } } Modified: branches/gasp/ieee1394_transactions.c ============================================================================== --- branches/gasp/ieee1394_transactions.c (original) +++ branches/gasp/ieee1394_transactions.c 2002-08-09 09:58:55.000000000 -0400 @@ -146,6 +146,17 @@ packet->speed_code = SPEED_100; /* Force speed to be 100Mbps */ } +void fill_async_stream_packet(struct hpsb_packet *packet, int length, + int channel, int tag, int sync) +{ + packet->header[0] = (length << 16) | (tag << 14) | (channel << 8) + | (TCODE_STREAM_DATA << 4) | sync; + + packet->header_size = 4; + packet->data_size = length; + packet->type = hpsb_async; + packet->tcode = TCODE_ISO_DATA; +} /** * get_tlabel - allocate a transaction label @@ -400,6 +411,31 @@ return p; } +struct hpsb_packet *hpsb_make_lock64packet(struct hpsb_host *host, nodeid_t node, + u64 addr, int extcode) +{ + struct hpsb_packet *p; + + p = alloc_hpsb_packet(16); + if (!p) return NULL; + + p->host = host; + p->tlabel = get_tlabel(host, node, 1); + p->node_id = node; + + switch (extcode) { + case EXTCODE_FETCH_ADD: + case EXTCODE_LITTLE_ADD: + fill_async_lock(p, addr, extcode, 8); + break; + default: + fill_async_lock(p, addr, extcode, 16); + break; + } + + return p; +} + struct hpsb_packet *hpsb_make_phypacket(struct hpsb_host *host, quadlet_t data) { @@ -611,3 +647,129 @@ return retval; } + +int hpsb_lock64(struct hpsb_host *host, nodeid_t node, unsigned int generation, + u64 addr, int extcode, octlet_t *data, octlet_t arg) +{ + struct hpsb_packet *packet; + int retval = 0, length; + + if (host->node_id == node) { + switch(highlevel_lock64(host, node, data, addr, *data, arg, + extcode)) { + case RCODE_COMPLETE: + return 0; + case RCODE_TYPE_ERROR: + return -EACCES; + case RCODE_ADDRESS_ERROR: + default: + return -EINVAL; + } + } + + packet = alloc_hpsb_packet(16); + if (!packet) { + return -ENOMEM; + } + + packet->host = host; + packet->tlabel = get_tlabel(host, node, 1); + packet->node_id = node; + + switch (extcode) { + case EXTCODE_MASK_SWAP: + case EXTCODE_COMPARE_SWAP: + case EXTCODE_BOUNDED_ADD: + case EXTCODE_WRAP_ADD: + length = 16; + packet->data[0] = (quadlet_t)(arg >> 32); + packet->data[1] = (quadlet_t)(arg & 0xFFFFFFFFLL); + packet->data[2] = (quadlet_t)(*data >> 32); + packet->data[3] = (quadlet_t)(*data & 0xFFFFFFFFLL); + break; + case EXTCODE_FETCH_ADD: + case EXTCODE_LITTLE_ADD: + length = 8; + packet->data[0] = (quadlet_t)(*data >> 32); + packet->data[1] = (quadlet_t)(*data & 0xFFFFFFFFLL); + break; + default: + return -EINVAL; + } + fill_async_lock(packet, addr, extcode, length); + + packet->generation = generation; + if (!hpsb_send_packet(packet)) { + retval = -EINVAL; + goto hpsb_lock_fail; + } + down(&packet->state_change); + down(&packet->state_change); + retval = hpsb_packet_success(packet); + + if (retval == 0) { + *data = (u64)packet->data[1] << 32 | packet->data[0]; + } + +hpsb_lock_fail: + free_tlabel(host, node, packet->tlabel); + free_hpsb_packet(packet); + + return retval; +} + +int hpsb_send_gasp(struct hpsb_host *host, int channel, unsigned int generation, + quadlet_t *buffer, size_t length, u32 specifier_id, + unsigned int version) +{ +#ifdef CONFIG_IEEE1394_VERBOSEDEBUG + int i; +#endif + + struct hpsb_packet *packet; + int retval = 0; + u16 specifier_id_hi = (specifier_id & 0x00ffff00) >> 8; + u8 specifier_id_lo = specifier_id & 0xff; + +#ifdef CONFIG_IEEE1394_VERBOSEDEBUG + HPSB_DEBUG("Send GASP: channel = %d, length = %d", channel, length); +#endif + + length += 8; + + packet = alloc_hpsb_packet(length + (length % 4 ? 4 - (length % 4) : 0)); + if (!packet) + return -ENOMEM; + + if (length % 4) { + packet->data[length / 4] = 0; + } + + packet->host = host; + fill_async_stream_packet(packet, length, channel, 3, 0); + + packet->data[0] = cpu_to_be32((host->node_id << 16) | specifier_id_hi); + packet->data[1] = cpu_to_be32((specifier_id_lo << 24) | (version & 0x00ffffff)); + + memcpy(&(packet->data[2]), buffer, length - 4); + +#ifdef CONFIG_IEEE1394_VERBOSEDEBUG + HPSB_DEBUG("GASP: packet->header_size = %d", packet->header_size); + HPSB_DEBUG("GASP: packet->data_size = %d", packet->data_size); + + for(i=0; i<(packet->data_size/4); i++) + HPSB_DEBUG("GASP: data[%d]: 0x%08x", i*4, be32_to_cpu(packet->data[i])); +#endif + + packet->generation = generation; + + packet->no_waiter = 1; + + if (!hpsb_send_packet(packet)) { + free_hpsb_packet(packet); + retval = -EINVAL; + } + + return retval; +} + Modified: branches/gasp/ieee1394_transactions.h ============================================================================== --- branches/gasp/ieee1394_transactions.h (original) +++ branches/gasp/ieee1394_transactions.h 2002-08-09 09:58:55.000000000 -0400 @@ -23,6 +23,8 @@ void fill_iso_packet(struct hpsb_packet *packet, int length, int channel, int tag, int sync); void fill_phy_packet(struct hpsb_packet *packet, quadlet_t data); +void fill_async_stream_packet(struct hpsb_packet *packet, int length, + int channel, int tag, int sync); /* * Get and free transaction labels. @@ -42,6 +44,8 @@ size_t length); struct hpsb_packet *hpsb_make_lockpacket(struct hpsb_host *host, nodeid_t node, u64 addr, int extcode); +struct hpsb_packet *hpsb_make_lock64packet(struct hpsb_host *host, nodeid_t node, + u64 addr, int extcode); struct hpsb_packet *hpsb_make_phypacket(struct hpsb_host *host, quadlet_t data) ; @@ -73,6 +77,11 @@ u64 addr, quadlet_t *buffer, size_t length); int hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation, u64 addr, int extcode, quadlet_t *data, quadlet_t arg); +int hpsb_lock64(struct hpsb_host *host, nodeid_t node, unsigned int generation, + u64 addr, int extcode, octlet_t *data, octlet_t arg); +int hpsb_send_gasp(struct hpsb_host *host, int channel, unsigned int generation, + quadlet_t *buffer, size_t length, u32 specifier_id, + unsigned int version); /* Generic packet creation. Used by hpsb_write. Also useful for protocol * drivers that want to implement their own hpsb_write replacement. */ Modified: branches/gasp/nodemgr.c ============================================================================== --- branches/gasp/nodemgr.c (original) +++ branches/gasp/nodemgr.c 2002-08-09 09:58:56.000000000 -0400 @@ -1159,6 +1159,51 @@ return; } + +/* Because we are a 1394a compliant IRM, we need to inform all the other nodes + * of the broadcast channel. (Really we're only setting the validity bit). */ +static void nodemgr_do_irm_duties(struct hpsb_host *host) +{ + quadlet_t bc; + + if (!host->is_irm) return; + + host->csr.broadcast_channel |= 0x40000000; /* set validity bit */ + + bc = cpu_to_be32(host->csr.broadcast_channel); + + hpsb_write(host, LOCAL_BUS | ALL_NODES, get_hpsb_generation(host), + (CSR_REGISTER_BASE | CSR_BROADCAST_CHANNEL), + &bc, + sizeof(quadlet_t)); +} + + +/* We need to ensure that if we are not the IRM, that the IRM node is capable of + * everything we can do, otherwise issue a bus reset and try to become the IRM + * ourselves. */ +static int nodemgr_check_root_capability(struct hpsb_host *host) +{ + quadlet_t bc; + int status; + + if (host->is_irm) return 0; + + status = hpsb_read(host, LOCAL_BUS | (host->irm_id), + get_hpsb_generation(host), + (CSR_REGISTER_BASE | CSR_BROADCAST_CHANNEL), + &bc, sizeof(quadlet_t)); + + if(status < 0 || !(be32_to_cpu(bc) & 0x80000000)) { + /* The root node does not have a valid BROADCAST_CHANNEL + * register and we do, so reset the bus with force_root set */ + HPSB_INFO("remote root node does not have a valid BROADCAST_CHANNEL register, resetting..."); + hpsb_reset_bus(host, 1); + return 1; + } + return 0; +} + static int nodemgr_host_thread(void *__hi) { struct host_info *hi = (struct host_info *)__hi; @@ -1172,6 +1217,12 @@ * happens when we get a bus reset. */ while (!down_interruptible(&hi->reset_sem) && !down_interruptible(&nodemgr_serialize)) { + if(nodemgr_check_root_capability(hi->host)) { + up(&nodemgr_serialize); + continue; /* don't do anything else, we're resetting */ + } + nodemgr_do_irm_duties(hi->host); + nodemgr_node_probe(hi->host); up(&nodemgr_serialize); } Modified: branches/gasp/hosts.c ============================================================================== --- branches/gasp/hosts.c (original) +++ branches/gasp/hosts.c 2002-08-09 09:58:56.000000000 -0400 @@ -136,6 +136,8 @@ sema_init(&h->tlabel_count, 64); spin_lock_init(&h->tlabel_lock); + spin_lock_init(&h->channel_access_lock); + atomic_set(&h->generation, 0); INIT_TQUEUE(&h->timeout_tq, (void (*)(void*))abort_timedouts, h); Modified: branches/gasp/eth1394.c ============================================================================== --- branches/gasp/eth1394.c (original) +++ branches/gasp/eth1394.c 2002-08-09 09:58:56.000000000 -0400 @@ -74,7 +74,8 @@ printk(level ETHER1394_DRIVER_NAME": %s: " fmt, dev_name, ## args) #define DEBUG(fmt, args...) \ - printk(KERN_ERR fmt, ## args) + ETH1394_PRINT_G(KERN_ERR, "%s[%d]:"fmt"\n", __FUNCTION__, __LINE__, ## args) + static char version[] __devinitdata = "$Rev$ Ben Collins <bco...@de...>"; @@ -167,7 +168,7 @@ ETH1394_PRINT (KERN_ERR, dev->name, "Timeout, resetting host %s\n", ((struct eth1394_priv *)(dev->priv))->host->driver->name); - highlevel_host_reset (((struct eth1394_priv *)(dev->priv))->host); + hpsb_reset_bus (((struct eth1394_priv *)(dev->priv))->host, 0); netif_wake_queue (dev); } @@ -178,7 +179,7 @@ * XXX: This is where we need to create a list of skb's for fragmented * packets. */ static inline void ether1394_encapsulate (struct sk_buff *skb, struct net_device *dev, - int proto) + int proto, struct packet_task *ptask) { union eth1394_hdr *hdr = (union eth1394_hdr *)skb_push (skb, hdr_type_len[ETH1394_HDR_LF_UF]); @@ -187,6 +188,16 @@ hdr->words.word1 = htons(hdr->words.word1); hdr->uf.ether_type = proto; + /* Set the transmission type for the packet. Right now only ARP + * packets are sent via GASP. IP broadcast and IP multicast are not + * yet supported properly, they too should use GASP. */ + switch(proto) { + case __constant_htons(ETH_P_ARP): + ptask->tx_type = ETH1394_GASP; + break; + default: + ptask->tx_type = ETH1394_WRREQ; + } return; } @@ -289,6 +300,8 @@ memset (priv->fifo_hi, 0, sizeof (priv->fifo_hi)); memset (priv->fifo_lo, 0, sizeof (priv->fifo_lo)); + priv->bc_state = ETHER1394_CHECK; + /* Register our limits now */ ether1394_register_limits (phy_id, (be32_to_cpu(priv->host->csr.rom[2]) >> 12) & 0xf, priv->host->speed_map[(phy_id << 6) + phy_id], @@ -299,7 +312,8 @@ /* We'll use our max_rec as the default mtu */ if (set_mtu) - dev->mtu = (1 << (priv->max_rec[phy_id] + 1)) - sizeof (union eth1394_hdr); + dev->mtu = (1 << (priv->max_rec[phy_id] + 1)) - /* mtu = max_rec - */ + (sizeof (union eth1394_hdr) + 8); /* (hdr + GASP) */ /* Set our hardware address while we're at it */ *(nodeid_t *)dev->dev_addr = htons (priv->host->node_id); @@ -343,6 +357,8 @@ struct eth1394_priv *priv; static int version_printed = 0; + quadlet_t bc; + if (version_printed++ == 0) ETH1394_PRINT_G (KERN_INFO, "%s\n", version); @@ -382,6 +398,17 @@ list_add_tail (&hi->list, &host_info_list); spin_unlock_irq (&host_info_lock); + + highlevel_read(host, host->node_id, &bc, + CSR_REGISTER_BASE + CSR_BROADCAST_CHANNEL, + sizeof(quadlet_t)); + + /* Ignore validity in hopes that it will be set in the future. It'll + * check it on transmit. */ + priv->broadcast_channel = be32_to_cpu(bc) & 0x3f; + + highlevel_channel_open(host, priv->broadcast_channel, ISOCH_RDWR | ISOCH_SGL_PKT); + return; out: @@ -395,11 +422,14 @@ /* Remove a card from our list */ static void ether1394_remove_host (struct hpsb_host *host) { + struct eth1394_priv *priv; struct host_info *hi; spin_lock_irq (&host_info_lock); hi = find_host_info (host); if (hi != NULL) { + priv = (struct eth1394_priv *)hi->dev->priv; + priv->bc_state = ETHER1394_BC_CLOSED; unregister_netdev (hi->dev); kfree (hi->dev); list_del (&hi->list); @@ -590,6 +620,88 @@ return RCODE_COMPLETE; } +static void ether1394_iso_receive(struct hpsb_host *host, int channel, + quadlet_t *data, unsigned int length) +{ + struct sk_buff *skb; + char *buf = (char *)data + 12; + int flags; + struct net_device *dev = ether1394_find_dev (host); + struct eth1394_priv *priv; + unsigned int len = length - 12; + u32 specifier_id = (((be32_to_cpu(data[1]) & 0xffff) << 8) | + ((be32_to_cpu(data[2]) & 0xff000000) >> 24)); + u16 source_id = be32_to_cpu(data[1]) >> 16; + + if (dev == NULL) { + ETH1394_PRINT_G (KERN_ERR, "Could not find net device for host %s\n", + host->driver->name); + return; + } + + priv = (struct eth1394_priv *)dev->priv; + + if (channel != priv->broadcast_channel || + specifier_id != ETHER1394_GASP_SPECIFIER_ID) { + /* This packet is not for us */ + return; + } + + /* A packet has been received by the ieee1394 bus. Build an skbuff + * around it so we can pass it to the high level network layer. */ + + skb = dev_alloc_skb (len + dev->hard_header_len + 15); + if (!skb) { + HPSB_PRINT (KERN_ERR, "ether1394 rx: low on mem\n"); + priv->stats.rx_dropped++; + return; + } + + skb_reserve(skb, (dev->hard_header_len + 15) & ~15); + + memcpy (skb_put (skb, len), buf, len); + + /* Write metadata, and then pass to the receive level */ + skb->dev = dev; + skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */ + + /* Parse the encapsulation header. This actually does the job of + * converting to an ethernet frame header, aswell as arp + * conversion if needed. ARP conversion is easier in this + * direction, since we are using ethernet as our backend. */ + skb->protocol = ether1394_parse_encap (skb, dev, source_id, + LOCAL_BUS | ALL_NODES); + + spin_lock_irqsave (&priv->lock, flags); + if (!skb->protocol) { + priv->stats.rx_errors++; + priv->stats.rx_dropped++; + dev_kfree_skb_any(skb); + goto bad_proto; + } + + netif_stop_queue(dev); + if (netif_rx (skb) == NET_RX_DROP) { + priv->stats.rx_errors++; + priv->stats.rx_dropped++; + goto bad_proto; + } + + /* Statistics */ + priv->stats.rx_packets++; + priv->stats.rx_bytes += skb->len; + +bad_proto: + netif_start_queue(dev); + spin_unlock_irqrestore (&priv->lock, flags); + + dev->last_rx = jiffies; + + return; +} + + + /* This function is our scheduled write */ static void hpsb_write_sched (void *__ptask) { @@ -598,12 +710,24 @@ struct net_device *dev = ptask->skb->dev; struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv; unsigned long flags; + int status; + + if (ptask->tx_type == ETH1394_GASP) { + status = hpsb_send_gasp(priv->host, priv->broadcast_channel, + get_hpsb_generation(priv->host), + (quadlet_t *)skb->data, skb->len, + ETHER1394_GASP_SPECIFIER_ID, + ETHER1394_GASP_VERSION); + } else { + status = hpsb_write(priv->host, ptask->dest_node, + get_hpsb_generation(priv->host), + ptask->addr, (quadlet_t *)skb->data, + skb->len); + } /* Statistics */ spin_lock_irqsave (&priv->lock, flags); - if (!hpsb_write(priv->host, ptask->dest_node, - get_hpsb_generation(priv->host), - ptask->addr, (quadlet_t *)skb->data, skb->len)) { + if (!status) { priv->stats.tx_bytes += skb->len; priv->stats.tx_packets++; } else { @@ -635,6 +759,54 @@ struct packet_task *ptask = NULL; int ret = 0; + spin_lock_irqsave (&priv->lock, flags); + if(priv->bc_state == ETHER1394_BC_CLOSED) + ETH1394_PRINT(KERN_ERR, dev->name, + "Cannot send packet, no broadcast channel available."); + + /* First time sending? Need a broadcast channel for ARP and for + * listening on */ + if (priv->bc_state == ETHER1394_CHECK) { + quadlet_t bc; + + /* Get the local copy of the broadcast channel and check its + * validity (the IRM should validate it for us) */ + + highlevel_read(priv->host, priv->host->node_id, &bc, + CSR_REGISTER_BASE + CSR_BROADCAST_CHANNEL, + sizeof(quadlet_t)); + + bc = be32_to_cpu(bc); + if((bc & 0xc0000000) != 0xc0000000) { + /* broadcast channel not validated yet */ + ETH1394_PRINT(KERN_WARNING, dev->name, + "Error BROADCAST_CHANNEL register valid " + "bit not set, can't send IP traffic\n"); + highlevel_channel_close(priv->host, + priv->broadcast_channel); + priv->bc_state = ETHER1394_BC_CLOSED; + ret = -EAGAIN; + spin_unlock_irqrestore (&priv->lock, flags); + goto fail; + } + if(priv->broadcast_channel != (bc & 0x3f)) { + /* This really shouldn't be possible, but just in case + * the IEEE 1394 spec changes regarding broadcast + * channels in the future. */ + highlevel_channel_close(priv->host, + priv->broadcast_channel); + priv->broadcast_channel = bc & 0x3f; + ETH1394_PRINT(KERN_WARNING, dev->name, + "Changing to broadcast channel %d...\n", + priv->broadcast_channel); + highlevel_channel_open(priv->host, priv->broadcast_channel, + ISOCH_RDWR | ISOCH_SGL_PKT); + } + priv->bc_state = ETHER1394_OPENED; + } + spin_unlock_irqrestore (&priv->lock, flags); + + if ((skb = skb_share_check (skb, kmflags)) == NULL) { ret = -ENOMEM; goto fail; @@ -653,8 +825,14 @@ if (proto == __constant_htons (ETH_P_ARP)) ether1394_arp_to_1394arp (skb, dev); + ptask = kmem_cache_alloc(packet_task_cache, kmflags); + if (ptask == NULL) { + ret = -ENOMEM; + goto fail; + } + /* Now add our encapsulation header */ - ether1394_encapsulate (skb, dev, proto); + ether1394_encapsulate (skb, dev, proto, ptask); /* TODO: The above encapsulate function needs to recognize when a * packet needs to be split for a specified node. It should create @@ -673,12 +851,6 @@ if (!addr) addr = ETHER1394_REGION_ADDR; - ptask = kmem_cache_alloc(packet_task_cache, kmflags); - if (ptask == NULL) { - ret = -ENOMEM; - goto fail; - } - ptask->skb = skb; ptask->addr = addr; ptask->dest_node = dest_node; @@ -699,7 +871,7 @@ netif_wake_queue (dev); spin_unlock_irqrestore (&priv->lock, flags); - return ret; + return 0; /* returning non-zero causes serious problems */ } /* Function for incoming 1394 packets */ @@ -712,6 +884,7 @@ .add_host = ether1394_add_host, .remove_host = ether1394_remove_host, .host_reset = ether1394_host_reset, + .iso_receive = ether1394_iso_receive, }; static int __init ether1394_init_module (void) @@ -735,6 +908,21 @@ static void __exit ether1394_exit_module (void) { + struct list_head *lh; + struct host_info *hi; + struct eth1394_priv *priv; + + lh = host_info_list.next; + while (lh != &host_info_list) { + hi = list_entry (lh, struct host_info, list); + priv = (struct eth1394_priv*)hi->dev->priv; + if(priv->bc_state != ETHER1394_BC_CLOSED) { + highlevel_channel_close(hi->host, priv->broadcast_channel); + } + lh = lh->next; + } + + hpsb_unregister_highlevel (hl_handle); kmem_cache_destroy(packet_task_cache); } Modified: branches/gasp/hosts.h ============================================================================== --- branches/gasp/hosts.h (original) +++ branches/gasp/hosts.h 2002-08-09 09:58:56.000000000 -0400 @@ -12,6 +12,14 @@ struct hpsb_packet; +typedef enum { + HPSB_CHANNEL_UNUSED, + HPSB_CHANNEL_SHARED, + HPSB_CHANNEL_EXCLUSIVE, + HPSB_CHANNEL_RESERVED, +} __attribute__((packed)) hpsb_channel_alloc_t; + + struct hpsb_host { struct list_head host_list; @@ -32,7 +40,9 @@ spinlock_t tlabel_lock; u32 tlabel_current; - unsigned char iso_listen_count[64]; + spinlock_t channel_access_lock; + unsigned char iso_access_count[64]; + hpsb_channel_alloc_t iso_channel_usage[64]; int node_count; /* number of identified nodes on this bus */ int selfid_count; /* total number of SelfIDs received */ @@ -94,13 +104,19 @@ * fail. */ MODIFY_USAGE, - /* Start or stop receiving isochronous channel in arg. Return void. - * This acts as an optimization hint, hosts are not required not to - * listen on unrequested channels. */ + /* Start or stop receiving isochronous channel in arg. Do not use + * these directly, use the functions highlevel_channel_open() and + * highlevel_channel_close() instead. Returns an error code if there + * is a problem and 0 otherwise. The arg option + * ISO_LISTEN_SINGLE_PACKET may not be implemented for all + * controllers */ ISO_LISTEN_CHANNEL, ISO_UNLISTEN_CHANNEL }; +#define ISO_LISTEN_CHANNEL_MASK 0x3f +#define ISO_LISTEN_SINGLE_PACKET (1 << 6) + enum reset_types { /* 166 microsecond reset -- only type of reset available on non-1394a capable IEEE 1394 controllers */ Modified: branches/gasp/eth1394.h ============================================================================== --- branches/gasp/eth1394.h (original) +++ branches/gasp/eth1394.h 2002-08-09 09:58:56.000000000 -0400 @@ -30,9 +30,17 @@ #define ETHER1394_REGION_ADDR 0xfffff0200000ULL #define ETHER1394_REGION_ADDR_END (ETHER1394_REGION_ADDR + ETHER1394_REGION_ADDR_LEN) +/* GASP identifier numbers for IPv4 over IEEE 1394 */ +#define ETHER1394_GASP_SPECIFIER_ID 0x00005E +#define ETHER1394_GASP_VERSION 1 + + /* Node set == 64 */ #define NODE_SET (ALL_NODES + 1) +enum eth1394_bc_states { ETHER1394_BC_CLOSED, ETHER1394_OPENED, + ETHER1394_CHECK }; + /* Private structure for our ethernet driver */ struct eth1394_priv { struct net_device_stats stats; /* Device stats */ @@ -43,6 +51,8 @@ u32 fifo_lo[ALL_NODES]; /* 32bit lo fifo offset per node */ u64 eui[ALL_NODES]; /* EUI-64 per node */ spinlock_t lock; /* Private lock */ + int broadcast_channel; /* Async stream Broadcast Channel */ + enum eth1394_bc_states bc_state; /* broadcast channel state */ }; struct host_info { @@ -51,12 +61,15 @@ struct net_device *dev; }; +typedef enum {ETH1394_GASP, ETH1394_WRREQ} eth1394_tx_type; + /* This is our task struct. It's used for the complete_tq callback. */ struct packet_task { struct sk_buff *skb; /* Socket buffer we are sending */ nodeid_t dest_node; /* Destination of the packet */ u64 addr; /* Address */ struct tq_struct tq; /* The task */ + eth1394_tx_type tx_type; /* Send data via GASP or Write Req. */ }; /* IP1394 headers */ Modified: branches/gasp/highlevel.c ============================================================================== --- branches/gasp/highlevel.c (original) +++ branches/gasp/highlevel.c 2002-08-09 09:58:56.000000000 -0400 @@ -130,31 +130,77 @@ } -void hpsb_listen_channel(struct hpsb_highlevel *hl, struct hpsb_host *host, - unsigned int channel) +int highlevel_channel_open(struct hpsb_host *host, unsigned int channel, + unsigned int flags) { + int slflags; + int enable_listen = ((flags & (ISOCH_RDONLY | ISOCH_RDWR)) != 0); + int enable_sgl_pkt = ((flags & ISOCH_SGL_PKT) != 0); + int retval = 0; + if (channel > 63) { - HPSB_ERR("%s called with invalid channel", __FUNCTION__); - return; + HPSB_ERR("%s called with invalid channel: %d", __FUNCTION__, channel); + return -EINVAL; } - if (host->iso_listen_count[channel]++ == 0) { - host->driver->devctl(host, ISO_LISTEN_CHANNEL, channel); - } + spin_lock_irqsave(&host->channel_access_lock, slflags); + + if (host->iso_channel_usage[channel] == HPSB_CHANNEL_UNUSED) { + if (flags & ISOCH_RESERVE) + host->iso_channel_usage[channel] = HPSB_CHANNEL_RESERVED; + else if (flags & ISOCH_EXCL) + host->iso_channel_usage[channel] = HPSB_CHANNEL_EXCLUSIVE; + else /* shared channel */ + host->iso_channel_usage[channel] = HPSB_CHANNEL_SHARED; + } else if ((host->iso_channel_usage[channel] != HPSB_CHANNEL_SHARED) || + ((flags & (ISOCH_EXCL | ISOCH_RESERVE)) != 0)) { + spin_unlock_irqrestore(&host->channel_access_lock, slflags); + HPSB_WARN("iso channel %d not available for opening", channel); + return -EBUSY; + ... [truncated message content] |