📄 i2o_lan.c
字号:
/* * drivers/i2o/i2o_lan.c * * I2O LAN CLASS OSM May 26th 2000 * * (C) Copyright 1999, 2000 University of Helsinki, * Department of Computer Science * * This code is still under development / test. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * Authors: Auvo H鋕kinen <Auvo.Hakkinen@cs.Helsinki.FI> * Fixes: Juha Siev鋘en <Juha.Sievanen@cs.Helsinki.FI> * Taneli V鋒鋕angas <Taneli.Vahakangas@cs.Helsinki.FI> * Deepak Saxena <deepak@plexity.net> * * Tested: in FDDI environment (using SysKonnect's DDM) * in Gigabit Eth environment (using SysKonnect's DDM) * in Fast Ethernet environment (using Intel 82558 DDM) * * TODO: tests for other LAN classes (Token Ring, Fibre Channel) */#include <linux/config.h>#include <linux/module.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/fddidevice.h>#include <linux/trdevice.h>#include <linux/fcdevice.h>#include <linux/skbuff.h>#include <linux/if_arp.h>#include <linux/malloc.h>#include <linux/init.h>#include <linux/spinlock.h>#include <linux/tqueue.h>#include <asm/io.h>#include <linux/errno.h>#include <linux/i2o.h>#include "i2o_lan.h"//#define DRIVERDEBUG#ifdef DRIVERDEBUG#define dprintk(s, args...) printk(s, ## args)#else#define dprintk(s, args...)#endif/* The following module parameters are used as default values * for per interface values located in the net_device private area. * Private values are changed via /proc filesystem. */static u32 max_buckets_out = I2O_LAN_MAX_BUCKETS_OUT;static u32 bucket_thresh = I2O_LAN_BUCKET_THRESH;static u32 rx_copybreak = I2O_LAN_RX_COPYBREAK;static u8 tx_batch_mode = I2O_LAN_TX_BATCH_MODE;static u32 i2o_event_mask = I2O_LAN_EVENT_MASK;#define MAX_LAN_CARDS 16static struct net_device *i2o_landevs[MAX_LAN_CARDS+1];static int unit = -1; /* device unit number */static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop, struct i2o_message *m);static void i2o_lan_send_post_reply(struct i2o_handler *h, struct i2o_controller *iop, struct i2o_message *m);static int i2o_lan_receive_post(struct net_device *dev);static void i2o_lan_receive_post_reply(struct i2o_handler *h, struct i2o_controller *iop, struct i2o_message *m);static void i2o_lan_release_buckets(struct net_device *dev, u32 *msg);static int i2o_lan_reset(struct net_device *dev);static void i2o_lan_handle_event(struct net_device *dev, u32 *msg);/* Structures to register handlers for the incoming replies. */static struct i2o_handler i2o_lan_send_handler = { i2o_lan_send_post_reply, // For send replies NULL, NULL, NULL, "I2O LAN OSM send", -1, I2O_CLASS_LAN};static int lan_send_context;static struct i2o_handler i2o_lan_receive_handler = { i2o_lan_receive_post_reply, // For receive replies NULL, NULL, NULL, "I2O LAN OSM receive", -1, I2O_CLASS_LAN};static int lan_receive_context;static struct i2o_handler i2o_lan_handler = { i2o_lan_reply, // For other replies NULL, NULL, NULL, "I2O LAN OSM", -1, I2O_CLASS_LAN};static int lan_context;DECLARE_TASK_QUEUE(i2o_post_buckets_task);struct tq_struct run_i2o_post_buckets_task = { routine: (void (*)(void *)) run_task_queue, data: (void *) 0};/* Functions to handle message failures and transaction errors:==============================================================*//* * i2o_lan_handle_failure(): Fail bit has been set since IOP's message * layer cannot deliver the request to the target, or the target cannot * process the request. */static void i2o_lan_handle_failure(struct net_device *dev, u32 *msg){ struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; struct i2o_device *i2o_dev = priv->i2o_dev; struct i2o_controller *iop = i2o_dev->controller; u32 *preserved_msg = (u32*)(iop->mem_offset + msg[7]); u32 *sgl_elem = &preserved_msg[4]; struct sk_buff *skb = NULL; u8 le_flag; i2o_report_status(KERN_INFO, dev->name, msg); /* If PacketSend failed, free sk_buffs reserved by upper layers */ if (msg[1] >> 24 == LAN_PACKET_SEND) { do { skb = (struct sk_buff *)(sgl_elem[1]); dev_kfree_skb_irq(skb); atomic_dec(&priv->tx_out); le_flag = *sgl_elem >> 31; sgl_elem +=3; } while (le_flag == 0); /* Last element flag not set */ if (netif_queue_stopped(dev)) netif_wake_queue(dev); } /* If ReceivePost failed, free sk_buffs we have reserved */ if (msg[1] >> 24 == LAN_RECEIVE_POST) { do { skb = (struct sk_buff *)(sgl_elem[1]); dev_kfree_skb_irq(skb); atomic_dec(&priv->buckets_out); le_flag = *sgl_elem >> 31; sgl_elem +=3; } while (le_flag == 0); /* Last element flag not set */ } /* Release the preserved msg frame by resubmitting it as a NOP */ preserved_msg[0] = THREE_WORD_MSG_SIZE | SGL_OFFSET_0; preserved_msg[1] = I2O_CMD_UTIL_NOP << 24 | HOST_TID << 12 | 0; preserved_msg[2] = 0; i2o_post_message(iop, msg[7]);}/* * i2o_lan_handle_transaction_error(): IOP or DDM has rejected the request * for general cause (format error, bad function code, insufficient resources, * etc.). We get one transaction_error for each failed transaction. */static void i2o_lan_handle_transaction_error(struct net_device *dev, u32 *msg){ struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; struct sk_buff *skb; i2o_report_status(KERN_INFO, dev->name, msg); /* If PacketSend was rejected, free sk_buff reserved by upper layers */ if (msg[1] >> 24 == LAN_PACKET_SEND) { skb = (struct sk_buff *)(msg[3]); // TransactionContext dev_kfree_skb_irq(skb); atomic_dec(&priv->tx_out); if (netif_queue_stopped(dev)) netif_wake_queue(dev); } /* If ReceivePost was rejected, free sk_buff we have reserved */ if (msg[1] >> 24 == LAN_RECEIVE_POST) { skb = (struct sk_buff *)(msg[3]); dev_kfree_skb_irq(skb); atomic_dec(&priv->buckets_out); }}/* * i2o_lan_handle_status(): Common parts of handling a not succeeded request * (status != SUCCESS). */static int i2o_lan_handle_status(struct net_device *dev, u32 *msg){ /* Fail bit set? */ if (msg[0] & MSG_FAIL) { i2o_lan_handle_failure(dev, msg); return -1; } /* Message rejected for general cause? */ if ((msg[4]>>24) == I2O_REPLY_STATUS_TRANSACTION_ERROR) { i2o_lan_handle_transaction_error(dev, msg); return -1; } /* Else have to handle it in the callback function */ return 0;}/* Callback functions called from the interrupt routine:=======================================================*//* * i2o_lan_send_post_reply(): Callback function to handle PostSend replies. */static void i2o_lan_send_post_reply(struct i2o_handler *h, struct i2o_controller *iop, struct i2o_message *m){ u32 *msg = (u32 *)m; u8 unit = (u8)(msg[2]>>16); // InitiatorContext struct net_device *dev = i2o_landevs[unit]; struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; u8 trl_count = msg[3] & 0x000000FF; if ((msg[4] >> 24) != I2O_REPLY_STATUS_SUCCESS) { if (i2o_lan_handle_status(dev, msg)) return; }#ifdef DRIVERDEBUG i2o_report_status(KERN_INFO, dev->name, msg);#endif /* DDM has handled transmit request(s), free sk_buffs. * We get similar single transaction reply also in error cases * (except if msg failure or transaction error). */ while (trl_count) { dev_kfree_skb_irq((struct sk_buff *)msg[4 + trl_count]); dprintk(KERN_INFO "%s: tx skb freed (trl_count=%d).\n", dev->name, trl_count); atomic_dec(&priv->tx_out); trl_count--; } /* If priv->tx_out had reached tx_max_out, the queue was stopped */ if (netif_queue_stopped(dev)) netif_wake_queue(dev);}/* * i2o_lan_receive_post_reply(): Callback function to process incoming packets. */static void i2o_lan_receive_post_reply(struct i2o_handler *h, struct i2o_controller *iop, struct i2o_message *m){ u32 *msg = (u32 *)m; u8 unit = (u8)(msg[2]>>16); // InitiatorContext struct net_device *dev = i2o_landevs[unit]; struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv; struct i2o_bucket_descriptor *bucket = (struct i2o_bucket_descriptor *)&msg[6]; struct i2o_packet_info *packet; u8 trl_count = msg[3] & 0x000000FF; struct sk_buff *skb, *old_skb; unsigned long flags = 0; if ((msg[4] >> 24) != I2O_REPLY_STATUS_SUCCESS) { if (i2o_lan_handle_status(dev, msg)) return; i2o_lan_release_buckets(dev, msg); return; }#ifdef DRIVERDEBUG i2o_report_status(KERN_INFO, dev->name, msg);#endif /* Else we are receiving incoming post. */ while (trl_count--) { skb = (struct sk_buff *)bucket->context; packet = (struct i2o_packet_info *)bucket->packet_info; atomic_dec(&priv->buckets_out); /* Sanity checks: Any weird characteristics in bucket? */ if (packet->flags & 0x0f || ! packet->flags & 0x40) { if (packet->flags & 0x01) printk(KERN_WARNING "%s: packet with errors, error code=0x%02x.\n", dev->name, packet->status & 0xff); /* The following shouldn't happen, unless parameters in * LAN_OPERATION group are changed during the run time. */ if (packet->flags & 0x0c) printk(KERN_DEBUG "%s: multi-bucket packets not supported!\n", dev->name); if (! packet->flags & 0x40) printk(KERN_DEBUG "%s: multiple packets in a bucket not supported!\n", dev->name); dev_kfree_skb_irq(skb); bucket++; continue; } /* Copy short packet to a new skb */ if (packet->len < priv->rx_copybreak) { old_skb = skb; skb = (struct sk_buff *)dev_alloc_skb(packet->len+2); if (skb == NULL) { printk(KERN_ERR "%s: Can't allocate skb.\n", dev->name); return; } skb_reserve(skb, 2); memcpy(skb_put(skb, packet->len), old_skb->data, packet->len); spin_lock_irqsave(&priv->fbl_lock, flags); if (priv->i2o_fbl_tail < I2O_LAN_MAX_BUCKETS_OUT) priv->i2o_fbl[++priv->i2o_fbl_tail] = old_skb; else dev_kfree_skb_irq(old_skb); spin_unlock_irqrestore(&priv->fbl_lock, flags); } else skb_put(skb, packet->len); /* Deliver to upper layers */ skb->dev = dev; skb->protocol = priv->type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; dprintk(KERN_INFO "%s: Incoming packet (%d bytes) delivered " "to upper level.\n", dev->name, packet->len); bucket++; // to next Packet Descriptor Block }#ifdef DRIVERDEBUG if (msg[5] == 0) printk(KERN_INFO "%s: DDM out of buckets (priv->count = %d)!\n", dev->name, atomic_read(&priv->buckets_out));#endif /* If DDM has already consumed bucket_thresh buckets, post new ones */ if (atomic_read(&priv->buckets_out) <= priv->max_buckets_out - priv->bucket_thresh) { run_i2o_post_buckets_task.data = (void *)dev; queue_task(&run_i2o_post_buckets_task, &tq_immediate); mark_bh(IMMEDIATE_BH); } return;}/* * i2o_lan_reply(): Callback function to handle other incoming messages * except SendPost and ReceivePost.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -