📄 eth1394.c
字号:
} ether1394_data_handler(dev, source_id, LOCAL_BUS | ALL_NODES, buf, len); } hpsb_iso_recv_release_packets(iso, i); dev->last_rx = jiffies;}/****************************************** * Datagram transmission code ******************************************//* Convert a standard ARP packet to 1394 ARP. The first 8 bytes (the entire * arphdr) is the same format as the ip1394 header, so they overlap. The rest * needs to be munged a bit. The remainder of the arphdr is formatted based * on hwaddr len and ipaddr len. We know what they'll be, so it's easy to * judge. * * Now that the EUI is used for the hardware address all we need to do to make * this work for 1394 is to insert 2 quadlets that contain max_rec size, * speed, and unicast FIFO address information between the sender_unique_id * and the IP addresses. */static inline void ether1394_arp_to_1394arp(struct sk_buff *skb, struct net_device *dev){ struct eth1394_priv *priv = netdev_priv(dev); struct arphdr *arp = (struct arphdr *)skb->data; unsigned char *arp_ptr = (unsigned char *)(arp + 1); struct eth1394_arp *arp1394 = (struct eth1394_arp *)skb->data; /* Believe it or not, all that need to happen is sender IP get moved * and set hw_addr_len, max_rec, sspd, fifo_hi and fifo_lo. */ arp1394->hw_addr_len = 16; arp1394->sip = *(u32*)(arp_ptr + ETH1394_ALEN); arp1394->max_rec = priv->host->csr.max_rec; arp1394->sspd = priv->host->csr.lnk_spd; arp1394->fifo_hi = htons (priv->local_fifo >> 32); arp1394->fifo_lo = htonl (priv->local_fifo & ~0x0); return;}/* We need to encapsulate the standard header with our own. We use the * ethernet header's proto for our own. */static inline unsigned int ether1394_encapsulate_prep(unsigned int max_payload, __be16 proto, union eth1394_hdr *hdr, u16 dg_size, u16 dgl){ unsigned int adj_max_payload = max_payload - hdr_type_len[ETH1394_HDR_LF_UF]; /* Does it all fit in one packet? */ if (dg_size <= adj_max_payload) { hdr->uf.lf = ETH1394_HDR_LF_UF; hdr->uf.ether_type = proto; } else { hdr->ff.lf = ETH1394_HDR_LF_FF; hdr->ff.ether_type = proto; hdr->ff.dg_size = dg_size - 1; hdr->ff.dgl = dgl; adj_max_payload = max_payload - hdr_type_len[ETH1394_HDR_LF_FF]; } return((dg_size + (adj_max_payload - 1)) / adj_max_payload);}static inline unsigned int ether1394_encapsulate(struct sk_buff *skb, unsigned int max_payload, union eth1394_hdr *hdr){ union eth1394_hdr *bufhdr; int ftype = hdr->common.lf; int hdrsz = hdr_type_len[ftype]; unsigned int adj_max_payload = max_payload - hdrsz; switch(ftype) { case ETH1394_HDR_LF_UF: bufhdr = (union eth1394_hdr *)skb_push(skb, hdrsz); bufhdr->words.word1 = htons(hdr->words.word1); bufhdr->words.word2 = hdr->words.word2; break; case ETH1394_HDR_LF_FF: bufhdr = (union eth1394_hdr *)skb_push(skb, hdrsz); bufhdr->words.word1 = htons(hdr->words.word1); bufhdr->words.word2 = hdr->words.word2; bufhdr->words.word3 = htons(hdr->words.word3); bufhdr->words.word4 = 0; /* Set frag type here for future interior fragments */ hdr->common.lf = ETH1394_HDR_LF_IF; hdr->sf.fg_off = 0; break; default: hdr->sf.fg_off += adj_max_payload; bufhdr = (union eth1394_hdr *)skb_pull(skb, adj_max_payload); if (max_payload >= skb->len) hdr->common.lf = ETH1394_HDR_LF_LF; bufhdr->words.word1 = htons(hdr->words.word1); bufhdr->words.word2 = htons(hdr->words.word2); bufhdr->words.word3 = htons(hdr->words.word3); bufhdr->words.word4 = 0; } return min(max_payload, skb->len);}static inline struct hpsb_packet *ether1394_alloc_common_packet(struct hpsb_host *host){ struct hpsb_packet *p; p = hpsb_alloc_packet(0); if (p) { p->host = host; p->generation = get_hpsb_generation(host); p->type = hpsb_async; } return p;}static inline int ether1394_prep_write_packet(struct hpsb_packet *p, struct hpsb_host *host, nodeid_t node, u64 addr, void * data, int tx_len){ p->node_id = node; p->data = NULL; p->tcode = TCODE_WRITEB; p->header[1] = (host->node_id << 16) | (addr >> 32); p->header[2] = addr & 0xffffffff; p->header_size = 16; p->expect_response = 1; if (hpsb_get_tlabel(p)) { ETH1394_PRINT_G(KERN_ERR, "No more tlabels left while sending " "to node " NODE_BUS_FMT "\n", NODE_BUS_ARGS(host, node)); return -1; } p->header[0] = (p->node_id << 16) | (p->tlabel << 10) | (1 << 8) | (TCODE_WRITEB << 4); p->header[3] = tx_len << 16; p->data_size = (tx_len + 3) & ~3; p->data = (quadlet_t*)data; return 0;}static inline void ether1394_prep_gasp_packet(struct hpsb_packet *p, struct eth1394_priv *priv, struct sk_buff *skb, int length){ p->header_size = 4; p->tcode = TCODE_STREAM_DATA; p->header[0] = (length << 16) | (3 << 14) | ((priv->broadcast_channel) << 8) | (TCODE_STREAM_DATA << 4); p->data_size = length; p->data = ((quadlet_t*)skb->data) - 2; p->data[0] = cpu_to_be32((priv->host->node_id << 16) | ETHER1394_GASP_SPECIFIER_ID_HI); p->data[1] = cpu_to_be32((ETHER1394_GASP_SPECIFIER_ID_LO << 24) | ETHER1394_GASP_VERSION); /* Setting the node id to ALL_NODES (not LOCAL_BUS | ALL_NODES) * prevents hpsb_send_packet() from setting the speed to an arbitrary * value based on packet->node_id if packet->node_id is not set. */ p->node_id = ALL_NODES; p->speed_code = priv->bc_sspd;}static inline void ether1394_free_packet(struct hpsb_packet *packet){ if (packet->tcode != TCODE_STREAM_DATA) hpsb_free_tlabel(packet); hpsb_free_packet(packet);}static void ether1394_complete_cb(void *__ptask);static int ether1394_send_packet(struct packet_task *ptask, unsigned int tx_len){ struct eth1394_priv *priv = ptask->priv; struct hpsb_packet *packet = NULL; packet = ether1394_alloc_common_packet(priv->host); if (!packet) return -1; if (ptask->tx_type == ETH1394_GASP) { int length = tx_len + (2 * sizeof(quadlet_t)); ether1394_prep_gasp_packet(packet, priv, ptask->skb, length); } else if (ether1394_prep_write_packet(packet, priv->host, ptask->dest_node, ptask->addr, ptask->skb->data, tx_len)) { hpsb_free_packet(packet); return -1; } ptask->packet = packet; hpsb_set_packet_complete_task(ptask->packet, ether1394_complete_cb, ptask); if (hpsb_send_packet(packet) < 0) { ether1394_free_packet(packet); return -1; } return 0;}/* Task function to be run when a datagram transmission is completed */static inline void ether1394_dg_complete(struct packet_task *ptask, int fail){ struct sk_buff *skb = ptask->skb; struct net_device *dev = skb->dev; struct eth1394_priv *priv = netdev_priv(dev); unsigned long flags; /* Statistics */ spin_lock_irqsave(&priv->lock, flags); if (fail) { priv->stats.tx_dropped++; priv->stats.tx_errors++; } else { priv->stats.tx_bytes += skb->len; priv->stats.tx_packets++; } spin_unlock_irqrestore(&priv->lock, flags); dev_kfree_skb_any(skb); kmem_cache_free(packet_task_cache, ptask);}/* Callback for when a packet has been sent and the status of that packet is * known */static void ether1394_complete_cb(void *__ptask){ struct packet_task *ptask = (struct packet_task *)__ptask; struct hpsb_packet *packet = ptask->packet; int fail = 0; if (packet->tcode != TCODE_STREAM_DATA) fail = hpsb_packet_success(packet); ether1394_free_packet(packet); ptask->outstanding_pkts--; if (ptask->outstanding_pkts > 0 && !fail) { int tx_len; /* Add the encapsulation header to the fragment */ tx_len = ether1394_encapsulate(ptask->skb, ptask->max_payload, &ptask->hdr); if (ether1394_send_packet(ptask, tx_len)) ether1394_dg_complete(ptask, 1); } else { ether1394_dg_complete(ptask, fail); }}/* Transmit a packet (called by kernel) */static int ether1394_tx (struct sk_buff *skb, struct net_device *dev){ gfp_t kmflags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL; struct eth1394hdr *eth; struct eth1394_priv *priv = netdev_priv(dev); __be16 proto; unsigned long flags; nodeid_t dest_node; eth1394_tx_type tx_type; int ret = 0; unsigned int tx_len; unsigned int max_payload; u16 dg_size; u16 dgl; struct packet_task *ptask; struct eth1394_node_ref *node; struct eth1394_node_info *node_info = NULL; ptask = kmem_cache_alloc(packet_task_cache, kmflags); if (ptask == NULL) { ret = -ENOMEM; goto fail; } /* XXX Ignore this for now. Noticed that when MacOSX is the IRM, * it does not set our validity bit. We need to compensate for * that somewhere else, but not in eth1394. */#if 0 if ((priv->host->csr.broadcast_channel & 0xc0000000) != 0xc0000000) { ret = -EAGAIN; goto fail; }#endif if ((skb = skb_share_check (skb, kmflags)) == NULL) { ret = -ENOMEM; goto fail; } /* Get rid of the fake eth1394 header, but save a pointer */ eth = (struct eth1394hdr*)skb->data; skb_pull(skb, ETH1394_HLEN); proto = eth->h_proto; dg_size = skb->len; /* Set the transmission type for the packet. ARP packets and IP * broadcast packets are sent via GASP. */ if (memcmp(eth->h_dest, dev->broadcast, ETH1394_ALEN) == 0 || proto == htons(ETH_P_ARP) || (proto == htons(ETH_P_IP) && IN_MULTICAST(ntohl(skb->nh.iph->daddr)))) { tx_type = ETH1394_GASP; dest_node = LOCAL_BUS | ALL_NODES; max_payload = priv->bc_maxpayload - ETHER1394_GASP_OVERHEAD; BUG_ON(max_payload < (512 - ETHER1394_GASP_OVERHEAD)); dgl = priv->bc_dgl; if (max_payload < dg_size + hdr_type_len[ETH1394_HDR_LF_UF]) priv->bc_dgl++; } else { __be64 guid = get_unaligned((u64 *)eth->h_dest); node = eth1394_find_node_guid(&priv->ip_node_list, be64_to_cpu(guid)); if (!node) { ret = -EAGAIN; goto fail; } node_info = (struct eth1394_node_info*)node->ud->device.driver_data; if (node_info->fifo == CSR1212_INVALID_ADDR_SPACE) { ret = -EAGAIN; goto fail; } dest_node = node->ud->ne->nodeid; max_payload = node_info->maxpayload; BUG_ON(max_payload < (512 - ETHER1394_GASP_OVERHEAD)); dgl = node_info->dgl; if (max_payload < dg_size + hdr_type_len[ETH1394_HDR_LF_UF]) node_info->dgl++; tx_type = ETH1394_WRREQ; } /* If this is an ARP packet, convert it */ if (proto == htons(ETH_P_ARP)) ether1394_arp_to_1394arp (skb, dev); ptask->hdr.words.word1 = 0; ptask->hdr.words.word2 = 0; ptask->hdr.words.word3 = 0; ptask->hdr.words.word4 = 0; ptask->skb = skb; ptask->priv = priv; ptask->tx_type = tx_type; if (tx_type != ETH1394_GASP) { u64 addr; spin_lock_irqsave(&priv->lock, flags); addr = node_info->fifo; spin_unlock_irqrestore(&priv->lock, flags); ptask->addr = addr; ptask->dest_node = dest_node; } ptask->tx_type = tx_type; ptask->max_payload = max_payload; ptask->outstanding_pkts = ether1394_encapsulate_prep(max_payload, proto, &ptask->hdr, dg_size, dgl); /* Add the encapsulation header to the fragment */ tx_len = ether1394_encapsulate(skb, max_payload, &ptask->hdr); dev->trans_start = jiffies; if (ether1394_send_packet(ptask, tx_len)) goto fail; netif_wake_queue(dev); return 0;fail: if (ptask) kmem_cache_free(packet_task_cache, ptask); if (skb != NULL) dev_kfree_skb(skb); spin_lock_irqsave (&priv->lock, flags); priv->stats.tx_dropped++; priv->stats.tx_errors++; spin_unlock_irqrestore (&priv->lock, flags); if (netif_queue_stopped(dev)) netif_wake_queue(dev); return 0; /* returning non-zero causes serious problems */}static void ether1394_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info){ strcpy (info->driver, driver_name); /* FIXME XXX provide sane businfo */ strcpy (info->bus_info, "ieee1394");}static struct ethtool_ops ethtool_ops = { .get_drvinfo = ether1394_get_drvinfo};static int __init ether1394_init_module (void){ packet_task_cache = kmem_cache_create("packet_task", sizeof(struct packet_task), 0, 0, NULL, NULL); /* Register ourselves as a highlevel driver */ hpsb_register_highlevel(ð1394_highlevel); return hpsb_register_protocol(ð1394_proto_driver);}static void __exit ether1394_exit_module (void){ hpsb_unregister_protocol(ð1394_proto_driver); hpsb_unregister_highlevel(ð1394_highlevel); kmem_cache_destroy(packet_task_cache);}module_init(ether1394_init_module);module_exit(ether1394_exit_module);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -