Thread: [Linux1394-cvslog] rev 801 - trunk
Brought to you by:
aeb,
bencollins
From: SVN U. <ben...@li...> - 2003-02-26 21:15:59
|
Author: bencollins Date: 2003-02-26 16:15:08 -0500 (Wed, 26 Feb 2003) New Revision: 801 Modified: trunk/eth1394.c trunk/eth1394.h trunk/ieee1394_core.c trunk/ieee1394_transactions.c trunk/ieee1394_transactions.h trunk/nodemgr.c trunk/ohci1394.c Log: Experimental GASP support patch from Steve Kinneberg. Modified: trunk/ieee1394_core.c ============================================================================== --- trunk/ieee1394_core.c (original) +++ trunk/ieee1394_core.c 2003-02-26 16:15:10.000000000 -0500 @@ -396,9 +396,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; } else { host->is_busmgr = 0; host->is_irm = 0; @@ -1248,6 +1245,7 @@ EXPORT_SYMBOL(hpsb_write); EXPORT_SYMBOL(hpsb_lock); EXPORT_SYMBOL(hpsb_lock64); +EXPORT_SYMBOL(hpsb_send_gasp); EXPORT_SYMBOL(hpsb_packet_success); /** highlevel.c **/ Modified: trunk/ohci1394.c ============================================================================== --- trunk/ohci1394.c (original) +++ trunk/ohci1394.c 2003-02-26 16:15:10.000000000 -0500 @@ -31,9 +31,9 @@ * * Things implemented, but still in test phase: * . Iso Transmit + * . Async Stream Packets Transmit (Receive done via Iso interface) * * Things not implemented: - * . Async Stream Packets * . DMA error recovery * * Known bugs: @@ -649,18 +649,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]; + + if (packet->tcode == TCODE_ISO_DATA) { + /* Sending an async stream packet */ + d->prg_cpu[idx]->data[1] = packet->header[0] & 0xFFFF0000; + } else { + /* Sending a normal async request or response */ + 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 | @@ -830,7 +843,7 @@ /* Decide whether we have an iso, a request, or a response packet */ if (packet->type == hpsb_raw) d = &ohci->at_req_context; - else if (packet->tcode == TCODE_ISO_DATA) { + else if ((packet->tcode == TCODE_ISO_DATA) && (packet->type == hpsb_iso)) { /* The legacy IT DMA context is initialized on first * use. However, the alloc cannot be run from * interrupt context, so we bail out if that is the @@ -856,7 +869,7 @@ } d = &ohci->it_legacy_context; - } else if (packet->tcode & 0x02) + } else if ((packet->tcode & 0x02) && (packet->tcode != TCODE_ISO_DATA)) d = &ohci->at_resp_context; else d = &ohci->at_req_context; @@ -1295,6 +1308,8 @@ u32 *prev_branch = NULL; for (blk = 0; blk < recv->nblocks; blk++) { + u32 control; + /* the DMA descriptor */ struct dma_cmd *cmd = &recv->block[blk]; @@ -1305,29 +1320,29 @@ unsigned long buf_offset = blk * recv->buf_stride; if (recv->dma_mode == BUFFER_FILL_MODE) { - cmd->control = 2 << 28; /* INPUT_MORE */ + control = 2 << 28; /* INPUT_MORE */ } else { - cmd->control = 3 << 28; /* INPUT_LAST */ + control = 3 << 28; /* INPUT_LAST */ } - cmd->control |= 8 << 24; /* s = 1, update xferStatus and resCount */ + control |= 8 << 24; /* s = 1, update xferStatus and resCount */ /* interrupt on last block, and at intervals */ if (blk == recv->nblocks-1 || (blk % recv->block_irq_interval) == 0) { - cmd->control |= 3 << 20; /* want interrupt */ + control |= 3 << 20; /* want interrupt */ } - cmd->control |= 3 << 18; /* enable branch to address */ - cmd->control |= recv->buf_stride; + control |= 3 << 18; /* enable branch to address */ + control |= recv->buf_stride; - cmd->address = dma_region_offset_to_bus(&iso->data_buf, buf_offset); + cmd->control = cpu_to_le32(control); + cmd->address = cpu_to_le32(dma_region_offset_to_bus(&iso->data_buf, buf_offset)); cmd->branchAddress = 0; /* filled in on next loop */ - cmd->status = recv->buf_stride; + cmd->status = cpu_to_le32(recv->buf_stride); /* link the previous descriptor to this one */ if (prev_branch) { - *prev_branch = dma_prog_region_offset_to_bus(&recv->prog, prog_offset); - *prev_branch |= 1; /* set Z=1 */ + *prev_branch = cpu_to_le32(dma_prog_region_offset_to_bus(&recv->prog, prog_offset) | 1); } prev_branch = &cmd->branchAddress; @@ -1485,18 +1500,18 @@ /* 'next' becomes the new end of the DMA chain, so disable branch and enable interrupt */ next->branchAddress = 0; - next->control |= 3 << 20; + next->control |= cpu_to_le32(3 << 20); /* link prev to next */ - prev->branchAddress = dma_prog_region_offset_to_bus(&recv->prog, - sizeof(struct dma_cmd) * next_i) - | 1; /* Z=1 */ + prev->branchAddress = cpu_to_le32(dma_prog_region_offset_to_bus(&recv->prog, + sizeof(struct dma_cmd) * next_i) + | 1); /* Z=1 */ /* disable interrupt on previous DMA descriptor, except at intervals */ if((prev_i % recv->block_irq_interval) == 0) { - prev->control |= 3 << 20; /* enable interrupt */ + prev->control |= cpu_to_le32(3 << 20); /* enable interrupt */ } else { - prev->control &= ~(3<<20); /* disable interrupt */ + prev->control &= cpu_to_le32(~(3<<20)); /* disable interrupt */ } wmb(); @@ -1720,8 +1735,8 @@ struct dma_cmd *il = ((struct dma_cmd*) recv->prog.kvirt) + iso->pkt_dma; /* check the DMA descriptor for new writes to xferStatus */ - u16 xferstatus = il->status >> 16; - u16 rescount = il->status & 0xFFFF; + u16 xferstatus = le32_to_cpu(il->status) >> 16; + u16 rescount = le32_to_cpu(il->status) & 0xFFFF; unsigned char event = xferstatus & 0x1F; @@ -1903,7 +1918,7 @@ struct iso_xmit_cmd *cmd = dma_region_i(&xmit->prog, struct iso_xmit_cmd, iso->pkt_dma); /* check for new writes to xferStatus */ - u16 xferstatus = cmd->output_last.status >> 16; + u16 xferstatus = le32_to_cpu(cmd->output_last.status) >> 16; u8 event = xferstatus & 0x1F; if(!event) { @@ -1919,7 +1934,7 @@ wake = 1; /* parse cycle */ - cycle = cmd->output_last.status & 0x1FFF; + cycle = le32_to_cpu(cmd->output_last.status) & 0x1FFF; /* tell the subsystem the packet has gone out */ hpsb_iso_packet_sent(iso, cycle, event != 0x11); @@ -1972,7 +1987,7 @@ /* set up the OUTPUT_MORE_IMMEDIATE descriptor */ memset(next, 0, sizeof(struct iso_xmit_cmd)); - next->output_more_immediate.control = 0x02000008; + next->output_more_immediate.control = cpu_to_le32(0x02000008); /* ISO packet header is embedded in the OUTPUT_MORE_IMMEDIATE */ @@ -1990,28 +2005,28 @@ next->iso_hdr[7] = len >> 8; /* set up the OUTPUT_LAST */ - next->output_last.control = 1 << 28; - next->output_last.control |= 1 << 27; /* update timeStamp */ - next->output_last.control |= 3 << 20; /* want interrupt */ - next->output_last.control |= 3 << 18; /* enable branch */ - next->output_last.control |= len; + next->output_last.control = cpu_to_le32(1 << 28); + next->output_last.control |= cpu_to_le32(1 << 27); /* update timeStamp */ + next->output_last.control |= cpu_to_le32(3 << 20); /* want interrupt */ + next->output_last.control |= cpu_to_le32(3 << 18); /* enable branch */ + next->output_last.control |= cpu_to_le32(len); /* payload bus address */ - next->output_last.address = dma_region_offset_to_bus(&iso->data_buf, offset); + next->output_last.address = cpu_to_le32(dma_region_offset_to_bus(&iso->data_buf, offset)); /* leave branchAddress at zero for now */ /* re-write the previous DMA descriptor to chain to this one */ /* set prev branch address to point to next (Z=3) */ - prev->output_last.branchAddress = - dma_prog_region_offset_to_bus(&xmit->prog, sizeof(struct iso_xmit_cmd) * next_i) | 3; + prev->output_last.branchAddress = cpu_to_le32( + dma_prog_region_offset_to_bus(&xmit->prog, sizeof(struct iso_xmit_cmd) * next_i) | 3); /* disable interrupt, unless required by the IRQ interval */ if(prev_i % iso->irq_interval) { - prev->output_last.control &= ~(3 << 20); /* no interrupt */ + prev->output_last.control &= cpu_to_le32(~(3 << 20)); /* no interrupt */ } else { - prev->output_last.control |= 3 << 20; /* enable interrupt */ + prev->output_last.control |= cpu_to_le32(3 << 20); /* enable interrupt */ } wmb(); Modified: trunk/ieee1394_transactions.c ============================================================================== --- trunk/ieee1394_transactions.c (original) +++ trunk/ieee1394_transactions.c 2003-02-26 16:15:10.000000000 -0500 @@ -98,6 +98,17 @@ packet->speed_code = SPEED_100; /* Force speed to be 100Mbps */ } +static 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; +} /** * hpsb_get_tlabel - allocate a transaction label @@ -495,7 +506,6 @@ } -/* We need a hpsb_lock64 function for the 64 bit equivalent. Probably. */ int hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation, u64 addr, int extcode, quadlet_t *data, quadlet_t arg) { @@ -558,3 +568,58 @@ 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: trunk/ieee1394_transactions.h ============================================================================== --- trunk/ieee1394_transactions.h (original) +++ trunk/ieee1394_transactions.h 2003-02-26 16:15:10.000000000 -0500 @@ -55,5 +55,8 @@ 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); #endif /* _IEEE1394_TRANSACTIONS_H */ Modified: trunk/nodemgr.c ============================================================================== --- trunk/nodemgr.c (original) +++ trunk/nodemgr.c 2003-02-26 16:15:10.000000000 -0500 @@ -1210,6 +1210,52 @@ return; } +/* Because we are a 1394a-2000 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 1; + + 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 is not IRM capable, resetting..."); + hpsb_reset_bus(host, 1); + return 0; + } + return 1; +} + static int nodemgr_host_thread(void *__hi) { struct host_info *hi = (struct host_info *)__hi; @@ -1222,7 +1268,12 @@ * happens when we get a bus reset. */ while (!down_interruptible(&hi->reset_sem) && !down_interruptible(&nodemgr_serialize)) { + nodemgr_node_probe(hi->host); + + if (nodemgr_check_root_capability(hi->host)) + nodemgr_do_irm_duties(hi->host); + up(&nodemgr_serialize); } #ifdef CONFIG_IEEE1394_VERBOSEDEBUG Modified: trunk/eth1394.c ============================================================================== --- trunk/eth1394.c (original) +++ trunk/eth1394.c 2003-02-26 16:15:10.000000000 -0500 @@ -65,6 +65,7 @@ #include "ieee1394_transactions.h" #include "ieee1394.h" #include "highlevel.h" +#include "iso.h" #include "eth1394.h" #define ETH1394_PRINT_G(level, fmt, args...) \ @@ -101,6 +102,9 @@ MODULE_DESCRIPTION("IEEE 1394 IPv4 Driver (IPv4-over-1394 as per RFC 2734)"); MODULE_LICENSE("GPL"); +static void ether1394_iso(struct hpsb_iso *iso); + + /* Find our host_info struct for a given host pointer. Must be called * under spinlock. */ static inline struct host_info *find_host_info (struct hpsb_host *host) @@ -178,15 +182,26 @@ * 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]); + hdr->words.word1 = 0; hdr->common.lf = ETH1394_HDR_LF_UF; 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; } @@ -280,6 +295,7 @@ unsigned long flags; struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv; int phy_id = NODEID_TO_NODE(priv->host->node_id); + struct hpsb_host *host = priv->host; spin_lock_irqsave (&priv->lock, flags); @@ -289,20 +305,23 @@ memset (priv->fifo_hi, 0, sizeof (priv->fifo_hi)); memset (priv->fifo_lo, 0, sizeof (priv->fifo_lo)); + priv->bc_state = ETHER1394_BC_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], - (u64)(((u64)be32_to_cpu(priv->host->csr.rom[3]) << 32) | - be32_to_cpu(priv->host->csr.rom[4])), + ether1394_register_limits (phy_id, (be32_to_cpu(host->csr.rom[2]) >> 12) & 0xf, + host->speed_map[(phy_id << 6) + phy_id], + (u64)(((u64)be32_to_cpu(host->csr.rom[3]) << 32) | + be32_to_cpu(host->csr.rom[4])), ETHER1394_REGION_ADDR >> 32, ETHER1394_REGION_ADDR & 0xffffffff, priv); /* 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); + *(nodeid_t *)dev->dev_addr = htons (host->node_id); spin_unlock_irqrestore (&priv->lock, flags); } @@ -383,6 +402,15 @@ list_add_tail (&hi->list, &host_info_list); spin_unlock_irq (&host_info_lock); + /* Ignore validity in hopes that it will be set in the future. It'll + * check it on transmit. */ + priv->broadcast_channel = host->csr.broadcast_channel & 0x3f; + + priv->iso = hpsb_iso_recv_init(host, 8 * 4096, 8, priv->broadcast_channel, + 1, ether1394_iso); + if (priv->iso == NULL) { + priv->bc_state = ETHER1394_BC_CLOSED; + } return; out: @@ -396,11 +424,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); @@ -591,6 +622,104 @@ return RCODE_COMPLETE; } +static void ether1394_iso(struct hpsb_iso *iso) +{ + struct sk_buff *skb; + quadlet_t *data; + char *buf; + int flags; + struct net_device *dev = ether1394_find_dev(iso->host); + struct eth1394_priv *priv; + unsigned int len; + u32 specifier_id; + u16 source_id; + int i; + int nready; + + if (dev == NULL) { + ETH1394_PRINT_G (KERN_ERR, "Could not find net device for host %s\n", + iso->host->driver->name); + return; + } + + nready = hpsb_iso_n_ready(iso); + for(i = 0; i < nready; i++) { + struct hpsb_iso_packet_info *info = &iso->infos[iso->first_packet + i]; + data = (quadlet_t*) (iso->data_buf.kvirt + info->offset); + + /* skip over GASP header */ + buf = (char *)data + 8; + len = info->len - 8; + + specifier_id = (((be32_to_cpu(data[0]) & 0xffff) << 8) | + ((be32_to_cpu(data[1]) & 0xff000000) >> 24)); + source_id = be32_to_cpu(data[0]) >> 16; + + priv = (struct eth1394_priv *)dev->priv; + + if (info->channel != priv->broadcast_channel || + specifier_id != ETHER1394_GASP_SPECIFIER_ID) { + /* This packet is not for us */ + continue; + } + + /* 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++; + break; + } + + 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: + spin_unlock_irqrestore (&priv->lock, flags); + } + + hpsb_iso_recv_release_packets(iso, i); + + netif_start_queue(dev); + + dev->last_rx = jiffies; + + return; +} + + /* This function is our scheduled write */ static void hpsb_write_sched (void *__ptask) { @@ -598,13 +727,26 @@ struct sk_buff *skb = ptask->skb; struct net_device *dev = ptask->skb->dev; struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv; - unsigned long flags; + 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 { @@ -636,6 +778,67 @@ 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."); + ret = -EAGAIN; + goto fail; + } + + /* First time sending? Need a broadcast channel for ARP and for + * listening on */ + if (priv->bc_state == ETHER1394_BC_CHECK) { + quadlet_t bc; + + /* Get the local copy of the broadcast channel and check its + * validity (the IRM should validate it for us) */ + + bc = priv->host->csr.broadcast_channel; + + 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"); + hpsb_iso_shutdown(priv->iso); + 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. */ + hpsb_iso_shutdown(priv->iso); + + priv->broadcast_channel = bc & 0x3f; + ETH1394_PRINT(KERN_WARNING, dev->name, + "Changing to broadcast channel %d...\n", + priv->broadcast_channel); + + priv->iso = hpsb_iso_recv_init(priv->host, 8 * 4096, + 8, priv->broadcast_channel, + 1, ether1394_iso); + if (priv->iso == NULL) { + ret = -EAGAIN; + goto fail; + } + } + if (hpsb_iso_recv_start(priv->iso, -1, (1 << 3), -1) < 0) { + ETH1394_PRINT(KERN_ERR, dev->name, + "Could not start async reception\n"); + hpsb_iso_shutdown(priv->iso); + priv->bc_state = ETHER1394_BC_CLOSED; + ret = -EAGAIN; + spin_unlock_irqrestore (&priv->lock, flags); + goto fail; + } + priv->bc_state = ETHER1394_BC_OPENED; + } + spin_unlock_irqrestore (&priv->lock, flags); + if ((skb = skb_share_check (skb, kmflags)) == NULL) { ret = -ENOMEM; goto fail; @@ -654,8 +857,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 @@ -674,12 +883,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; @@ -702,7 +905,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 */ @@ -738,6 +941,19 @@ 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) { + hpsb_iso_shutdown(priv->iso); + } + lh = lh->next; + } hpsb_unregister_highlevel (hl_handle); kmem_cache_destroy(packet_task_cache); } Modified: trunk/eth1394.h ============================================================================== --- trunk/eth1394.h (original) +++ trunk/eth1394.h 2003-02-26 16:15:10.000000000 -0500 @@ -30,9 +30,16 @@ #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_BC_OPENED, + ETHER1394_BC_CHECK }; + /* Private structure for our ethernet driver */ struct eth1394_priv { struct net_device_stats stats; /* Device stats */ @@ -43,6 +50,9 @@ 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 hpsb_iso *iso; /* Async stream recv handle */ }; 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 packet complete 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 hpsb_queue_struct tq; /* The task */ + eth1394_tx_type tx_type; /* Send data via GASP or Write Req. */ }; /* IP1394 headers */ |