11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Simulated Ethernet Driver 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 1999-2001, 2003 Hewlett-Packard Co 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Stephane Eranian <eranian@hpl.hp.com> 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sched.h> 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h> 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/in.h> 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h> 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h> 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h> 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/etherdevice.h> 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/inetdevice.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/if_ether.h> 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/if_arp.h> 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h> 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/notifier.h> 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/bitops.h> 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/irq.h> 247b3166dbc3df5b72f2ba4ea130f4461e318a3838Peter Chubb#include <asm/hpsim.h> 257b3166dbc3df5b72f2ba4ea130f4461e318a3838Peter Chubb 267b3166dbc3df5b72f2ba4ea130f4461e318a3838Peter Chubb#include "hpsim_ssc.h" 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SIMETH_RECV_MAX 10 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Maximum possible received frame for Ethernet. 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We preallocate an sk_buff of that size to avoid costly 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * memcpy for temporary buffer into sk_buff. We do basically 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * what's done in other drivers, like eepro with a ring. 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The difference is, of course, that we don't have real DMA !!! 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SIMETH_FRAME_SIZE ETH_FRAME_LEN 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define NETWORK_INTR 8 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct simeth_local { 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device_stats stats; 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int simfd; /* descriptor in the simulator */ 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int simeth_probe1(void); 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int simeth_open(struct net_device *dev); 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int simeth_close(struct net_device *dev); 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int simeth_tx(struct sk_buff *skb, struct net_device *dev); 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int simeth_rx(struct net_device *dev); 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct net_device_stats *simeth_get_stats(struct net_device *dev); 535dcded1b0b4f1537bb6dff453fb805517756c94bAl Virostatic irqreturn_t simeth_interrupt(int irq, void *dev_id); 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void set_multicast_list(struct net_device *dev); 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int simeth_device_event(struct notifier_block *this,unsigned long event, void *ptr); 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char *simeth_version="0.3"; 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This variable is used to establish a mapping between the Linux/ia64 kernel 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and the host linux kernel. 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * As of today, we support only one card, even though most of the code 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is ready for many more. The mapping is then: 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * linux/ia64 -> linux/x86 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * eth0 -> eth1 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * In the future, we some string operations, we could easily support up 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to 10 cards (0-9). 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The default mapping can be changed on the kernel command line by 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * specifying simeth=ethX (or whatever string you want). 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char *simeth_device="eth0"; /* default host interface to use */ 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic volatile unsigned int card_count; /* how many cards "found" so far */ 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int simeth_debug; /* set to 1 to get debug information */ 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Used to catch IFF_UP & IFF_DOWN events 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct notifier_block simeth_dev_notifier = { 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds simeth_device_event, 86cfa7fd72ca03ac2324e8e469bd4b9ecc6f53394cAl Viro NULL 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function used when using a kernel command line option. 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Format: simeth=interface_name (like eth0) 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssimeth_setup(char *str) 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds simeth_device = str; 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds__setup("simeth=", simeth_setup); 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function used to probe for simeth devices when not installed 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * as a loadable module 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint __init 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssimeth_probe (void) 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int r; 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "simeth: v%s\n", simeth_version); 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds r = simeth_probe1(); 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (r == 0) register_netdevice_notifier(&simeth_dev_notifier); 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return r; 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsnetdev_probe(char *name, unsigned char *ether) 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ia64_ssc(__pa(name), __pa(ether), 0,0, SSC_NETDEV_PROBE); 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsnetdev_attach(int fd, int irq, unsigned int ipaddr) 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* this puts the host interface in the right mode (start interrupting) */ 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ia64_ssc(fd, ipaddr, 0,0, SSC_NETDEV_ATTACH); 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsnetdev_detach(int fd) 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * inactivate the host interface (don't interrupt anymore) */ 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ia64_ssc(fd, 0,0,0, SSC_NETDEV_DETACH); 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsnetdev_send(int fd, unsigned char *buf, unsigned int len) 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ia64_ssc(fd, __pa(buf), len, 0, SSC_NETDEV_SEND); 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsnetdev_read(int fd, unsigned char *buf, unsigned int len) 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ia64_ssc(fd, __pa(buf), len, 0, SSC_NETDEV_RECV); 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 158f9867328f9e1c3fceb8593f84b980aa1d648ce9cAlexey Dobriyanstatic const struct net_device_ops simeth_netdev_ops = { 159f9867328f9e1c3fceb8593f84b980aa1d648ce9cAlexey Dobriyan .ndo_open = simeth_open, 160f9867328f9e1c3fceb8593f84b980aa1d648ce9cAlexey Dobriyan .ndo_stop = simeth_close, 161f9867328f9e1c3fceb8593f84b980aa1d648ce9cAlexey Dobriyan .ndo_start_xmit = simeth_tx, 162f9867328f9e1c3fceb8593f84b980aa1d648ce9cAlexey Dobriyan .ndo_get_stats = simeth_get_stats, 163afc4b13df143122f99a0eb10bfefb216c2806de0Jiri Pirko .ndo_set_rx_mode = set_multicast_list, /* not yet used */ 164f9867328f9e1c3fceb8593f84b980aa1d648ce9cAlexey Dobriyan 165f9867328f9e1c3fceb8593f84b980aa1d648ce9cAlexey Dobriyan}; 166f9867328f9e1c3fceb8593f84b980aa1d648ce9cAlexey Dobriyan 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function shared with module code, so cannot be in init section 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * So far this function "detects" only one card (test_&_set) but could 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * be extended easily. 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Return: 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - -ENODEV is no device found 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - -ENOMEM is no more memory 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - 0 otherwise 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssimeth_probe1(void) 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char mac_addr[ETH_ALEN]; 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct simeth_local *local; 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev; 184ff40a675bba27c990c7b32c2fcc50d3db758b226Danny Kukawka int fd, err, rc; 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * XXX Fix me 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * let's support just one card for now 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (test_and_set_bit(0, &card_count)) 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * check with the simulator for the device 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fd = netdev_probe(simeth_device, mac_addr); 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fd == -1) 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev = alloc_etherdev(sizeof(struct simeth_local)); 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dev) 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(dev->dev_addr, mac_addr, sizeof(mac_addr)); 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20628945dd4fba8dcbc1c74ea702b731caaedae6ccbWang Chen local = netdev_priv(dev); 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local->simfd = fd; /* keep track of underlying file descriptor */ 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 209f9867328f9e1c3fceb8593f84b980aa1d648ce9cAlexey Dobriyan dev->netdev_ops = &simeth_netdev_ops; 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = register_netdev(dev); 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) { 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_netdev(dev); 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * attach the interrupt in the simulator, this does enable interrupts 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * until a netdev_attach() is called 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2216efb6b77ff6fd512e9ef45b29f1940cb924cd7a6Jiri Slaby if ((rc = hpsim_get_irq(NETWORK_INTR)) < 0) 2226efb6b77ff6fd512e9ef45b29f1940cb924cd7a6Jiri Slaby panic("%s: out of interrupt vectors!\n", __func__); 2236efb6b77ff6fd512e9ef45b29f1940cb924cd7a6Jiri Slaby dev->irq = rc; 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 225ff40a675bba27c990c7b32c2fcc50d3db758b226Danny Kukawka printk(KERN_INFO "%s: hosteth=%s simfd=%d, HwAddr=%pm, IRQ %d\n", 226ff40a675bba27c990c7b32c2fcc50d3db758b226Danny Kukawka dev->name, simeth_device, local->simfd, dev->dev_addr, dev->irq); 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * actually binds the device to an interrupt vector 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssimeth_open(struct net_device *dev) 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (request_irq(dev->irq, simeth_interrupt, 0, "simeth", dev)) { 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING "simeth: unable to get IRQ %d.\n", dev->irq); 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EAGAIN; 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_start_queue(dev); 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* copied from lapbether.c */ 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __inline__ int dev_is_ethdev(struct net_device *dev) 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ( dev->type == ARPHRD_ETHER && strncmp(dev->name, "dummy", 5)); 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Handler for IFF_UP or IFF_DOWN 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The reason for that is that we don't want to be interrupted when the 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * interface is down. There is no way to unconnect in the simualtor. Instead 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we use this function to shutdown packet processing in the frame filter 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in the simulator. Thus no interrupts are generated 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * That's also the place where we pass the IP address of this device to the 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * simulator so that that we can start filtering packets for it 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * There may be a better way of doing this, but I don't know which yet. 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssimeth_device_event(struct notifier_block *this,unsigned long event, void *ptr) 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev = ptr; 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct simeth_local *local; 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct in_device *in_dev; 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct in_ifaddr **ifap = NULL; 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct in_ifaddr *ifa = NULL; 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int r; 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ( ! dev ) { 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING "simeth_device_event dev=0\n"); 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NOTIFY_DONE; 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 284c346dca10840a874240c78efe3f39acf4312a1f2YOSHIFUJI Hideaki if (dev_net(dev) != &init_net) 285e9dc86534051b78e41e5b746cccc291b57a3a311Eric W. Biederman return NOTIFY_DONE; 286e9dc86534051b78e41e5b746cccc291b57a3a311Eric W. Biederman 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ( event != NETDEV_UP && event != NETDEV_DOWN ) return NOTIFY_DONE; 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Check whether or not it's for an ethernet device 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * XXX Fixme: This works only as long as we support one 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * type of ethernet device. 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ( !dev_is_ethdev(dev) ) return NOTIFY_DONE; 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((in_dev=dev->ip_ptr) != NULL) { 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (ifap=&in_dev->ifa_list; (ifa=*ifap) != NULL; ifap=&ifa->ifa_next) 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (strcmp(dev->name, ifa->ifa_label) == 0) break; 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ( ifa == NULL ) { 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "simeth_open: can't find device %s's ifa\n", dev->name); 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NOTIFY_DONE; 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "simeth_device_event: %s ipaddr=0x%x\n", 307a144ea4b7a13087081ab5402fa9ad0bcfd249e67Al Viro dev->name, ntohl(ifa->ifa_local)); 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * XXX Fix me 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if the device was up, and we're simply reconfiguring it, not sure 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we get DOWN then UP. 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31528945dd4fba8dcbc1c74ea702b731caaedae6ccbWang Chen local = netdev_priv(dev); 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* now do it for real */ 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds r = event == NETDEV_UP ? 318a144ea4b7a13087081ab5402fa9ad0bcfd249e67Al Viro netdev_attach(local->simfd, dev->irq, ntohl(ifa->ifa_local)): 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netdev_detach(local->simfd); 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "simeth: netdev_attach/detach: event=%s ->%d\n", 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds event == NETDEV_UP ? "attach":"detach", r); 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NOTIFY_DONE; 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssimeth_close(struct net_device *dev) 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_stop_queue(dev); 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_irq(dev->irq, dev); 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Only used for debug 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsframe_print(unsigned char *from, unsigned char *frame, int len) 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s: (%d) %02x", from, len, frame[0] & 0xff); 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for(i=1; i < 6; i++ ) { 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(":%02x", frame[i] &0xff); 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(" %2x", frame[6] &0xff); 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for(i=7; i < 12; i++ ) { 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(":%02x", frame[i] &0xff); 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(" [%02x%02x]\n", frame[12], frame[13]); 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for(i=14; i < len; i++ ) { 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%02x ", frame[i] &0xff); 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ( (i%10)==0) printk("\n"); 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("\n"); 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function used to transmit of frame, very last one on the path before 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * going to the simulator. 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssimeth_tx(struct sk_buff *skb, struct net_device *dev) 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 37028945dd4fba8dcbc1c74ea702b731caaedae6ccbWang Chen struct simeth_local *local = netdev_priv(dev); 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* ensure we have at least ETH_ZLEN bytes (min frame size) */ 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Where do the extra padding bytes comes from inthe skbuff ? */ 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* the real driver in the host system is going to take care of that 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * or maybe it's the NIC itself. 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int length = skb->len; 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local->stats.tx_bytes += skb->len; 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local->stats.tx_packets++; 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (simeth_debug > 5) frame_print("simeth_tx", skb->data, length); 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netdev_send(local->simfd, skb->data, length); 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we are synchronous on write, so we don't simulate a 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * trasnmit complete interrupt, thus we don't need to arm a tx 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_kfree_skb(skb); 3976ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy return NETDEV_TX_OK; 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct sk_buff * 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmake_new_skb(struct net_device *dev) 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *nskb; 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The +2 is used to make sure that the IP header is nicely 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * aligned (on 4byte boundary I assume 14+2=16) 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nskb = dev_alloc_skb(SIMETH_FRAME_SIZE + 2); 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ( nskb == NULL ) { 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_NOTICE "%s: memory squeeze. dropping packet.\n", dev->name); 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_reserve(nskb, 2); /* Align IP on 16 byte boundaries */ 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_put(nskb,SIMETH_FRAME_SIZE); 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return nskb; 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * called from interrupt handler to process a received frame 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssimeth_rx(struct net_device *dev) 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct simeth_local *local; 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb; 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int len; 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rcv_count = SIMETH_RECV_MAX; 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43328945dd4fba8dcbc1c74ea702b731caaedae6ccbWang Chen local = netdev_priv(dev); 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the loop concept has been borrowed from other drivers 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * looks to me like it's a throttling thing to avoid pushing to many 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * packets at one time into the stack. Making sure we can process them 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * upstream and make forward progress overall 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ( (skb=make_new_skb(dev)) == NULL ) { 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_NOTICE "%s: memory squeeze. dropping packet.\n", dev->name); 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local->stats.rx_dropped++; 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Read only one frame at a time 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = netdev_read(local->simfd, skb->data, SIMETH_FRAME_SIZE); 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ( len == 0 ) { 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ( simeth_debug > 0 ) printk(KERN_WARNING "%s: count=%d netdev_read=0\n", 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->name, SIMETH_RECV_MAX-rcv_count); 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * XXX Fix me 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Should really do a csum+copy here 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 46027d7ff46a3498d3debc6ba68fb8014c702b81170Arnaldo Carvalho de Melo skb_copy_to_linear_data(skb, frame, len); 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb->protocol = eth_type_trans(skb, dev); 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ( simeth_debug > 6 ) frame_print("simeth_rx", skb->data, len); 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * push the packet up & trigger software interrupt 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_rx(skb); 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local->stats.rx_packets++; 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local->stats.rx_bytes += len; 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while ( --rcv_count ); 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return len; /* 0 = nothing left to read, otherwise, we can try again */ 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Interrupt handler (Yes, we can do it too !!!) 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic irqreturn_t 4835dcded1b0b4f1537bb6dff453fb805517756c94bAl Virosimeth_interrupt(int irq, void *dev_id) 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev = dev_id; 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * very simple loop because we get interrupts only when receiving 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (simeth_rx(dev)); 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_HANDLED; 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct net_device_stats * 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssimeth_get_stats(struct net_device *dev) 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 49728945dd4fba8dcbc1c74ea702b731caaedae6ccbWang Chen struct simeth_local *local = netdev_priv(dev); 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return &local->stats; 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* fake multicast ability */ 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsset_multicast_list(struct net_device *dev) 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING "%s: set_multicast_list called\n", dev->name); 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds__initcall(simeth_probe); 510