| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* bionet.c     BioNet-100 device driver for linux68k. | 
 | 2 |  * | 
 | 3 |  * Version:	@(#)bionet.c	1.0	02/06/96 | 
 | 4 |  * | 
 | 5 |  * Author:	Hartmut Laue <laue@ifk-mp.uni-kiel.de> | 
 | 6 |  * and		Torsten Narjes <narjes@ifk-mp.uni-kiel.de> | 
 | 7 |  * | 
 | 8 |  * Little adaptions for integration into pl7 by Roman Hodek | 
 | 9 |  * | 
 | 10 |  * Some changes in bionet_poll_rx by Karl-Heinz Lohner | 
 | 11 |  * | 
 | 12 | 	What is it ? | 
 | 13 | 	------------ | 
 | 14 | 	This driver controls the BIONET-100 LAN-Adapter which connects | 
 | 15 | 	an ATARI ST/TT via the ACSI-port to an Ethernet-based network. | 
 | 16 |  | 
 | 17 | 	This version can be compiled as a loadable module (See the | 
 | 18 | 	compile command at the bottom of this file). | 
 | 19 | 	At load time, you can optionally set the debugging level and the | 
 | 20 | 	fastest response time on the command line of 'insmod'. | 
 | 21 |  | 
 | 22 | 	'bionet_debug' | 
 | 23 | 		controls the amount of diagnostic messages: | 
 | 24 | 	  0  : no messages | 
 | 25 | 	  >0 : see code for meaning of printed messages | 
 | 26 |  | 
 | 27 | 	'bionet_min_poll_time' (always >=1) | 
 | 28 | 		gives the time (in jiffies) between polls. Low values | 
 | 29 | 		increase the system load (beware!) | 
 | 30 |  | 
 | 31 | 	When loaded, a net device with the name 'bio0' becomes available, | 
 | 32 | 	which can be controlled with the usual 'ifconfig' command. | 
 | 33 |  | 
 | 34 | 	It is possible to compile this driver into the kernel like other | 
 | 35 | 	(net) drivers. For this purpose, some source files (e.g. config-files | 
 | 36 | 	makefiles, Space.c) must be changed accordingly. (You may refer to | 
 | 37 | 	other drivers how to do it.) In this case, the device will be detected | 
 | 38 | 	at boot time and (probably) appear as 'eth0'. | 
 | 39 |  | 
 | 40 | 	This code is based on several sources: | 
 | 41 | 	- The driver code for a parallel port ethernet adapter by | 
 | 42 | 	  Donald Becker (see file 'atp.c' from the PC linux distribution) | 
 | 43 | 	- The ACSI code by Roman Hodek for the ATARI-ACSI harddisk support | 
 | 44 | 	  and DMA handling. | 
 | 45 | 	- Very limited information about moving packets in and out of the | 
 | 46 | 	  BIONET-adapter from the TCP package for TOS by BioData GmbH. | 
 | 47 |  | 
 | 48 | 	Theory of Operation | 
 | 49 | 	------------------- | 
 | 50 | 	Because the ATARI DMA port is usually shared between several | 
 | 51 | 	devices (eg. harddisk, floppy) we cannot block the ACSI bus | 
 | 52 | 	while waiting for interrupts. Therefore we use a polling mechanism | 
 | 53 | 	to fetch packets from the adapter. For the same reason, we send | 
 | 54 | 	packets without checking that the previous packet has been sent to | 
 | 55 | 	the LAN. We rely on the higher levels of the networking code to detect | 
 | 56 | 	missing packets and resend them. | 
 | 57 |  | 
 | 58 | 	Before we access the ATARI DMA controller, we check if another | 
 | 59 | 	process is using the DMA. If not, we lock the DMA, perform one or | 
 | 60 | 	more packet transfers and unlock the DMA before returning. | 
 | 61 | 	We do not use 'stdma_lock' unconditionally because it is unclear | 
 | 62 | 	if the networking code can be set to sleep, which will happen if | 
 | 63 | 	another (possibly slow) device is using the DMA controller. | 
 | 64 |  | 
 | 65 | 	The polling is done via timer interrupts which periodically | 
 | 66 | 	'simulate' an interrupt from the Ethernet adapter. The time (in jiffies) | 
 | 67 | 	between polls varies depending on an estimate of the net activity. | 
 | 68 | 	The allowed range is given by the variable 'bionet_min_poll_time' | 
 | 69 | 	for the lower (fastest) limit and the constant 'MAX_POLL_TIME' | 
 | 70 | 	for the higher (slowest) limit. | 
 | 71 |  | 
 | 72 | 	Whenever a packet arrives, we switch to fastest response by setting | 
 | 73 | 	the polling time to its lowest limit. If the following poll fails, | 
 | 74 | 	because no packets have arrived, we increase the time for the next | 
 | 75 | 	poll. When the net activity is low, the polling time effectively | 
 | 76 | 	stays at its maximum value, resulting in the lowest load for the | 
 | 77 | 	machine. | 
 | 78 |  */ | 
 | 79 |  | 
 | 80 | #define MAX_POLL_TIME	10 | 
 | 81 |  | 
 | 82 | static char version[] = | 
 | 83 | 	"bionet.c:v1.0 06-feb-96 (c) Hartmut Laue.\n"; | 
 | 84 |  | 
 | 85 | #include <linux/module.h> | 
 | 86 |  | 
 | 87 | #include <linux/errno.h> | 
 | 88 | #include <linux/kernel.h> | 
 | 89 | #include <linux/jiffies.h> | 
 | 90 | #include <linux/types.h> | 
 | 91 | #include <linux/fcntl.h> | 
 | 92 | #include <linux/interrupt.h> | 
 | 93 | #include <linux/ioport.h> | 
 | 94 | #include <linux/in.h> | 
 | 95 | #include <linux/slab.h> | 
 | 96 | #include <linux/string.h> | 
 | 97 | #include <linux/delay.h> | 
 | 98 | #include <linux/timer.h> | 
 | 99 | #include <linux/init.h> | 
 | 100 | #include <linux/bitops.h> | 
 | 101 |  | 
 | 102 | #include <linux/netdevice.h> | 
 | 103 | #include <linux/etherdevice.h> | 
 | 104 | #include <linux/skbuff.h> | 
 | 105 |  | 
 | 106 | #include <asm/setup.h> | 
 | 107 | #include <asm/pgtable.h> | 
 | 108 | #include <asm/system.h> | 
 | 109 | #include <asm/io.h> | 
 | 110 | #include <asm/dma.h> | 
 | 111 | #include <asm/atarihw.h> | 
 | 112 | #include <asm/atariints.h> | 
 | 113 | #include <asm/atari_acsi.h> | 
 | 114 | #include <asm/atari_stdma.h> | 
 | 115 |  | 
 | 116 |  | 
 | 117 | /* use 0 for production, 1 for verification, >2 for debug | 
 | 118 |  */ | 
 | 119 | #ifndef NET_DEBUG | 
 | 120 | #define NET_DEBUG 0 | 
 | 121 | #endif | 
 | 122 | /* | 
 | 123 |  * Global variable 'bionet_debug'. Can be set at load time by 'insmod' | 
 | 124 |  */ | 
 | 125 | unsigned int bionet_debug = NET_DEBUG; | 
 | 126 | MODULE_PARM(bionet_debug, "i"); | 
 | 127 | MODULE_PARM_DESC(bionet_debug, "bionet debug level (0-2)"); | 
 | 128 | MODULE_LICENSE("GPL"); | 
 | 129 |  | 
 | 130 | static unsigned int bionet_min_poll_time = 2; | 
 | 131 |  | 
 | 132 |  | 
 | 133 | /* Information that need to be kept for each board. | 
 | 134 |  */ | 
 | 135 | struct net_local { | 
 | 136 | 	struct net_device_stats stats; | 
 | 137 | 	long open_time;			/* for debugging */ | 
 | 138 | 	int  poll_time;			/* polling time varies with net load */ | 
 | 139 | }; | 
 | 140 |  | 
 | 141 | static struct nic_pkt_s {		/* packet format */ | 
 | 142 | 	unsigned char	status; | 
 | 143 | 	unsigned char	dummy; | 
 | 144 | 	unsigned char	l_lo, l_hi; | 
 | 145 | 	unsigned char	buffer[3000]; | 
 | 146 | } *nic_packet; | 
 | 147 | unsigned char *phys_nic_packet; | 
 | 148 |  | 
 | 149 | /* Index to functions, as function prototypes. | 
 | 150 |  */ | 
 | 151 | static int bionet_open(struct net_device *dev); | 
 | 152 | static int bionet_send_packet(struct sk_buff *skb, struct net_device *dev); | 
 | 153 | static void bionet_poll_rx(struct net_device *); | 
 | 154 | static int bionet_close(struct net_device *dev); | 
 | 155 | static struct net_device_stats *net_get_stats(struct net_device *dev); | 
 | 156 | static void bionet_tick(unsigned long); | 
 | 157 |  | 
| Ingo Molnar | 8d06afa | 2005-09-09 13:10:40 -0700 | [diff] [blame] | 158 | static DEFINE_TIMER(bionet_timer, bionet_tick, 0, 0); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 159 |  | 
 | 160 | #define STRAM_ADDR(a)	(((a) & 0xff000000) == 0) | 
 | 161 |  | 
 | 162 | /* The following routines access the ethernet board connected to the | 
 | 163 |  * ACSI port via the st_dma chip. | 
 | 164 |  */ | 
 | 165 | #define NODE_ADR 0x60 | 
 | 166 |  | 
 | 167 | #define C_READ 8 | 
 | 168 | #define C_WRITE 0x0a | 
 | 169 | #define C_GETEA 0x0f | 
 | 170 | #define C_SETCR 0x0e | 
 | 171 |  | 
 | 172 | static int | 
 | 173 | sendcmd(unsigned int a0, unsigned int mod, unsigned int cmd) { | 
 | 174 | 	unsigned int c; | 
 | 175 |  | 
 | 176 | 	dma_wd.dma_mode_status = (mod | ((a0) ? 2 : 0) | 0x88); | 
 | 177 | 	dma_wd.fdc_acces_seccount = cmd; | 
 | 178 | 	dma_wd.dma_mode_status = (mod | 0x8a); | 
 | 179 |  | 
 | 180 | 	if( !acsi_wait_for_IRQ(HZ/2) )	/* wait for cmd ack */ | 
 | 181 | 		return -1;		/* timeout */ | 
 | 182 |  | 
 | 183 | 	c = dma_wd.fdc_acces_seccount; | 
 | 184 | 	return (c & 0xff); | 
 | 185 | } | 
 | 186 |  | 
 | 187 |  | 
 | 188 | static void | 
 | 189 | set_status(int cr) { | 
 | 190 | 	sendcmd(0,0x100,NODE_ADR | C_SETCR);    /* CMD: SET CR */ | 
 | 191 | 	sendcmd(1,0x100,cr); | 
 | 192 |  | 
 | 193 | 	dma_wd.dma_mode_status = 0x80; | 
 | 194 | } | 
 | 195 |  | 
 | 196 | static int | 
 | 197 | get_status(unsigned char *adr) { | 
 | 198 | 	int i,c; | 
 | 199 |  | 
 | 200 | 	DISABLE_IRQ(); | 
 | 201 | 	c = sendcmd(0,0x00,NODE_ADR | C_GETEA);  /* CMD: GET ETH ADR*/ | 
 | 202 | 	if( c < 0 ) goto gsend; | 
 | 203 |  | 
 | 204 | 	/* now read status bytes */ | 
 | 205 |  | 
 | 206 | 	for (i=0; i<6; i++) { | 
 | 207 | 		dma_wd.fdc_acces_seccount = 0;	/* request next byte */ | 
 | 208 |  | 
 | 209 |     		if( !acsi_wait_for_IRQ(HZ/2) ) {	/* wait for cmd ack */ | 
 | 210 | 			c = -1; | 
 | 211 | 			goto gsend;		/* timeout */ | 
 | 212 | 		} | 
 | 213 | 		c = dma_wd.fdc_acces_seccount; | 
 | 214 | 		*adr++ = (unsigned char)c; | 
 | 215 | 	} | 
 | 216 | 	c = 1; | 
 | 217 | gsend: | 
 | 218 |   	dma_wd.dma_mode_status = 0x80; | 
 | 219 | 	return c; | 
 | 220 | } | 
 | 221 |  | 
 | 222 | static irqreturn_t | 
 | 223 | bionet_intr(int irq, void *data, struct pt_regs *fp) { | 
 | 224 | 	return IRQ_HANDLED; | 
 | 225 | } | 
 | 226 |  | 
 | 227 |  | 
 | 228 | static int | 
 | 229 | get_frame(unsigned long paddr, int odd) { | 
 | 230 | 	int c; | 
 | 231 | 	unsigned long flags; | 
 | 232 |  | 
 | 233 | 	DISABLE_IRQ(); | 
 | 234 | 	local_irq_save(flags); | 
 | 235 |  | 
 | 236 | 	dma_wd.dma_mode_status		= 0x9a; | 
 | 237 | 	dma_wd.dma_mode_status		= 0x19a; | 
 | 238 | 	dma_wd.dma_mode_status		= 0x9a; | 
 | 239 | 	dma_wd.fdc_acces_seccount	= 0x04;		/* sector count (was 5) */ | 
 | 240 | 	dma_wd.dma_lo			= (unsigned char)paddr; | 
 | 241 | 	paddr >>= 8; | 
 | 242 | 	dma_wd.dma_md			= (unsigned char)paddr; | 
 | 243 | 	paddr >>= 8; | 
 | 244 | 	dma_wd.dma_hi			= (unsigned char)paddr; | 
 | 245 | 	local_irq_restore(flags); | 
 | 246 |  | 
 | 247 | 	c = sendcmd(0,0x00,NODE_ADR | C_READ);	/* CMD: READ */ | 
 | 248 | 	if( c < 128 ) goto rend; | 
 | 249 |  | 
 | 250 | 	/* now read block */ | 
 | 251 |  | 
 | 252 | 	c = sendcmd(1,0x00,odd);	/* odd flag for address shift */ | 
 | 253 | 	dma_wd.dma_mode_status	= 0x0a; | 
 | 254 |  | 
 | 255 | 	if( !acsi_wait_for_IRQ(100) ) {	/* wait for DMA to complete */ | 
 | 256 | 		c = -1; | 
 | 257 | 		goto rend; | 
 | 258 | 	} | 
 | 259 | 	dma_wd.dma_mode_status	= 0x8a; | 
 | 260 | 	dma_wd.dma_mode_status	= 0x18a; | 
 | 261 | 	dma_wd.dma_mode_status	= 0x8a; | 
 | 262 | 	c = dma_wd.fdc_acces_seccount; | 
 | 263 |  | 
 | 264 | 	dma_wd.dma_mode_status	= 0x88; | 
 | 265 | 	c = dma_wd.fdc_acces_seccount; | 
 | 266 | 	c = 1; | 
 | 267 |  | 
 | 268 | rend: | 
 | 269 | 	dma_wd.dma_mode_status	= 0x80; | 
 | 270 | 	udelay(40); | 
 | 271 | 	acsi_wait_for_noIRQ(20); | 
 | 272 | 	return c; | 
 | 273 | } | 
 | 274 |  | 
 | 275 |  | 
 | 276 | static int | 
 | 277 | hardware_send_packet(unsigned long paddr, int cnt) { | 
 | 278 | 	unsigned int c; | 
 | 279 | 	unsigned long flags; | 
 | 280 |  | 
 | 281 | 	DISABLE_IRQ(); | 
 | 282 | 	local_irq_save(flags); | 
 | 283 |  | 
 | 284 | 	dma_wd.dma_mode_status	= 0x19a; | 
 | 285 | 	dma_wd.dma_mode_status	= 0x9a; | 
 | 286 | 	dma_wd.dma_mode_status	= 0x19a; | 
 | 287 | 	dma_wd.dma_lo		= (unsigned char)paddr; | 
 | 288 | 	paddr >>= 8; | 
 | 289 | 	dma_wd.dma_md		= (unsigned char)paddr; | 
 | 290 | 	paddr >>= 8; | 
 | 291 | 	dma_wd.dma_hi		= (unsigned char)paddr; | 
 | 292 |  | 
 | 293 | 	dma_wd.fdc_acces_seccount	= 0x4;		/* sector count */ | 
 | 294 | 	local_irq_restore(flags); | 
 | 295 |  | 
 | 296 | 	c = sendcmd(0,0x100,NODE_ADR | C_WRITE);	/* CMD: WRITE */ | 
 | 297 | 	c = sendcmd(1,0x100,cnt&0xff); | 
 | 298 | 	c = sendcmd(1,0x100,cnt>>8); | 
 | 299 |  | 
 | 300 | 	/* now write block */ | 
 | 301 |  | 
 | 302 | 	dma_wd.dma_mode_status	= 0x10a;	/* DMA enable */ | 
 | 303 | 	if( !acsi_wait_for_IRQ(100) )		/* wait for DMA to complete */ | 
 | 304 | 		goto end; | 
 | 305 |  | 
 | 306 | 	dma_wd.dma_mode_status	= 0x19a;	/* DMA disable ! */ | 
 | 307 | 	c = dma_wd.fdc_acces_seccount; | 
 | 308 |  | 
 | 309 | end: | 
 | 310 | 	c = sendcmd(1,0x100,0); | 
 | 311 | 	c = sendcmd(1,0x100,0); | 
 | 312 |  | 
 | 313 | 	dma_wd.dma_mode_status	= 0x180; | 
 | 314 | 	udelay(40); | 
 | 315 | 	acsi_wait_for_noIRQ(20); | 
 | 316 | 	return( c & 0x02); | 
 | 317 | } | 
 | 318 |  | 
 | 319 |  | 
 | 320 | /* Check for a network adaptor of this type, and return '0' if one exists. | 
 | 321 |  */ | 
 | 322 | struct net_device * __init bionet_probe(int unit) | 
 | 323 | { | 
 | 324 | 	struct net_device *dev; | 
 | 325 | 	unsigned char station_addr[6]; | 
 | 326 | 	static unsigned version_printed; | 
 | 327 | 	static int no_more_found;	/* avoid "Probing for..." printed 4 times */ | 
 | 328 | 	int i; | 
 | 329 | 	int err; | 
 | 330 |  | 
 | 331 | 	if (!MACH_IS_ATARI || no_more_found) | 
 | 332 | 		return ERR_PTR(-ENODEV); | 
 | 333 |  | 
 | 334 | 	dev = alloc_etherdev(sizeof(struct net_local)); | 
 | 335 | 	if (!dev) | 
 | 336 | 		return ERR_PTR(-ENOMEM); | 
 | 337 | 	if (unit >= 0) { | 
 | 338 | 		sprintf(dev->name, "eth%d", unit); | 
 | 339 | 		netdev_boot_setup_check(dev); | 
 | 340 | 	} | 
 | 341 | 	SET_MODULE_OWNER(dev); | 
 | 342 |  | 
 | 343 | 	printk("Probing for BioNet 100 Adapter...\n"); | 
 | 344 |  | 
 | 345 | 	stdma_lock(bionet_intr, NULL); | 
 | 346 | 	i = get_status(station_addr);	/* Read the station address PROM.  */ | 
 | 347 | 	ENABLE_IRQ(); | 
 | 348 | 	stdma_release(); | 
 | 349 |  | 
 | 350 | 	/* Check the first three octets of the S.A. for the manufactor's code. | 
 | 351 | 	 */ | 
 | 352 |  | 
 | 353 | 	if( i < 0 | 
 | 354 | 	||  station_addr[0] != 'B' | 
 | 355 | 	||  station_addr[1] != 'I' | 
 | 356 | 	||  station_addr[2] != 'O' ) { | 
 | 357 | 		no_more_found = 1; | 
 | 358 | 		printk( "No BioNet 100 found.\n" ); | 
 | 359 | 		free_netdev(dev); | 
 | 360 | 		return ERR_PTR(-ENODEV); | 
 | 361 | 	} | 
 | 362 |  | 
 | 363 | 	if (bionet_debug > 0 && version_printed++ == 0) | 
 | 364 | 		printk(version); | 
 | 365 |  | 
 | 366 | 	printk("%s: %s found, eth-addr: %02x-%02x-%02x:%02x-%02x-%02x.\n", | 
 | 367 | 		dev->name, "BioNet 100", | 
 | 368 | 		station_addr[0], station_addr[1], station_addr[2], | 
 | 369 | 		station_addr[3], station_addr[4], station_addr[5]); | 
 | 370 |  | 
 | 371 | 	/* Initialize the device structure. */ | 
 | 372 |  | 
 | 373 | 	nic_packet = (struct nic_pkt_s *)acsi_buffer; | 
 | 374 | 	phys_nic_packet = (unsigned char *)phys_acsi_buffer; | 
 | 375 | 	if (bionet_debug > 0) { | 
 | 376 | 		printk("nic_packet at 0x%p, phys at 0x%p\n", | 
 | 377 | 			nic_packet, phys_nic_packet ); | 
 | 378 | 	} | 
 | 379 |  | 
 | 380 | 	dev->open		= bionet_open; | 
 | 381 | 	dev->stop		= bionet_close; | 
 | 382 | 	dev->hard_start_xmit	= bionet_send_packet; | 
 | 383 | 	dev->get_stats		= net_get_stats; | 
 | 384 |  | 
 | 385 | 	/* Fill in the fields of the device structure with ethernet-generic | 
 | 386 | 	 * values. This should be in a common file instead of per-driver. | 
 | 387 | 	 */ | 
 | 388 |  | 
 | 389 | 	for (i = 0; i < ETH_ALEN; i++) { | 
 | 390 | #if 0 | 
 | 391 | 		dev->broadcast[i] = 0xff; | 
 | 392 | #endif | 
 | 393 | 		dev->dev_addr[i]  = station_addr[i]; | 
 | 394 | 	} | 
 | 395 | 	err = register_netdev(dev); | 
 | 396 | 	if (!err) | 
 | 397 | 		return dev; | 
 | 398 | 	free_netdev(dev); | 
 | 399 | 	return ERR_PTR(err); | 
 | 400 | } | 
 | 401 |  | 
 | 402 | /* Open/initialize the board.  This is called (in the current kernel) | 
 | 403 |    sometime after booting when the 'ifconfig' program is run. | 
 | 404 |  | 
 | 405 |    This routine should set everything up anew at each open, even | 
 | 406 |    registers that "should" only need to be set once at boot, so that | 
 | 407 |    there is non-reboot way to recover if something goes wrong. | 
 | 408 |  */ | 
 | 409 | static int | 
 | 410 | bionet_open(struct net_device *dev) { | 
 | 411 | 	struct net_local *lp = netdev_priv(dev); | 
 | 412 |  | 
 | 413 | 	if (bionet_debug > 0) | 
 | 414 | 		printk("bionet_open\n"); | 
 | 415 | 	stdma_lock(bionet_intr, NULL); | 
 | 416 |  | 
 | 417 | 	/* Reset the hardware here. | 
 | 418 | 	 */ | 
 | 419 | 	set_status(4); | 
 | 420 | 	lp->open_time = 0;	/*jiffies*/ | 
 | 421 | 	lp->poll_time = MAX_POLL_TIME; | 
 | 422 |  | 
 | 423 | 	dev->tbusy = 0; | 
 | 424 | 	dev->interrupt = 0; | 
 | 425 | 	dev->start = 1; | 
 | 426 |  | 
 | 427 | 	stdma_release(); | 
 | 428 | 	bionet_timer.data = (long)dev; | 
 | 429 | 	bionet_timer.expires = jiffies + lp->poll_time; | 
 | 430 | 	add_timer(&bionet_timer); | 
 | 431 | 	return 0; | 
 | 432 | } | 
 | 433 |  | 
 | 434 | static int | 
 | 435 | bionet_send_packet(struct sk_buff *skb, struct net_device *dev) { | 
 | 436 | 	struct net_local *lp = netdev_priv(dev); | 
 | 437 | 	unsigned long flags; | 
 | 438 |  | 
 | 439 | 	/* Block a timer-based transmit from overlapping.  This could better be | 
 | 440 | 	 * done with atomic_swap(1, dev->tbusy), but set_bit() works as well. | 
 | 441 | 	 */ | 
 | 442 | 	local_irq_save(flags); | 
 | 443 |  | 
 | 444 | 	if (stdma_islocked()) { | 
 | 445 | 		local_irq_restore(flags); | 
 | 446 | 		lp->stats.tx_errors++; | 
 | 447 | 	} | 
 | 448 | 	else { | 
 | 449 | 		int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; | 
 | 450 | 		unsigned long buf = virt_to_phys(skb->data); | 
 | 451 | 		int stat; | 
 | 452 |  | 
 | 453 | 		stdma_lock(bionet_intr, NULL); | 
 | 454 | 		local_irq_restore(flags); | 
 | 455 | 		if( !STRAM_ADDR(buf+length-1) ) { | 
 | 456 | 			memcpy(nic_packet->buffer, skb->data, length); | 
 | 457 | 			buf = (unsigned long)&((struct nic_pkt_s *)phys_nic_packet)->buffer; | 
 | 458 | 		} | 
 | 459 |  | 
 | 460 | 		if (bionet_debug >1) { | 
 | 461 | 			u_char *data = nic_packet->buffer, *p; | 
 | 462 | 			int i; | 
 | 463 | 			 | 
 | 464 | 			printk( "%s: TX pkt type 0x%4x from ", dev->name, | 
 | 465 | 				  ((u_short *)data)[6]); | 
 | 466 |  | 
 | 467 | 			for( p = &data[6], i = 0; i < 6; i++ ) | 
 | 468 | 				printk("%02x%s", *p++,i != 5 ? ":" : "" ); | 
 | 469 | 			printk(" to "); | 
 | 470 |  | 
 | 471 | 			for( p = data, i = 0; i < 6; i++ ) | 
 | 472 | 				printk("%02x%s", *p++,i != 5 ? ":" : "" "\n" ); | 
 | 473 |  | 
 | 474 | 			printk( "%s: ", dev->name ); | 
 | 475 | 			printk(" data %02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x" | 
 | 476 | 			       " %02x%02x%02x%02x len %d\n", | 
 | 477 | 				  data[12], data[13], data[14], data[15], data[16], data[17], data[18], data[19], | 
 | 478 | 				  data[20], data[21], data[22], data[23], data[24], data[25], data[26], data[27], | 
 | 479 | 				  data[28], data[29], data[30], data[31], data[32], data[33], | 
 | 480 | 				  length ); | 
 | 481 | 		} | 
 | 482 | 		dma_cache_maintenance(buf, length, 1); | 
 | 483 |  | 
 | 484 | 		stat = hardware_send_packet(buf, length); | 
 | 485 | 		ENABLE_IRQ(); | 
 | 486 | 		stdma_release(); | 
 | 487 |  | 
 | 488 | 		dev->trans_start = jiffies; | 
 | 489 | 		dev->tbusy	 = 0; | 
 | 490 | 		lp->stats.tx_packets++; | 
 | 491 | 		lp->stats.tx_bytes+=length; | 
 | 492 | 	} | 
 | 493 | 	dev_kfree_skb(skb); | 
 | 494 |  | 
 | 495 | 	return 0; | 
 | 496 | } | 
 | 497 |  | 
 | 498 | /* We have a good packet(s), get it/them out of the buffers. | 
 | 499 |  */ | 
 | 500 | static void | 
 | 501 | bionet_poll_rx(struct net_device *dev) { | 
 | 502 | 	struct net_local *lp = netdev_priv(dev); | 
 | 503 | 	int boguscount = 10; | 
 | 504 | 	int pkt_len, status; | 
 | 505 | 	unsigned long flags; | 
 | 506 |  | 
 | 507 | 	local_irq_save(flags); | 
 | 508 | 	/* ++roman: Take care at locking the ST-DMA... This must be done with ints | 
 | 509 | 	 * off, since otherwise an int could slip in between the question and the | 
 | 510 | 	 * locking itself, and then we'd go to sleep... And locking itself is | 
 | 511 | 	 * necessary to keep the floppy_change timer from working with ST-DMA | 
 | 512 | 	 * registers. */ | 
 | 513 | 	if (stdma_islocked()) { | 
 | 514 | 		local_irq_restore(flags); | 
 | 515 | 		return; | 
 | 516 | 	} | 
 | 517 | 	stdma_lock(bionet_intr, NULL); | 
 | 518 | 	DISABLE_IRQ(); | 
 | 519 | 	local_irq_restore(flags); | 
 | 520 |  | 
 | 521 | 	if( lp->poll_time < MAX_POLL_TIME ) lp->poll_time++; | 
 | 522 |  | 
 | 523 | 	while(boguscount--) { | 
 | 524 | 		status = get_frame((unsigned long)phys_nic_packet, 0); | 
 | 525 |  | 
 | 526 | 		if( status == 0 ) break; | 
 | 527 |  | 
 | 528 | 		/* Good packet... */ | 
 | 529 |  | 
 | 530 | 		dma_cache_maintenance((unsigned long)phys_nic_packet, 1520, 0); | 
 | 531 |  | 
 | 532 | 		pkt_len = (nic_packet->l_hi << 8) | nic_packet->l_lo; | 
 | 533 |  | 
 | 534 | 		lp->poll_time = bionet_min_poll_time;    /* fast poll */ | 
 | 535 | 		if( pkt_len >= 60 && pkt_len <= 1520 ) { | 
 | 536 | 					/*	^^^^ war 1514  KHL */ | 
 | 537 | 			/* Malloc up new buffer. | 
 | 538 | 			 */ | 
 | 539 | 			struct sk_buff *skb = dev_alloc_skb( pkt_len + 2 ); | 
 | 540 | 			if (skb == NULL) { | 
 | 541 | 				printk("%s: Memory squeeze, dropping packet.\n", | 
 | 542 | 					dev->name); | 
 | 543 | 				lp->stats.rx_dropped++; | 
 | 544 | 				break; | 
 | 545 | 			} | 
 | 546 |  | 
 | 547 | 			skb->dev = dev; | 
 | 548 | 			skb_reserve( skb, 2 );		/* 16 Byte align  */ | 
 | 549 | 			skb_put( skb, pkt_len );	/* make room */ | 
 | 550 |  | 
 | 551 | 			/* 'skb->data' points to the start of sk_buff data area. | 
 | 552 | 			 */ | 
 | 553 | 			memcpy(skb->data, nic_packet->buffer, pkt_len); | 
 | 554 | 			skb->protocol = eth_type_trans( skb, dev );  | 
 | 555 | 			netif_rx(skb); | 
 | 556 | 			dev->last_rx = jiffies; | 
 | 557 | 			lp->stats.rx_packets++; | 
 | 558 | 			lp->stats.rx_bytes+=pkt_len; | 
 | 559 |  | 
 | 560 | 	/* If any worth-while packets have been received, dev_rint() | 
 | 561 | 	   has done a mark_bh(INET_BH) for us and will work on them | 
 | 562 | 	   when we get to the bottom-half routine. | 
 | 563 | 	 */ | 
 | 564 |  | 
 | 565 |  			if (bionet_debug >1) { | 
 | 566 |  				u_char *data = nic_packet->buffer, *p; | 
 | 567 |  				int i; | 
 | 568 |  				 | 
 | 569 |  				printk( "%s: RX pkt type 0x%4x from ", dev->name, | 
 | 570 |  					  ((u_short *)data)[6]); | 
 | 571 |  					  | 
 | 572 |  				 | 
 | 573 |  				for( p = &data[6], i = 0; i < 6; i++ ) | 
 | 574 |  					printk("%02x%s", *p++,i != 5 ? ":" : "" ); | 
 | 575 |  				printk(" to "); | 
 | 576 |  				for( p = data, i = 0; i < 6; i++ ) | 
 | 577 |  					printk("%02x%s", *p++,i != 5 ? ":" : "" "\n" ); | 
 | 578 |   | 
 | 579 |  				printk( "%s: ", dev->name ); | 
 | 580 |  				printk(" data %02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x" | 
 | 581 |  				       " %02x%02x%02x%02x len %d\n", | 
 | 582 |  					  data[12], data[13], data[14], data[15], data[16], data[17], data[18], data[19], | 
 | 583 |  					  data[20], data[21], data[22], data[23], data[24], data[25], data[26], data[27], | 
 | 584 |  					  data[28], data[29], data[30], data[31], data[32], data[33], | 
 | 585 |  						  pkt_len ); | 
 | 586 |  			} | 
 | 587 |  		} | 
 | 588 |  		else { | 
 | 589 |  			printk(" Packet has wrong length: %04d bytes\n", pkt_len); | 
 | 590 |  			lp->stats.rx_errors++; | 
 | 591 |  		} | 
 | 592 |  	} | 
 | 593 | 	stdma_release(); | 
 | 594 | 	ENABLE_IRQ(); | 
 | 595 | 	return; | 
 | 596 | } | 
 | 597 |  | 
 | 598 | /* bionet_tick: called by bionet_timer. Reads packets from the adapter, | 
 | 599 |  * passes them to the higher layers and restarts the timer. | 
 | 600 |  */ | 
 | 601 | static void | 
 | 602 | bionet_tick(unsigned long data) { | 
 | 603 | 	struct net_device	 *dev = (struct net_device *)data; | 
 | 604 | 	struct net_local *lp = netdev_priv(dev); | 
 | 605 |  | 
 | 606 | 	if( bionet_debug > 0 && (lp->open_time++ & 7) == 8 ) | 
 | 607 | 		printk("bionet_tick: %ld\n", lp->open_time); | 
 | 608 |  | 
 | 609 | 	if( !stdma_islocked() ) bionet_poll_rx(dev); | 
 | 610 |  | 
 | 611 | 	bionet_timer.expires = jiffies + lp->poll_time; | 
 | 612 | 	add_timer(&bionet_timer); | 
 | 613 | } | 
 | 614 |  | 
 | 615 | /* The inverse routine to bionet_open(). | 
 | 616 |  */ | 
 | 617 | static int | 
 | 618 | bionet_close(struct net_device *dev) { | 
 | 619 | 	struct net_local *lp = netdev_priv(dev); | 
 | 620 |  | 
 | 621 | 	if (bionet_debug > 0) | 
 | 622 | 		printk("bionet_close, open_time=%ld\n", lp->open_time); | 
 | 623 | 	del_timer(&bionet_timer); | 
 | 624 | 	stdma_lock(bionet_intr, NULL); | 
 | 625 |  | 
 | 626 | 	set_status(0); | 
 | 627 | 	lp->open_time = 0; | 
 | 628 |  | 
 | 629 | 	dev->tbusy = 1; | 
 | 630 | 	dev->start = 0; | 
 | 631 |  | 
 | 632 | 	stdma_release(); | 
 | 633 | 	return 0; | 
 | 634 | } | 
 | 635 |  | 
 | 636 | /* Get the current statistics. | 
 | 637 |    This may be called with the card open or closed. | 
 | 638 |  */ | 
 | 639 | static struct net_device_stats *net_get_stats(struct net_device *dev)  | 
 | 640 | { | 
 | 641 | 	struct net_local *lp = netdev_priv(dev); | 
 | 642 | 	return &lp->stats; | 
 | 643 | } | 
 | 644 |  | 
 | 645 |  | 
 | 646 | #ifdef MODULE | 
 | 647 |  | 
 | 648 | static struct net_device *bio_dev; | 
 | 649 |  | 
 | 650 | int init_module(void) | 
 | 651 | { | 
 | 652 | 	bio_dev = bionet_probe(-1); | 
 | 653 | 	if (IS_ERR(bio_dev)) | 
 | 654 | 		return PTR_ERR(bio_dev); | 
 | 655 | 	return 0; | 
 | 656 | } | 
 | 657 |  | 
 | 658 | void cleanup_module(void) | 
 | 659 | { | 
 | 660 | 	unregister_netdev(bio_dev); | 
 | 661 | 	free_netdev(bio_dev); | 
 | 662 | } | 
 | 663 |  | 
 | 664 | #endif /* MODULE */ | 
 | 665 |  | 
 | 666 | /* Local variables: | 
 | 667 |  *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include | 
 | 668 | 	-b m68k-linuxaout -Wall -Wstrict-prototypes -O2 | 
 | 669 | 	-fomit-frame-pointer -pipe -DMODULE -I../../net/inet -c bionet.c" | 
 | 670 |  *  version-control: t | 
 | 671 |  *  kept-new-versions: 5 | 
 | 672 |  *  tab-width: 8 | 
 | 673 |  * End: | 
 | 674 |  */ |