port more changes to make PCI work
[linux-2.4.git] / net / core / profile.c
1 #include <linux/config.h>
2 #include <linux/types.h>
3 #include <linux/kernel.h>
4 #include <linux/sched.h>
5 #include <linux/mm.h>
6 #include <linux/interrupt.h>
7 #include <linux/netdevice.h>
8 #include <linux/string.h>
9 #include <linux/skbuff.h>
10 #include <linux/proc_fs.h>
11 #include <linux/init.h>
12 #include <linux/ip.h>
13 #include <linux/inet.h>
14 #include <net/checksum.h>
15
16 #include <asm/processor.h>
17 #include <asm/uaccess.h>
18 #include <asm/system.h>
19
20 #include <net/profile.h>
21
22 #ifdef CONFIG_NET_PROFILE
23
24 atomic_t net_profile_active;
25 struct timeval net_profile_adjust;
26
27 NET_PROFILE_DEFINE(total);
28
29 struct net_profile_slot *net_profile_chain = &net_prof_total;
30
31 #ifdef __alpha__
32 __u32 alpha_lo;
33 long alpha_hi;
34
35 static void alpha_tick(unsigned long);
36
37 static struct timer_list alpha_timer =
38         { NULL, NULL, 0, 0L, alpha_tick };
39
40 void alpha_tick(unsigned long dummy)
41 {
42         struct timeval dummy_stamp;
43         net_profile_stamp(&dummy_stamp);
44         alpha_timer.expires = jiffies + 4*HZ;
45         add_timer(&alpha_timer);
46 }
47
48 #endif
49
50 void net_profile_irq_adjust(struct timeval *entered, struct timeval* leaved)
51 {
52         struct net_profile_slot *s;
53
54         net_profile_sub(entered, leaved);
55         for (s = net_profile_chain; s; s = s->next) {
56                 if (s->active)
57                         net_profile_add(leaved, &s->irq);
58         }
59 }
60
61
62 #ifdef CONFIG_PROC_FS
63 static int profile_read_proc(char *buffer, char **start, off_t offset,
64                              int length, int *eof, void *data)
65 {
66         off_t pos=0;
67         off_t begin=0;
68         int len=0;
69         struct net_profile_slot *s;
70
71         len+= sprintf(buffer, "Slot            Hits       Hi         Lo         OnIrqHi    OnIrqLo    Ufl\n");
72
73         if (offset == 0) {
74                 cli();
75                 net_prof_total.active = 1;
76                 atomic_inc(&net_profile_active);
77                 NET_PROFILE_LEAVE(total);
78                 sti();
79         }
80         for (s = net_profile_chain; s; s = s->next) {
81                 struct net_profile_slot tmp;
82
83                 cli();
84                 tmp = *s;
85
86                 /* Wrong, but pretty close to truth */
87
88                 s->accumulator.tv_sec = 0;
89                 s->accumulator.tv_usec = 0;
90                 s->irq.tv_sec = 0;
91                 s->irq.tv_usec = 0;
92                 s->hits = 0;
93                 s->underflow = 0;
94                 /* Repair active count, it is possible, only if code has a bug */
95                 if (s->active) {
96                         s->active = 0;
97                         atomic_dec(&net_profile_active);
98                 }
99                 sti();
100
101                 net_profile_sub(&tmp.irq, &tmp.accumulator);
102
103                 len += sprintf(buffer+len,"%-15s %-10d %-10ld %-10lu %-10lu %-10lu %d/%d",
104                                tmp.id,
105                                tmp.hits,
106                                tmp.accumulator.tv_sec,
107                                tmp.accumulator.tv_usec,
108                                tmp.irq.tv_sec,
109                                tmp.irq.tv_usec,
110                                tmp.underflow, tmp.active);
111
112                         buffer[len++]='\n';
113                 
114                         pos=begin+len;
115                         if(pos<offset) {
116                                 len=0;
117                                 begin=pos;
118                         }
119                         if(pos>offset+length)
120                                 goto done;
121         }
122         *eof = 1;
123
124 done:
125         *start=buffer+(offset-begin);
126         len-=(offset-begin);
127         if(len>length)
128                 len=length;
129         if (len < 0)
130                 len = 0;
131         if (offset == 0) {
132                 cli();
133                 net_prof_total.active = 0;
134                 net_prof_total.hits = 0;
135                 net_profile_stamp(&net_prof_total.entered);
136                 sti();
137         }
138         return len;
139 }
140 #endif
141
142 struct iphdr whitehole_iph;
143 int whitehole_count;
144
145 static int whitehole_xmit(struct sk_buff *skb, struct net_device *dev)
146 {
147         struct net_device_stats *stats;
148
149         stats = (struct net_device_stats *)dev->priv;
150         stats->tx_packets++;
151         stats->tx_bytes+=skb->len;
152
153         dev_kfree_skb(skb);
154         return 0;
155 }
156
157 static void whitehole_inject(unsigned long);
158 int whitehole_init(struct net_device *dev);
159
160 static struct timer_list whitehole_timer =
161         { NULL, NULL, 0, 0L, whitehole_inject };
162
163 static struct net_device whitehole_dev = {
164         "whitehole", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NULL, whitehole_init, };
165
166 static int whitehole_open(struct net_device *dev)
167 {
168         whitehole_count = 100000;
169         whitehole_timer.expires = jiffies + 5*HZ;
170         add_timer(&whitehole_timer);
171         return 0;
172 }
173
174 static int whitehole_close(struct net_device *dev)
175 {
176         del_timer(&whitehole_timer);
177         return 0;
178 }
179
180 static void whitehole_inject(unsigned long dummy)
181 {
182         struct net_device_stats *stats = (struct net_device_stats *)whitehole_dev.priv;
183         extern int netdev_dropping;
184
185         do {
186                 struct iphdr *iph;
187                 struct sk_buff *skb = alloc_skb(128, GFP_ATOMIC);
188                 if (!skb)
189                         break;
190                 skb_reserve(skb, 32);
191                 iph = (struct iphdr*)skb_put(skb, sizeof(*iph));
192                 skb->mac.raw = ((u8*)iph) - 14;
193                 memcpy(iph, &whitehole_iph, sizeof(*iph));
194                 skb->protocol = __constant_htons(ETH_P_IP);
195                 skb->dev = &whitehole_dev;
196                 skb->pkt_type = PACKET_HOST;
197                 stats->rx_packets++;
198                 stats->rx_bytes += skb->len;
199                 netif_rx(skb);
200                 whitehole_count--;
201         } while (netdev_dropping == 0 && whitehole_count>0);
202         if (whitehole_count > 0) {
203                 whitehole_timer.expires = jiffies + 1;
204                 add_timer(&whitehole_timer);
205         }
206 }
207
208 static struct net_device_stats *whitehole_get_stats(struct net_device *dev)
209 {
210         struct net_device_stats *stats = (struct net_device_stats *) dev->priv;
211         return stats;
212 }
213
214 int __init whitehole_init(struct net_device *dev)
215 {
216         dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);
217         if (dev->priv == NULL)
218                 return -ENOBUFS;
219         memset(dev->priv, 0, sizeof(struct net_device_stats));
220         dev->get_stats  = whitehole_get_stats;
221         dev->hard_start_xmit = whitehole_xmit;
222         dev->open = whitehole_open;
223         dev->stop = whitehole_close;
224         ether_setup(dev);
225         dev->tx_queue_len = 0;
226         dev->flags |= IFF_NOARP;
227         dev->flags &= ~(IFF_BROADCAST|IFF_MULTICAST);
228         dev->iflink = 0;
229         whitehole_iph.ihl = 5;
230         whitehole_iph.version = 4;
231         whitehole_iph.ttl = 2;
232         whitehole_iph.saddr = in_aton("193.233.7.21");
233         whitehole_iph.daddr = in_aton("193.233.7.10");
234         whitehole_iph.tot_len = htons(20);
235         whitehole_iph.check = ip_compute_csum((void *)&whitehole_iph, 20);
236         return 0;
237 }
238
239 int net_profile_register(struct net_profile_slot *slot)
240 {
241         cli();
242         slot->next = net_profile_chain;
243         net_profile_chain = slot;
244         sti();
245         return 0;
246 }
247
248 int net_profile_unregister(struct net_profile_slot *slot)
249 {
250         struct net_profile_slot **sp, *s;
251
252         for (sp = &net_profile_chain; (s = *sp) != NULL; sp = &s->next) {
253                 if (s == slot) {
254                         cli();
255                         *sp = s->next;
256                         sti();
257                         return 0;
258                 }
259         }
260         return -ESRCH;
261 }
262
263
264 int __init net_profile_init(void)
265 {
266         int i;
267
268 #ifdef CONFIG_PROC_FS
269         create_proc_read_entry("net/profile", 0, 0, profile_read_proc, NULL);
270 #endif
271
272         register_netdevice(&whitehole_dev);
273
274         printk("Evaluating net profiler cost ...");
275 #ifdef __alpha__
276         alpha_tick(0);
277 #endif
278         for (i=0; i<1024; i++) {
279                 NET_PROFILE_ENTER(total);
280                 NET_PROFILE_LEAVE(total);
281         }
282         if (net_prof_total.accumulator.tv_sec) {
283                 printk(" too high!\n");
284         } else {
285                 net_profile_adjust.tv_usec = net_prof_total.accumulator.tv_usec>>10;
286                 printk("%ld units\n", net_profile_adjust.tv_usec);
287         }
288         net_prof_total.hits = 0;
289         net_profile_stamp(&net_prof_total.entered);
290         return 0;
291 }
292
293 #endif