📄 eth1394.c
字号:
* 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 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;
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);
}
/* We need to encapsulate the standard header with our own. We use the
* ethernet header's proto for our own. */
static 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 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 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 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;
if (hpsb_get_tlabel(p))
return -EAGAIN;
p->tcode = TCODE_WRITEB;
p->header_size = 16;
p->expect_response = 1;
p->header[0] =
p->node_id << 16 | p->tlabel << 10 | 1 << 8 | TCODE_WRITEB << 4;
p->header[1] = host->node_id << 16 | addr >> 32;
p->header[2] = addr & 0xffffffff;
p->header[3] = tx_len << 16;
p->data_size = (tx_len + 3) & ~3;
p->data = data;
return 0;
}
static 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);
p->speed_code = priv->bc_sspd;
/* prevent hpsb_send_packet() from overriding our speed code */
p->node_id = LOCAL_BUS | ALL_NODES;
}
static 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 -ENOMEM;
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 -EAGAIN;
}
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 -EIO;
}
return 0;
}
/* Task function to be run when a datagram transmission is completed */
static void ether1394_dg_complete(struct packet_task *ptask, int fail)
{
struct sk_buff *skb = ptask->skb;
struct eth1394_priv *priv = netdev_priv(skb->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, err;
/* Add the encapsulation header to the fragment */
tx_len = ether1394_encapsulate(ptask->skb, ptask->max_payload,
&ptask->hdr);
err = ether1394_send_packet(ptask, tx_len);
if (err) {
if (err == -EAGAIN)
ETH1394_PRINT_G(KERN_ERR, "Out of tlabels\n");
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)
{
struct eth1394hdr hdr_buf;
struct eth1394_priv *priv = netdev_priv(dev);
__be16 proto;
unsigned long flags;
nodeid_t dest_node;
eth1394_tx_type tx_type;
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, GFP_ATOMIC);
if (ptask == NULL)
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)
goto fail;
#endif
skb = skb_share_check(skb, GFP_ATOMIC);
if (!skb)
goto fail;
/* Get rid of the fake eth1394 header, but first make a copy.
* We might need to rebuild the header on tx failure. */
memcpy(&hdr_buf, skb->data, sizeof(hdr_buf));
skb_pull(skb, ETH1394_HLEN);
proto = hdr_buf.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(hdr_buf.h_dest, dev->broadcast, ETH1394_ALEN) == 0 ||
proto == htons(ETH_P_ARP) ||
(proto == htons(ETH_P_IP) &&
IN_MULTICAST(ntohl(ip_hdr(skb)->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 *)hdr_buf.h_dest);
node = eth1394_find_node_guid(&priv->ip_node_list,
be64_to_cpu(guid));
if (!node)
goto fail;
node_info =
(struct eth1394_node_info *)node->ud->device.driver_data;
if (node_info->fifo == CSR1212_INVALID_ADDR_SPACE)
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)) {
if (dest_node == (LOCAL_BUS | ALL_NODES))
goto fail;
/* At this point we want to restore the packet. When we return
* here with NETDEV_TX_BUSY we will get another entrance in this
* routine with the same skb and we need it to look the same.
* So we pull 4 more bytes, then build the header again. */
skb_pull(skb, 4);
ether1394_header(skb, dev, ntohs(hdr_buf.h_proto),
hdr_buf.h_dest, NULL, 0);
/* Most failures of ether1394_send_packet are recoverable. */
netif_stop_queue(dev);
priv->wake_node = dest_node;
schedule_work(&priv->wake);
kmem_cache_free(packet_task_cache, ptask);
return NETDEV_TX_BUSY;
}
return NETDEV_TX_OK;
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);
/*
* FIXME: According to a patch from 2003-02-26, "returning non-zero
* causes serious problems" here, allegedly. Before that patch,
* -ERRNO was returned which is not appropriate under Linux 2.6.
* Perhaps more needs to be done? Stop the queue in serious
* conditions and restart it elsewhere?
*/
/* return NETDEV_TX_BUSY; */
return NETDEV_TX_OK;
}
static void ether1394_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
strcpy(info->driver, driver_name);
strcpy(info->bus_info, "ieee1394"); /* FIXME provide more detail? */
}
static struct ethtool_ops ethtool_ops = {
.get_drvinfo = ether1394_get_drvinfo
};
static int __init ether1394_init_module(void)
{
int err;
packet_task_cache = kmem_cache_create("packet_task",
sizeof(struct packet_task),
0, 0, NULL, NULL);
if (!packet_task_cache)
return -ENOMEM;
hpsb_register_highlevel(ð1394_highlevel);
err = hpsb_register_protocol(ð1394_proto_driver);
if (err) {
hpsb_unregister_highlevel(ð1394_highlevel);
kmem_cache_destroy(packet_task_cache);
}
return err;
}
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 + -