aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/hp100.h
blob: e6ca128a5564ea5cb684f5e8d08026b15cf468e2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
/*
 * hp100.h: Hewlett Packard HP10/100VG ANY LAN ethernet driver for Linux.
 *
 * $Id: hp100.h,v 1.51 1997/04/08 14:26:42 floeff Exp floeff $
 *
 * Authors:  Jaroslav Kysela, <perex@pf.jcu.cz>
 *           Siegfried Loeffler <floeff@tunix.mathematik.uni-stuttgart.de>
 *
 * This driver is based on the 'hpfepkt' crynwr packet driver.
 *
 * This source/code is public free; you can distribute it and/or modify
 * it under terms of the GNU General Public License (published by the
 * Free Software Foundation) either version two of this License, or any
 * later version.
 */

/****************************************************************************
 *  Hardware Constants
 ****************************************************************************/

/*
 * Page Identifiers
 * (Swap Paging Register, PAGING, bits 3:0, Offset 0x02)
 */

#define HP100_PAGE_PERFORMANCE	0x0	/* Page 0 */
#define HP100_PAGE_MAC_ADDRESS	0x1	/* Page 1 */
#define HP100_PAGE_HW_MAP	0x2	/* Page 2 */
#define HP100_PAGE_EEPROM_CTRL	0x3	/* Page 3 */
#define HP100_PAGE_MAC_CTRL	0x4	/* Page 4 */
#define HP100_PAGE_MMU_CFG	0x5	/* Page 5 */
#define HP100_PAGE_ID_MAC_ADDR	0x6	/* Page 6 */
#define HP100_PAGE_MMU_POINTER	0x7	/* Page 7 */


/* Registers that are present on all pages  */

#define HP100_REG_HW_ID		0x00	/* R:  (16) Unique card ID           */
#define HP100_REG_TRACE		0x00	/* W:  (16) Used for debug output    */
#define HP100_REG_PAGING	0x02	/* R:  (16),15:4 Card ID             */
					/* W:  (16),3:0 Switch pages         */
#define HP100_REG_OPTION_LSW	0x04	/* RW: (16) Select card functions    */
#define HP100_REG_OPTION_MSW	0x06	/* RW: (16) Select card functions    */

/*  Page 0 - Performance  */

#define HP100_REG_IRQ_STATUS	0x08	/* RW: (16) Which ints are pending   */
#define HP100_REG_IRQ_MASK	0x0a	/* RW: (16) Select ints to allow     */
#define HP100_REG_FRAGMENT_LEN	0x0c	/* W: (16)12:0 Current fragment len */
/* Note: For 32 bit systems, fragment len and offset registers are available */
/*       at offset 0x28 and 0x2c, where they can be written as 32bit values. */
#define HP100_REG_OFFSET	0x0e	/* RW: (16)12:0 Offset to start read */
#define HP100_REG_DATA32	0x10	/* RW: (32) I/O mode data port       */
#define HP100_REG_DATA16	0x12	/* RW: WORDs must be read from here  */
#define HP100_REG_TX_MEM_FREE	0x14	/* RD: (32) Amount of free Tx mem    */
#define HP100_REG_TX_PDA_L      0x14	/* W: (32) BM: Ptr to PDL, Low Pri  */
#define HP100_REG_TX_PDA_H      0x1c	/* W: (32) BM: Ptr to PDL, High Pri */
#define HP100_REG_RX_PKT_CNT	0x18	/* RD: (8) Rx count of pkts on card  */
#define HP100_REG_TX_PKT_CNT	0x19	/* RD: (8) Tx count of pkts on card  */
#define HP100_REG_RX_PDL        0x1a	/* R: (8) BM: # rx pdl not executed */
#define HP100_REG_TX_PDL        0x1b	/* R: (8) BM: # tx pdl not executed */
#define HP100_REG_RX_PDA        0x18	/* W: (32) BM: Up to 31 addresses */
					/*             which point to a PDL */
#define HP100_REG_SL_EARLY      0x1c	/*    (32) Enhanced Slave Early Rx */
#define HP100_REG_STAT_DROPPED  0x20	/* R (12) Dropped Packet Counter */
#define HP100_REG_STAT_ERRORED  0x22	/* R (8) Errored Packet Counter */
#define HP100_REG_STAT_ABORT    0x23	/* R (8) Abort Counter/OW Coll. Flag */
#define HP100_REG_RX_RING       0x24	/* W (32) Slave: RX Ring Pointers */
#define HP100_REG_32_FRAGMENT_LEN 0x28	/* W (13) Slave: Fragment Length Reg */
#define HP100_REG_32_OFFSET     0x2c	/* W (16) Slave: Offset Register */

/*  Page 1 - MAC Address/Hash Table  */

#define HP100_REG_MAC_ADDR	0x08	/* RW: (8) Cards MAC address         */
#define HP100_REG_HASH_BYTE0	0x10	/* RW: (8) Cards multicast filter    */

/*  Page 2 - Hardware Mapping  */

#define HP100_REG_MEM_MAP_LSW	0x08	/* RW: (16) LSW of cards mem addr    */
#define HP100_REG_MEM_MAP_MSW	0x0a	/* RW: (16) MSW of cards mem addr    */
#define HP100_REG_IO_MAP	0x0c	/* RW: (8) Cards I/O address         */
#define HP100_REG_IRQ_CHANNEL	0x0d	/* RW: (8) IRQ and edge/level int    */
#define HP100_REG_SRAM		0x0e	/* RW: (8) How much RAM on card      */
#define HP100_REG_BM		0x0f	/* RW: (8) Controls BM functions     */

/* New on Page 2 for ETR chips: */
#define HP100_REG_MODECTRL1     0x10	/* RW: (8) Mode Control 1 */
#define HP100_REG_MODECTRL2     0x11	/* RW: (8) Mode Control 2 */
#define HP100_REG_PCICTRL1      0x12	/* RW: (8) PCI Cfg 1 */
#define HP100_REG_PCICTRL2      0x13	/* RW: (8) PCI Cfg 2 */
#define HP100_REG_PCIBUSMLAT    0x15	/* RW: (8) PCI Bus Master Latency */
#define HP100_REG_EARLYTXCFG    0x16	/* RW: (16) Early TX Cfg/Cntrl Reg */
#define HP100_REG_EARLYRXCFG    0x18	/* RW: (8) Early RX Cfg/Cntrl Reg */
#define HP100_REG_ISAPNPCFG1    0x1a	/* RW: (8) ISA PnP Cfg/Cntrl Reg 1 */
#define HP100_REG_ISAPNPCFG2    0x1b	/* RW: (8) ISA PnP Cfg/Cntrl Reg 2 */

/*  Page 3 - EEPROM/Boot ROM  */

#define HP100_REG_EEPROM_CTRL	0x08	/* RW: (16) Used to load EEPROM      */
#define HP100_REG_BOOTROM_CTRL  0x0a

/*  Page 4 - LAN Configuration  (MAC_CTRL) */

#define HP100_REG_10_LAN_CFG_1	0x08	/* RW: (8) Set 10M XCVR functions   */
#define HP100_REG_10_LAN_CFG_2  0x09	/* RW: (8)     10M XCVR functions   */
#define HP100_REG_VG_LAN_CFG_1	0x0a	/* RW: (8) Set 100M XCVR functions  */
#define HP100_REG_VG_LAN_CFG_2  0x0b	/* RW: (8) 100M LAN Training cfgregs */
#define HP100_REG_MAC_CFG_1	0x0c	/* RW: (8) Types of pkts to accept   */
#define HP100_REG_MAC_CFG_2	0x0d	/* RW: (8) Misc MAC functions        */
#define HP100_REG_MAC_CFG_3     0x0e	/* RW: (8) Misc MAC functions */
#define HP100_REG_MAC_CFG_4     0x0f	/* R:  (8) Misc MAC states */
#define HP100_REG_DROPPED	0x10	/* R:  (16),11:0 Pkts cant fit in mem */
#define HP100_REG_CRC		0x12	/* R:  (8) Pkts with CRC             */
#define HP100_REG_ABORT		0x13	/* R:  (8) Aborted Tx pkts           */
#define HP100_REG_TRAIN_REQUEST 0x14	/* RW: (16) Endnode MAC register. */
#define HP100_REG_TRAIN_ALLOW   0x16	/* R:  (16) Hub allowed register */

/*  Page 5 - MMU  */

#define HP100_REG_RX_MEM_STOP	0x0c	/* RW: (16) End of Rx ring addr      */
#define HP100_REG_TX_MEM_STOP	0x0e	/* RW: (16) End of Tx ring addr      */
#define HP100_REG_PDL_MEM_STOP  0x10	/* Not used by 802.12 devices */
#define HP100_REG_ECB_MEM_STOP  0x14	/* I've no idea what this is */

/*  Page 6 - Card ID/Physical LAN Address  */

#define HP100_REG_BOARD_ID	0x08	/* R:  (8) EISA/ISA card ID          */
#define HP100_REG_BOARD_IO_CHCK 0x0c	/* R:  (8) Added to ID to get FFh    */
#define HP100_REG_SOFT_MODEL	0x0d	/* R:  (8) Config program defined    */
#define HP100_REG_LAN_ADDR	0x10	/* R:  (8) MAC addr of card          */
#define HP100_REG_LAN_ADDR_CHCK 0x16	/* R:  (8) Added to addr to get FFh  */

/*  Page 7 - MMU Current Pointers  */

#define HP100_REG_PTR_RXSTART	0x08	/* R:  (16) Current begin of Rx ring */
#define HP100_REG_PTR_RXEND	0x0a	/* R:  (16) Current end of Rx ring   */
#define HP100_REG_PTR_TXSTART	0x0c	/* R:  (16) Current begin of Tx ring */
#define HP100_REG_PTR_TXEND	0x0e	/* R:  (16) Current end of Rx ring   */
#define HP100_REG_PTR_RPDLSTART 0x10
#define HP100_REG_PTR_RPDLEND   0x12
#define HP100_REG_PTR_RINGPTRS  0x14
#define HP100_REG_PTR_MEMDEBUG  0x1a
/* ------------------------------------------------------------------------ */


/*
 * Hardware ID Register I (Always available, HW_ID, Offset 0x00)
 */
#define HP100_HW_ID_CASCADE     0x4850	/* Identifies Cascade Chip */

/*
 * Hardware ID Register 2 & Paging Register
 * (Always available, PAGING, Offset 0x02)
 * Bits 15:4 are for the Chip ID
 */
#define HP100_CHIPID_MASK        0xFFF0
#define HP100_CHIPID_SHASTA      0x5350	/* Not 802.12 compliant */
					 /* EISA BM/SL, MCA16/32 SL, ISA SL */
#define HP100_CHIPID_RAINIER     0x5360	/* Not 802.12 compliant EISA BM, */
					 /* PCI SL, MCA16/32 SL, ISA SL */
#define HP100_CHIPID_LASSEN      0x5370	/* 802.12 compliant PCI BM, PCI SL */
					 /* LRF supported */

/*
 *  Option Registers I and II
 * (Always available, OPTION_LSW, Offset 0x04-0x05)
 */
#define HP100_DEBUG_EN		0x8000	/* 0:Dis., 1:Enable Debug Dump Ptr. */
#define HP100_RX_HDR		0x4000	/* 0:Dis., 1:Enable putting pkt into */
					/*   system mem. before Rx interrupt */
#define HP100_MMAP_DIS		0x2000	/* 0:Enable, 1:Disable mem.mapping. */
					/*   MMAP_DIS must be 0 and MEM_EN */
					/*   must be 1 for memory-mapped */
					/*   mode to be enabled */
#define HP100_EE_EN		0x1000	/* 0:Disable,1:Enable EEPROM writing */
#define HP100_BM_WRITE		0x0800	/* 0:Slave, 1:Bus Master for Tx data */
#define HP100_BM_READ		0x0400	/* 0:Slave, 1:Bus Master for Rx data */
#define HP100_TRI_INT		0x0200	/* 0:Don't, 1:Do tri-state the int */
#define HP100_MEM_EN		0x0040	/* Config program set this to */
					/*   0:Disable, 1:Enable mem map. */
					/*   See MMAP_DIS. */
#define HP100_IO_EN		0x0020	/* 1:Enable I/O transfers */
#define HP100_BOOT_EN		0x0010	/* 1:Enable boot ROM access */
#define HP100_FAKE_INT		0x0008	/* 1:int */
#define HP100_INT_EN		0x0004	/* 1:Enable ints from card */
#define HP100_HW_RST		0x0002	/* 0:Reset, 1:Out of reset */
					/* NIC reset on 0 to 1 transition */

/*
 *  Option Register III
 * (Always available, OPTION_MSW, Offset 0x06)
 */
#define HP100_PRIORITY_TX	0x0080	/* 1:Do all Tx pkts as priority */
#define HP100_EE_LOAD		0x0040	/* 1:EEPROM loading, 0 when done */
#define HP100_ADV_NXT_PKT	0x0004	/* 1:Advance to next pkt in Rx queue */
					/*   h/w will set to 0 when done */
#define HP100_TX_CMD		0x0002	/* 1:Tell h/w download done, h/w */
					/*   will set to 0 when done */

/*
 * Interrupt Status Registers I and II
 * (Page PERFORMANCE, IRQ_STATUS, Offset 0x08-0x09)
 * Note: With old chips, these Registers will clear when 1 is written to them
 *       with new chips this depends on setting of CLR_ISMODE
 */
#define HP100_RX_EARLY_INT      0x2000
#define HP100_RX_PDA_ZERO       0x1000
#define HP100_RX_PDL_FILL_COMPL 0x0800
#define HP100_RX_PACKET		0x0400	/* 0:No, 1:Yes pkt has been Rx */
#define HP100_RX_ERROR		0x0200	/* 0:No, 1:Yes Rx pkt had error */
#define HP100_TX_PDA_ZERO       0x0020	/* 1 when PDA count goes to zero */
#define HP100_TX_SPACE_AVAIL	0x0010	/* 0:<8192, 1:>=8192 Tx free bytes */
#define HP100_TX_COMPLETE	0x0008	/* 0:No, 1:Yes a Tx has completed */
#define HP100_MISC_ERROR        0x0004	/* 0:No, 1:Lan Link down or bus error */
#define HP100_TX_ERROR		0x0002	/* 0:No, 1:Yes Tx pkt had error */

/*
 * Xmit Memory Free Count
 * (Page PERFORMANCE, TX_MEM_FREE, Offset 0x14) (Read only, 32bit)
 */
#define HP100_AUTO_COMPARE	0x80000000	/* Tx Space avail & pkts<255 */
#define HP100_FREE_SPACE	0x7fffffe0	/* Tx free memory */

/*
 *  IRQ Channel
 * (Page HW_MAP, IRQ_CHANNEL, Offset 0x0d)
 */
#define HP100_ZERO_WAIT_EN	0x80	/* 0:No, 1:Yes asserts NOWS signal */
#define HP100_IRQ_SCRAMBLE      0x40
#define HP100_BOND_HP           0x20
#define HP100_LEVEL_IRQ		0x10	/* 0:Edge, 1:Level type interrupts. */
					/* (Only valid on EISA cards) */
#define HP100_IRQMASK		0x0F	/* Isolate the IRQ bits */

/*
 * SRAM Parameters
 * (Page HW_MAP, SRAM, Offset 0x0e)
 */
#define HP100_RAM_SIZE_MASK	0xe0	/* AND to get SRAM size index */
#define HP100_RAM_SIZE_SHIFT	0x05	/* Shift count(put index in lwr bits) */

/*
 * Bus Master Register
 * (Page HW_MAP, BM, Offset 0x0f)
 */
#define HP100_BM_BURST_RD       0x01	/* EISA only: 1=Use burst trans. fm system */
					/* memory to chip (tx) */
#define HP100_BM_BURST_WR       0x02	/* EISA only: 1=Use burst trans. fm system */
					/* memory to chip (rx) */
#define HP100_BM_MASTER		0x04	/* 0:Slave, 1:BM mode */
#define HP100_BM_PAGE_CK        0x08	/* This bit should be set whenever in */
					/* an EISA system */
#define HP100_BM_PCI_8CLK       0x40	/* ... cycles 8 clocks apart */


/*
 * Mode Control Register I
 * (Page HW_MAP, MODECTRL1, Offset0x10)
 */
#define HP100_TX_DUALQ          0x10
   /* If set and BM -> dual tx pda queues */
#define HP100_ISR_CLRMODE       0x02	/* If set ISR will clear all pending */
				       /* interrupts on read (etr only?) */
#define HP100_EE_NOLOAD         0x04	/* Status whether res will be loaded */
				       /* from the eeprom */
#define HP100_TX_CNT_FLG        0x08	/* Controls Early TX Reg Cnt Field */
#define HP100_PDL_USE3          0x10	/* If set BM engine will read only */
				       /* first three data elements of a PDL */
				       /* on the first access. */
#define HP100_BUSTYPE_MASK      0xe0	/* Three bit bus type info */

/*
 * Mode Control Register II
 * (Page HW_MAP, MODECTRL2, Offset0x11)
 */
#define HP100_EE_MASK           0x0f	/* Tell EEPROM circuit not to load */
				       /* certain resources */
#define HP100_DIS_CANCEL        0x20	/* For tx dualq mode operation */
#define HP100_EN_PDL_WB         0x40	/* 1: Status of PDL completion may be */
				       /* written back to system mem */
#define HP100_EN_BUS_FAIL       0x80	/* Enables bus-fail portion of misc */
				       /* interrupt */

/*
 * PCI Configuration and Control Register I
 * (Page HW_MAP, PCICTRL1, Offset 0x12)
 */
#define HP100_LO_MEM            0x01	/* 1: Mapped Mem requested below 1MB */
#define HP100_NO_MEM            0x02	/* 1: Disables Req for sysmem to PCI */
				       /* bios */
#define HP100_USE_ISA           0x04	/* 1: isa type decodes will occur */
				       /* simultaneously with PCI decodes */
#define HP100_IRQ_HI_MASK       0xf0	/* pgmed by pci bios */
#define HP100_PCI_IRQ_HI_MASK   0x78	/* Isolate 4 bits for PCI IRQ  */

/*
 * PCI Configuration and Control Register II
 * (Page HW_MAP, PCICTRL2, Offset 0x13)
 */
#define HP100_RD_LINE_PDL       0x01	/* 1: PCI command Memory Read Line en */
#define HP100_RD_TX_DATA_MASK   0x06	/* choose PCI memread cmds for TX */
#define HP100_MWI               0x08	/* 1: en. PCI memory write invalidate */
#define HP100_ARB_MODE          0x10	/* Select PCI arbitor type */
#define HP100_STOP_EN           0x20	/* Enables PCI state machine to issue */
				       /* pci stop if cascade not ready */
#define HP100_IGNORE_PAR        0x40	/* 1: PCI state machine ignores parity */
#define HP100_PCI_RESET         0x80	/* 0->1: Reset PCI block */

/*
 * Early TX Configuration and Control Register
 * (Page HW_MAP, EARLYTXCFG, Offset 0x16)
 */
#define HP100_EN_EARLY_TX       0x8000	/* 1=Enable Early TX */
#define HP100_EN_ADAPTIVE       0x4000	/* 1=Enable adaptive mode */
#define HP100_EN_TX_UR_IRQ      0x2000	/* reserved, must be 0 */
#define HP100_EN_LOW_TX         0x1000	/* reserved, must be 0 */
#define HP100_ET_CNT_MASK       0x0fff	/* bits 11..0: ET counters */

/*
 * Early RX Configuration and Control Register
 * (Page HW_MAP, EARLYRXCFG, Offset 0x18)
 */
#define HP100_EN_EARLY_RX       0x80	/* 1=Enable Early RX */
#define HP100_EN_LOW_RX         0x40	/* reserved, must be 0 */
#define HP100_RX_TRIP_MASK      0x1f	/* bits 4..0: threshold at which the
					 * early rx circuit will start the
					 * dma of received packet into system
					 * memory for BM */

/*
 *  Serial Devices Control Register
 * (Page EEPROM_CTRL, EEPROM_CTRL, Offset 0x08)
 */
#define HP100_EEPROM_LOAD	0x0001	/* 0->1 loads EEPROM into registers. */
					/* When it goes back to 0, load is   */
					/* complete. This should take ~600us. */

/*
 * 10MB LAN Control and Configuration Register I
 * (Page MAC_CTRL, 10_LAN_CFG_1, Offset 0x08)
 */
#define HP100_MAC10_SEL		0xc0	/* Get bits to indicate MAC */
#define HP100_AUI_SEL		0x20	/* Status of AUI selection */
#define HP100_LOW_TH		0x10	/* 0:No, 1:Yes allow better cabling */
#define HP100_LINK_BEAT_DIS	0x08	/* 0:Enable, 1:Disable link beat */
#define HP100_LINK_BEAT_ST	0x04	/* 0:No, 1:Yes link beat being Rx */
#define HP100_R_ROL_ST		0x02	/* 0:No, 1:Yes Rx twisted pair has */
					/*             been reversed */
#define HP100_AUI_ST		0x01	/* 0:No, 1:Yes use AUI on TP card */

/*
 * 10 MB LAN Control and Configuration Register II
 * (Page MAC_CTRL, 10_LAN_CFG_2, Offset 0x09)
 */
#define HP100_SQU_ST		0x01	/* 0:No, 1:Yes collision signal sent */
					/*       after Tx.Only used for AUI. */
#define HP100_FULLDUP           0x02	/* 1: LXT901 XCVR fullduplx enabled */
#define HP100_DOT3_MAC          0x04	/* 1: DOT 3 Mac sel. unless Autosel */

/*
 * MAC Selection, use with MAC10_SEL bits
 */
#define HP100_AUTO_SEL_10	0x0	/* Auto select */
#define HP100_XCVR_LXT901_10	0x1	/* LXT901 10BaseT transceiver */
#define HP100_XCVR_7213		0x2	/* 7213 transceiver */
#define HP100_XCVR_82503	0x3	/* 82503 transceiver */

/*
 *  100MB LAN Training Register
 * (Page MAC_CTRL, VG_LAN_CFG_2, Offset 0x0b) (old, pre 802.12)
 */
#define HP100_FRAME_FORMAT	0x08	/* 0:802.3, 1:802.5 frames */
#define HP100_BRIDGE		0x04	/* 0:No, 1:Yes tell hub i am a bridge */
#define HP100_PROM_MODE		0x02	/* 0:No, 1:Yes tell hub card is */
					/*         promiscuous */
#define HP100_REPEATER		0x01	/* 0:No, 1:Yes tell hub MAC wants to */
					/*         be a cascaded repeater */

/*
 * 100MB LAN Control and Configuration Register
 * (Page MAC_CTRL, VG_LAN_CFG_1, Offset 0x0a)
 */
#define HP100_VG_SEL	        0x80	/* 0:No, 1:Yes use 100 Mbit MAC */
#define HP100_LINK_UP_ST	0x40	/* 0:No, 1:Yes endnode logged in */
#define HP100_LINK_CABLE_ST	0x20	/* 0:No, 1:Yes cable can hear tones */
					/*         from  hub */
#define HP100_LOAD_ADDR		0x10	/* 0->1 card addr will be sent  */
					/* 100ms later the link status  */
					/* bits are valid */
#define HP100_LINK_CMD		0x08	/* 0->1 link will attempt to log in. */
					/* 100ms later the link status */
					/* bits are valid */
#define HP100_TRN_DONE          0x04	/* NEW ETR-Chips only: Will be reset */
					/* after LinkUp Cmd is given and set */
					/* when training has completed. */
#define HP100_LINK_GOOD_ST	0x02	/* 0:No, 1:Yes cable passed training */
#define HP100_VG_RESET		0x01	/* 0:Yes, 1:No reset the 100VG MAC */


/*
 *  MAC Configuration Register I
 * (Page MAC_CTRL, MAC_CFG_1, Offset 0x0c)
 */
#define HP100_RX_IDLE		0x80	/* 0:Yes, 1:No currently receiving pkts */
#define HP100_TX_IDLE		0x40	/* 0:Yes, 1:No currently Txing pkts */
#define HP100_RX_EN		0x20	/* 1: allow receiving of pkts */
#define HP100_TX_EN		0x10	/* 1: allow transmitting of pkts */
#define HP100_ACC_ERRORED	0x08	/* 0:No, 1:Yes allow Rx of errored pkts */
#define HP100_ACC_MC		0x04	/* 0:No, 1:Yes allow Rx of multicast pkts */
#define HP100_ACC_BC		0x02	/* 0:No, 1:Yes allow Rx of broadcast pkts */
#define HP100_ACC_PHY		0x01	/* 0:No, 1:Yes allow Rx of ALL phys. pkts */
#define HP100_MAC1MODEMASK	0xf0	/* Hide ACC bits */
#define HP100_MAC1MODE1		0x00	/* Receive nothing, must also disable RX */
#define HP100_MAC1MODE2		0x00
#define HP100_MAC1MODE3		HP100_MAC1MODE2 | HP100_ACC_BC
#define HP100_MAC1MODE4		HP100_MAC1MODE3 | HP100_ACC_MC
#define HP100_MAC1MODE5		HP100_MAC1MODE4	/* set mc hash to all ones also */
#define HP100_MAC1MODE6		HP100_MAC1MODE5 | HP100_ACC_PHY	/* Promiscuous */
/* Note MODE6 will receive all GOOD packets on the LAN. This really needs
   a mode 7 defined to be LAN Analyzer mode, which will receive errored and
   runt packets, and keep the CRC bytes. */
#define HP100_MAC1MODE7		HP100_MAC1MODE6 | HP100_ACC_ERRORED

/*
 *  MAC Configuration Register II
 * (Page MAC_CTRL, MAC_CFG_2, Offset 0x0d)
 */
#define HP100_TR_MODE		0x80	/* 0:No, 1:Yes support Token Ring formats */
#define HP100_TX_SAME		0x40	/* 0:No, 1:Yes Tx same packet continuous */
#define HP100_LBK_XCVR		0x20	/* 0:No, 1:Yes loopback through MAC & */
					/*   transceiver */
#define HP100_LBK_MAC		0x10	/* 0:No, 1:Yes loopback through MAC */
#define HP100_CRC_I		0x08	/* 0:No, 1:Yes inhibit CRC on Tx packets */
#define HP100_ACCNA             0x04	/* 1: For 802.5: Accept only token ring
					 * group addr that maches NA mask */
#define HP100_KEEP_CRC		0x02	/* 0:No, 1:Yes keep CRC on Rx packets. */
					/*   The length will reflect this. */
#define HP100_ACCFA             0x01	/* 1: For 802.5: Accept only functional
					 * addrs that match FA mask (page1) */
#define HP100_MAC2MODEMASK	0x02
#define HP100_MAC2MODE1		0x00
#define HP100_MAC2MODE2		0x00
#define HP100_MAC2MODE3		0x00
#define HP100_MAC2MODE4		0x00
#define HP100_MAC2MODE5		0x00
#define HP100_MAC2MODE6		0x00
#define HP100_MAC2MODE7		KEEP_CRC

/*
 * MAC Configuration Register III
 * (Page MAC_CTRL, MAC_CFG_3, Offset 0x0e)
 */
#define HP100_PACKET_PACE       0x03	/* Packet Pacing:
					 * 00: No packet pacing
					 * 01: 8 to 16 uS delay
					 * 10: 16 to 32 uS delay
					 * 11: 32 to 64 uS delay
					 */
#define HP100_LRF_EN            0x04	/* 1: External LAN Rcv Filter and
					 * TCP/IP Checksumming enabled. */
#define HP100_AUTO_MODE         0x10	/* 1: AutoSelect between 10/100 */

/*
 * MAC Configuration Register IV
 * (Page MAC_CTRL, MAC_CFG_4, Offset 0x0f)
 */
#define HP100_MAC_SEL_ST        0x01	/* (R): Status of external VGSEL
					 * Signal, 1=100VG, 0=10Mbit sel. */
#define HP100_LINK_FAIL_ST      0x02	/* (R): Status of Link Fail portion
					 * of the Misc. Interrupt */

/*
 *  100 MB LAN Training Request/Allowed Registers
 * (Page MAC_CTRL, TRAIN_REQUEST and TRAIN_ALLOW, Offset 0x14-0x16)(ETR parts only)
 */
#define HP100_MACRQ_REPEATER         0x0001	/* 1: MAC tells HUB it wants to be
						 *    a cascaded repeater
						 * 0: ... wants to be a DTE */
#define HP100_MACRQ_PROMSC           0x0006	/* 2 bits: Promiscious mode
						 * 00: Rcv only unicast packets
						 *     specifically addr to this
						 *     endnode
						 * 10: Rcv all pckts fwded by
						 *     the local repeater */
#define HP100_MACRQ_FRAMEFMT_EITHER  0x0018	/* 11: either format allowed */
#define HP100_MACRQ_FRAMEFMT_802_3   0x0000	/* 00: 802.3 is requested */
#define HP100_MACRQ_FRAMEFMT_802_5   0x0010	/* 10: 802.5 format is requested */
#define HP100_CARD_MACVER            0xe000	/* R: 3 bit Cards 100VG MAC version */
#define HP100_MALLOW_REPEATER        0x0001	/* If reset, requested access as an
						 * end node is allowed */
#define HP100_MALLOW_PROMSC          0x0004	/* 2 bits: Promiscious mode
						 * 00: Rcv only unicast packets
						 *     specifically addr to this
						 *     endnode
						 * 10: Rcv all pckts fwded by
						 *     the local repeater */
#define HP100_MALLOW_FRAMEFMT        0x00e0	/* 2 bits: Frame Format
						 * 00: 802.3 format will be used
						 * 10: 802.5 format will be used */
#define HP100_MALLOW_ACCDENIED       0x0400	/* N bit */
#define HP100_MALLOW_CONFIGURE       0x0f00	/* C bit */
#define HP100_MALLOW_DUPADDR         0x1000	/* D bit */
#define HP100_HUB_MACVER             0xe000	/* R: 3 bit 802.12 MAC/RMAC training */
					     /*    protocol of repeater */

/* ****************************************************************************** */

/*
 *  Set/Reset bits
 */
#define HP100_SET_HB		0x0100	/* 0:Set fields to 0 whose mask is 1 */
#define HP100_SET_LB		0x0001	/* HB sets upper byte, LB sets lower byte */
#define HP100_RESET_HB		0x0000	/* For readability when resetting bits */
#define HP100_RESET_LB		0x0000	/* For readability when resetting bits */

/*
 *  Misc. Constants
 */
#define HP100_LAN_100		100	/* lan_type value for VG */
#define HP100_LAN_10		10	/* lan_type value for 10BaseT */
#define HP100_LAN_COAX		9	/* lan_type value for Coax */
#define HP100_LAN_ERR		(-1)	/* lan_type value for link down */

/*
 * Bus Master Data Structures  ----------------------------------------------
 */

#define MAX_RX_PDL              30	/* Card limit = 31 */
#define MAX_RX_FRAG             2	/* Don't need more... */
#define MAX_TX_PDL              29
#define MAX_TX_FRAG             2	/* Limit = 31 */

/* Define total PDL area size in bytes (should be 4096) */
/* This is the size of kernel (dma) memory that will be allocated. */
#define MAX_RINGSIZE ((MAX_RX_FRAG*8+4+4)*MAX_RX_PDL+(MAX_TX_FRAG*8+4+4)*MAX_TX_PDL)+16

/* Ethernet Packet Sizes */
#define MIN_ETHER_SIZE          60
#define MAX_ETHER_SIZE          1514	/* Needed for preallocation of */
					/* skb buffer when busmastering */

/* Tx or Rx Ring Entry */
typedef struct hp100_ring {
	u_int *pdl;		/* Address of PDLs PDH, dword before
				 * this address is used for rx hdr */
	u_int pdl_paddr;	/* Physical address of PDL */
	struct sk_buff *skb;
	struct hp100_ring *next;
} hp100_ring_t;



/* Mask for Header Descriptor */
#define HP100_PKT_LEN_MASK	0x1FFF	/* AND with RxLength to get length */


/* Receive Packet Status.  Note, the error bits are only valid if ACC_ERRORED
   bit in the MAC Configuration Register 1 is set. */
#define HP100_RX_PRI		0x8000	/* 0:No, 1:Yes packet is priority */
#define HP100_SDF_ERR		0x4000	/* 0:No, 1:Yes start of frame error */
#define HP100_SKEW_ERR		0x2000	/* 0:No, 1:Yes skew out of range */
#define HP100_BAD_SYMBOL_ERR	0x1000	/* 0:No, 1:Yes invalid symbol received */
#define HP100_RCV_IPM_ERR	0x0800	/* 0:No, 1:Yes pkt had an invalid packet */
					/*   marker */
#define HP100_SYMBOL_BAL_ERR	0x0400	/* 0:No, 1:Yes symbol balance error */
#define HP100_VG_ALN_ERR	0x0200	/* 0:No, 1:Yes non-octet received */
#define HP100_TRUNC_ERR		0x0100	/* 0:No, 1:Yes the packet was truncated */
#define HP100_RUNT_ERR		0x0040	/* 0:No, 1:Yes pkt length < Min Pkt */
					/*   Length Reg. */
#define HP100_ALN_ERR		0x0010	/* 0:No, 1:Yes align error. */
#define HP100_CRC_ERR		0x0008	/* 0:No, 1:Yes CRC occurred. */

/* The last three bits indicate the type of destination address */

#define HP100_MULTI_ADDR_HASH	0x0006	/* 110: Addr multicast, matched hash */
#define HP100_BROADCAST_ADDR	0x0003	/* x11: Addr broadcast */
#define HP100_MULTI_ADDR_NO_HASH 0x0002	/* 010: Addr multicast, didn't match hash */
#define HP100_PHYS_ADDR_MATCH	0x0001	/* x01: Addr was physical and mine */
#define HP100_PHYS_ADDR_NO_MATCH 0x0000	/* x00: Addr was physical but not mine */

/*
 *  macros
 */

#define hp100_inb( reg ) \
        inb( ioaddr + HP100_REG_##reg )
#define hp100_inw( reg ) \
	inw( ioaddr + HP100_REG_##reg )
#define hp100_inl( reg ) \
	inl( ioaddr + HP100_REG_##reg )
#define hp100_outb( data, reg ) \
	outb( data, ioaddr + HP100_REG_##reg )
#define hp100_outw( data, reg ) \
	outw( data, ioaddr + HP100_REG_##reg )
#define hp100_outl( data, reg ) \
	outl( data, ioaddr + HP100_REG_##reg )
#define hp100_orb( data, reg ) \
	outb( inb( ioaddr + HP100_REG_##reg ) | (data), ioaddr + HP100_REG_##reg )
#define hp100_orw( data, reg ) \
	outw( inw( ioaddr + HP100_REG_##reg ) | (data), ioaddr + HP100_REG_##reg )
#define hp100_andb( data, reg ) \
	outb( inb( ioaddr + HP100_REG_##reg ) & (data), ioaddr + HP100_REG_##reg )
#define hp100_andw( data, reg ) \
	outw( inw( ioaddr + HP100_REG_##reg ) & (data), ioaddr + HP100_REG_##reg )

#define hp100_page( page ) \
	outw( HP100_PAGE_##page, ioaddr + HP100_REG_PAGING )
#define hp100_ints_off() \
	outw( HP100_INT_EN | HP100_RESET_LB, ioaddr + HP100_REG_OPTION_LSW )
#define hp100_ints_on() \
	outw( HP100_INT_EN | HP100_SET_LB, ioaddr + HP100_REG_OPTION_LSW )
#define hp100_mem_map_enable() \
	outw( HP100_MMAP_DIS | HP100_RESET_HB, ioaddr + HP100_REG_OPTION_LSW )
#define hp100_mem_map_disable() \
	outw( HP100_MMAP_DIS | HP100_SET_HB, ioaddr + HP100_REG_OPTION_LSW )
v); static void mc32_set_multicast_list(struct net_device *dev); static void mc32_reset_multicast_list(struct net_device *dev); static const struct ethtool_ops netdev_ethtool_ops; static void cleanup_card(struct net_device *dev) { struct mc32_local *lp = netdev_priv(dev); unsigned slot = lp->slot; mca_mark_as_unused(slot); mca_set_adapter_name(slot, NULL); free_irq(dev->irq, dev); release_region(dev->base_addr, MC32_IO_EXTENT); } /** * mc32_probe - Search for supported boards * @unit: interface number to use * * Because MCA bus is a real bus and we can scan for cards we could do a * single scan for all boards here. Right now we use the passed in device * structure and scan for only one board. This needs fixing for modules * in particular. */ struct net_device *__init mc32_probe(int unit) { struct net_device *dev = alloc_etherdev(sizeof(struct mc32_local)); static int current_mca_slot = -1; int i; int err; if (!dev) return ERR_PTR(-ENOMEM); if (unit >= 0) sprintf(dev->name, "eth%d", unit); SET_MODULE_OWNER(dev); /* Do not check any supplied i/o locations. POS registers usually don't fail :) */ /* MCA cards have POS registers. Autodetecting MCA cards is extremely simple. Just search for the card. */ for(i = 0; (mc32_adapters[i].name != NULL); i++) { current_mca_slot = mca_find_unused_adapter(mc32_adapters[i].id, 0); if(current_mca_slot != MCA_NOTFOUND) { if(!mc32_probe1(dev, current_mca_slot)) { mca_set_adapter_name(current_mca_slot, mc32_adapters[i].name); mca_mark_as_used(current_mca_slot); err = register_netdev(dev); if (err) { cleanup_card(dev); free_netdev(dev); dev = ERR_PTR(err); } return dev; } } } free_netdev(dev); return ERR_PTR(-ENODEV); } /** * mc32_probe1 - Check a given slot for a board and test the card * @dev: Device structure to fill in * @slot: The MCA bus slot being used by this card * * Decode the slot data and configure the card structures. Having done this we * can reset the card and configure it. The card does a full self test cycle * in firmware so we have to wait for it to return and post us either a * failure case or some addresses we use to find the board internals. */ static int __init mc32_probe1(struct net_device *dev, int slot) { static unsigned version_printed; int i, err; u8 POS; u32 base; struct mc32_local *lp = netdev_priv(dev); static u16 mca_io_bases[]={ 0x7280,0x7290, 0x7680,0x7690, 0x7A80,0x7A90, 0x7E80,0x7E90 }; static u32 mca_mem_bases[]={ 0x00C0000, 0x00C4000, 0x00C8000, 0x00CC000, 0x00D0000, 0x00D4000, 0x00D8000, 0x00DC000 }; static char *failures[]={ "Processor instruction", "Processor data bus", "Processor data bus", "Processor data bus", "Adapter bus", "ROM checksum", "Base RAM", "Extended RAM", "82586 internal loopback", "82586 initialisation failure", "Adapter list configuration error" }; /* Time to play MCA games */ if (mc32_debug && version_printed++ == 0) printk(KERN_DEBUG "%s", version); printk(KERN_INFO "%s: %s found in slot %d:", dev->name, cardname, slot); POS = mca_read_stored_pos(slot, 2); if(!(POS&1)) { printk(" disabled.\n"); return -ENODEV; } /* Fill in the 'dev' fields. */ dev->base_addr = mca_io_bases[(POS>>1)&7]; dev->mem_start = mca_mem_bases[(POS>>4)&7]; POS = mca_read_stored_pos(slot, 4); if(!(POS&1)) { printk("memory window disabled.\n"); return -ENODEV; } POS = mca_read_stored_pos(slot, 5); i=(POS>>4)&3; if(i==3) { printk("invalid memory window.\n"); return -ENODEV; } i*=16384; i+=16384; dev->mem_end=dev->mem_start + i; dev->irq = ((POS>>2)&3)+9; if(!request_region(dev->base_addr, MC32_IO_EXTENT, cardname)) { printk("io 0x%3lX, which is busy.\n", dev->base_addr); return -EBUSY; } printk("io 0x%3lX irq %d mem 0x%lX (%dK)\n", dev->base_addr, dev->irq, dev->mem_start, i/1024); /* We ought to set the cache line size here.. */ /* * Go PROM browsing */ printk("%s: Address ", dev->name); /* Retrieve and print the ethernet address. */ for (i = 0; i < 6; i++) { mca_write_pos(slot, 6, i+12); mca_write_pos(slot, 7, 0); printk(" %2.2x", dev->dev_addr[i] = mca_read_pos(slot,3)); } mca_write_pos(slot, 6, 0); mca_write_pos(slot, 7, 0); POS = mca_read_stored_pos(slot, 4); if(POS&2) printk(" : BNC port selected.\n"); else printk(" : AUI port selected.\n"); POS=inb(dev->base_addr+HOST_CTRL); POS|=HOST_CTRL_ATTN|HOST_CTRL_RESET; POS&=~HOST_CTRL_INTE; outb(POS, dev->base_addr+HOST_CTRL); /* Reset adapter */ udelay(100); /* Reset off */ POS&=~(HOST_CTRL_ATTN|HOST_CTRL_RESET); outb(POS, dev->base_addr+HOST_CTRL); udelay(300); /* * Grab the IRQ */ err = request_irq(dev->irq, &mc32_interrupt, IRQF_SHARED | IRQF_SAMPLE_RANDOM, DRV_NAME, dev); if (err) { release_region(dev->base_addr, MC32_IO_EXTENT); printk(KERN_ERR "%s: unable to get IRQ %d.\n", DRV_NAME, dev->irq); goto err_exit_ports; } memset(lp, 0, sizeof(struct mc32_local)); lp->slot = slot; i=0; base = inb(dev->base_addr); while(base == 0xFF) { i++; if(i == 1000) { printk(KERN_ERR "%s: failed to boot adapter.\n", dev->name); err = -ENODEV; goto err_exit_irq; } udelay(1000); if(inb(dev->base_addr+2)&(1<<5)) base = inb(dev->base_addr); } if(base>0) { if(base < 0x0C) printk(KERN_ERR "%s: %s%s.\n", dev->name, failures[base-1], base<0x0A?" test failure":""); else printk(KERN_ERR "%s: unknown failure %d.\n", dev->name, base); err = -ENODEV; goto err_exit_irq; } base=0; for(i=0;i<4;i++) { int n=0; while(!(inb(dev->base_addr+2)&(1<<5))) { n++; udelay(50); if(n>100) { printk(KERN_ERR "%s: mailbox read fail (%d).\n", dev->name, i); err = -ENODEV; goto err_exit_irq; } } base|=(inb(dev->base_addr)<<(8*i)); } lp->exec_box=isa_bus_to_virt(dev->mem_start+base); base=lp->exec_box->data[1]<<16|lp->exec_box->data[0]; lp->base = dev->mem_start+base; lp->rx_box=isa_bus_to_virt(lp->base + lp->exec_box->data[2]); lp->tx_box=isa_bus_to_virt(lp->base + lp->exec_box->data[3]); lp->stats = isa_bus_to_virt(lp->base + lp->exec_box->data[5]); /* * Descriptor chains (card relative) */ lp->tx_chain = lp->exec_box->data[8]; /* Transmit list start offset */ lp->rx_chain = lp->exec_box->data[10]; /* Receive list start offset */ lp->tx_len = lp->exec_box->data[9]; /* Transmit list count */ lp->rx_len = lp->exec_box->data[11]; /* Receive list count */ init_MUTEX_LOCKED(&lp->cmd_mutex); init_completion(&lp->execution_cmd); init_completion(&lp->xceiver_cmd); printk("%s: Firmware Rev %d. %d RX buffers, %d TX buffers. Base of 0x%08X.\n", dev->name, lp->exec_box->data[12], lp->rx_len, lp->tx_len, lp->base); dev->open = mc32_open; dev->stop = mc32_close; dev->hard_start_xmit = mc32_send_packet; dev->get_stats = mc32_get_stats; dev->set_multicast_list = mc32_set_multicast_list; dev->tx_timeout = mc32_timeout; dev->watchdog_timeo = HZ*5; /* Board does all the work */ dev->ethtool_ops = &netdev_ethtool_ops; return 0; err_exit_irq: free_irq(dev->irq, dev); err_exit_ports: release_region(dev->base_addr, MC32_IO_EXTENT); return err; } /** * mc32_ready_poll - wait until we can feed it a command * @dev: The device to wait for * * Wait until the card becomes ready to accept a command via the * command register. This tells us nothing about the completion * status of any pending commands and takes very little time at all. */ static inline void mc32_ready_poll(struct net_device *dev) { int ioaddr = dev->base_addr; while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); } /** * mc32_command_nowait - send a command non blocking * @dev: The 3c527 to issue the command to * @cmd: The command word to write to the mailbox * @data: A data block if the command expects one * @len: Length of the data block * * Send a command from interrupt state. If there is a command * currently being executed then we return an error of -1. It * simply isn't viable to wait around as commands may be * slow. This can theoretically be starved on SMP, but it's hard * to see a realistic situation. We do not wait for the command * to complete --- we rely on the interrupt handler to tidy up * after us. */ static int mc32_command_nowait(struct net_device *dev, u16 cmd, void *data, int len) { struct mc32_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; int ret = -1; if (down_trylock(&lp->cmd_mutex) == 0) { lp->cmd_nonblocking=1; lp->exec_box->mbox=0; lp->exec_box->mbox=cmd; memcpy((void *)lp->exec_box->data, data, len); barrier(); /* the memcpy forgot the volatile so be sure */ /* Send the command */ mc32_ready_poll(dev); outb(1<<6, ioaddr+HOST_CMD); ret = 0; /* Interrupt handler will signal mutex on completion */ } return ret; } /** * mc32_command - send a command and sleep until completion * @dev: The 3c527 card to issue the command to * @cmd: The command word to write to the mailbox * @data: A data block if the command expects one * @len: Length of the data block * * Sends exec commands in a user context. This permits us to wait around * for the replies and also to wait for the command buffer to complete * from a previous command before we execute our command. After our * command completes we will attempt any pending multicast reload * we blocked off by hogging the exec buffer. * * You feed the card a command, you wait, it interrupts you get a * reply. All well and good. The complication arises because you use * commands for filter list changes which come in at bh level from things * like IPV6 group stuff. */ static int mc32_command(struct net_device *dev, u16 cmd, void *data, int len) { struct mc32_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; int ret = 0; down(&lp->cmd_mutex); /* * My Turn */ lp->cmd_nonblocking=0; lp->exec_box->mbox=0; lp->exec_box->mbox=cmd; memcpy((void *)lp->exec_box->data, data, len); barrier(); /* the memcpy forgot the volatile so be sure */ mc32_ready_poll(dev); outb(1<<6, ioaddr+HOST_CMD); wait_for_completion(&lp->execution_cmd); if(lp->exec_box->mbox&(1<<13)) ret = -1; up(&lp->cmd_mutex); /* * A multicast set got blocked - try it now */ if(lp->mc_reload_wait) { mc32_reset_multicast_list(dev); } return ret; } /** * mc32_start_transceiver - tell board to restart tx/rx * @dev: The 3c527 card to issue the command to * * This may be called from the interrupt state, where it is used * to restart the rx ring if the card runs out of rx buffers. * * We must first check if it's ok to (re)start the transceiver. See * mc32_close for details. */ static void mc32_start_transceiver(struct net_device *dev) { struct mc32_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; /* Ignore RX overflow on device closure */ if (lp->xceiver_desired_state==HALTED) return; /* Give the card the offset to the post-EOL-bit RX descriptor */ mc32_ready_poll(dev); lp->rx_box->mbox=0; lp->rx_box->data[0]=lp->rx_ring[prev_rx(lp->rx_ring_tail)].p->next; outb(HOST_CMD_START_RX, ioaddr+HOST_CMD); mc32_ready_poll(dev); lp->tx_box->mbox=0; outb(HOST_CMD_RESTRT_TX, ioaddr+HOST_CMD); /* card ignores this on RX restart */ /* We are not interrupted on start completion */ } /** * mc32_halt_transceiver - tell board to stop tx/rx * @dev: The 3c527 card to issue the command to * * We issue the commands to halt the card's transceiver. In fact, * after some experimenting we now simply tell the card to * suspend. When issuing aborts occasionally odd things happened. * * We then sleep until the card has notified us that both rx and * tx have been suspended. */ static void mc32_halt_transceiver(struct net_device *dev) { struct mc32_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; mc32_ready_poll(dev); lp->rx_box->mbox=0; outb(HOST_CMD_SUSPND_RX, ioaddr+HOST_CMD); wait_for_completion(&lp->xceiver_cmd); mc32_ready_poll(dev); lp->tx_box->mbox=0; outb(HOST_CMD_SUSPND_TX, ioaddr+HOST_CMD); wait_for_completion(&lp->xceiver_cmd); } /** * mc32_load_rx_ring - load the ring of receive buffers * @dev: 3c527 to build the ring for * * This initalises the on-card and driver datastructures to * the point where mc32_start_transceiver() can be called. * * The card sets up the receive ring for us. We are required to use the * ring it provides, although the size of the ring is configurable. * * We allocate an sk_buff for each ring entry in turn and * initalise its house-keeping info. At the same time, we read * each 'next' pointer in our rx_ring array. This reduces slow * shared-memory reads and makes it easy to access predecessor * descriptors. * * We then set the end-of-list bit for the last entry so that the * card will know when it has run out of buffers. */ static int mc32_load_rx_ring(struct net_device *dev) { struct mc32_local *lp = netdev_priv(dev); int i; u16 rx_base; volatile struct skb_header *p; rx_base=lp->rx_chain; for(i=0; i<RX_RING_LEN; i++) { lp->rx_ring[i].skb=alloc_skb(1532, GFP_KERNEL); if (lp->rx_ring[i].skb==NULL) { for (;i>=0;i--) kfree_skb(lp->rx_ring[i].skb); return -ENOBUFS; } skb_reserve(lp->rx_ring[i].skb, 18); p=isa_bus_to_virt(lp->base+rx_base); p->control=0; p->data=isa_virt_to_bus(lp->rx_ring[i].skb->data); p->status=0; p->length=1532; lp->rx_ring[i].p=p; rx_base=p->next; } lp->rx_ring[i-1].p->control |= CONTROL_EOL; lp->rx_ring_tail=0; return 0; } /** * mc32_flush_rx_ring - free the ring of receive buffers * @lp: Local data of 3c527 to flush the rx ring of * * Free the buffer for each ring slot. This may be called * before mc32_load_rx_ring(), eg. on error in mc32_open(). * Requires rx skb pointers to point to a valid skb, or NULL. */ static void mc32_flush_rx_ring(struct net_device *dev) { struct mc32_local *lp = netdev_priv(dev); int i; for(i=0; i < RX_RING_LEN; i++) { if (lp->rx_ring[i].skb) { dev_kfree_skb(lp->rx_ring[i].skb); lp->rx_ring[i].skb = NULL; } lp->rx_ring[i].p=NULL; } } /** * mc32_load_tx_ring - load transmit ring * @dev: The 3c527 card to issue the command to * * This sets up the host transmit data-structures. * * First, we obtain from the card it's current postion in the tx * ring, so that we will know where to begin transmitting * packets. * * Then, we read the 'next' pointers from the on-card tx ring into * our tx_ring array to reduce slow shared-mem reads. Finally, we * intitalise the tx house keeping variables. * */ static void mc32_load_tx_ring(struct net_device *dev) { struct mc32_local *lp = netdev_priv(dev); volatile struct skb_header *p; int i; u16 tx_base; tx_base=lp->tx_box->data[0]; for(i=0 ; i<TX_RING_LEN ; i++) { p=isa_bus_to_virt(lp->base+tx_base); lp->tx_ring[i].p=p; lp->tx_ring[i].skb=NULL; tx_base=p->next; } /* -1 so that tx_ring_head cannot "lap" tx_ring_tail */ /* see mc32_tx_ring */ atomic_set(&lp->tx_count, TX_RING_LEN-1); atomic_set(&lp->tx_ring_head, 0); lp->tx_ring_tail=0; } /** * mc32_flush_tx_ring - free transmit ring * @lp: Local data of 3c527 to flush the tx ring of * * If the ring is non-empty, zip over the it, freeing any * allocated skb_buffs. The tx ring house-keeping variables are * then reset. Requires rx skb pointers to point to a valid skb, * or NULL. */ static void mc32_flush_tx_ring(struct net_device *dev) { struct mc32_local *lp = netdev_priv(dev); int i; for (i=0; i < TX_RING_LEN; i++) { if (lp->tx_ring[i].skb) { dev_kfree_skb(lp->tx_ring[i].skb); lp->tx_ring[i].skb = NULL; } } atomic_set(&lp->tx_count, 0); atomic_set(&lp->tx_ring_head, 0); lp->tx_ring_tail=0; } /** * mc32_open - handle 'up' of card * @dev: device to open * * The user is trying to bring the card into ready state. This requires * a brief dialogue with the card. Firstly we enable interrupts and then * 'indications'. Without these enabled the card doesn't bother telling * us what it has done. This had me puzzled for a week. * * We configure the number of card descriptors, then load the network * address and multicast filters. Turn on the workaround mode. This * works around a bug in the 82586 - it asks the firmware to do * so. It has a performance (latency) hit but is needed on busy * [read most] lans. We load the ring with buffers then we kick it * all off. */ static int mc32_open(struct net_device *dev) { int ioaddr = dev->base_addr; struct mc32_local *lp = netdev_priv(dev); u8 one=1; u8 regs; u16 descnumbuffs[2] = {TX_RING_LEN, RX_RING_LEN}; /* * Interrupts enabled */ regs=inb(ioaddr+HOST_CTRL); regs|=HOST_CTRL_INTE; outb(regs, ioaddr+HOST_CTRL); /* * Allow ourselves to issue commands */ up(&lp->cmd_mutex); /* * Send the indications on command */ mc32_command(dev, 4, &one, 2); /* * Poke it to make sure it's really dead. */ mc32_halt_transceiver(dev); mc32_flush_tx_ring(dev); /* * Ask card to set up on-card descriptors to our spec */ if(mc32_command(dev, 8, descnumbuffs, 4)) { printk("%s: %s rejected our buffer configuration!\n", dev->name, cardname); mc32_close(dev); return -ENOBUFS; } /* Report new configuration */ mc32_command(dev, 6, NULL, 0); lp->tx_chain = lp->exec_box->data[8]; /* Transmit list start offset */ lp->rx_chain = lp->exec_box->data[10]; /* Receive list start offset */ lp->tx_len = lp->exec_box->data[9]; /* Transmit list count */ lp->rx_len = lp->exec_box->data[11]; /* Receive list count */ /* Set Network Address */ mc32_command(dev, 1, dev->dev_addr, 6); /* Set the filters */ mc32_set_multicast_list(dev); if (WORKAROUND_82586) { u16 zero_word=0; mc32_command(dev, 0x0D, &zero_word, 2); /* 82586 bug workaround on */ } mc32_load_tx_ring(dev); if(mc32_load_rx_ring(dev)) { mc32_close(dev); return -ENOBUFS; } lp->xceiver_desired_state = RUNNING; /* And finally, set the ball rolling... */ mc32_start_transceiver(dev); netif_start_queue(dev); return 0; } /** * mc32_timeout - handle a timeout from the network layer * @dev: 3c527 that timed out * * Handle a timeout on transmit from the 3c527. This normally means * bad things as the hardware handles cable timeouts and mess for * us. * */ static void mc32_timeout(struct net_device *dev) { printk(KERN_WARNING "%s: transmit timed out?\n", dev->name); /* Try to restart the adaptor. */ netif_wake_queue(dev); } /** * mc32_send_packet - queue a frame for transmit * @skb: buffer to transmit * @dev: 3c527 to send it out of * * Transmit a buffer. This normally means throwing the buffer onto * the transmit queue as the queue is quite large. If the queue is * full then we set tx_busy and return. Once the interrupt handler * gets messages telling it to reclaim transmit queue entries, we will * clear tx_busy and the kernel will start calling this again. * * We do not disable interrupts or acquire any locks; this can * run concurrently with mc32_tx_ring(), and the function itself * is serialised at a higher layer. However, similarly for the * card itself, we must ensure that we update tx_ring_head only * after we've established a valid packet on the tx ring (and * before we let the card "see" it, to prevent it racing with the * irq handler). * */ static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev) { struct mc32_local *lp = netdev_priv(dev); u32 head = atomic_read(&lp->tx_ring_head); volatile struct skb_header *p, *np; netif_stop_queue(dev); if(atomic_read(&lp->tx_count)==0) { return 1; } if (skb_padto(skb, ETH_ZLEN)) { netif_wake_queue(dev); return 0; } atomic_dec(&lp->tx_count); /* P is the last sending/sent buffer as a pointer */ p=lp->tx_ring[head].p; head = next_tx(head); /* NP is the buffer we will be loading */ np=lp->tx_ring[head].p; /* We will need this to flush the buffer out */ lp->tx_ring[head].skb=skb; np->length = unlikely(skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len; np->data = isa_virt_to_bus(skb->data); np->status = 0; np->control = CONTROL_EOP | CONTROL_EOL; wmb(); /* * The new frame has been setup; we can now * let the interrupt handler and card "see" it */ atomic_set(&lp->tx_ring_head, head); p->control &= ~CONTROL_EOL; netif_wake_queue(dev); return 0; } /** * mc32_update_stats - pull off the on board statistics * @dev: 3c527 to service * * * Query and reset the on-card stats. There's the small possibility * of a race here, which would result in an underestimation of * actual errors. As such, we'd prefer to keep all our stats * collection in software. As a rule, we do. However it can't be * used for rx errors and collisions as, by default, the card discards * bad rx packets. * * Setting the SAV BP in the rx filter command supposedly * stops this behaviour. However, testing shows that it only seems to * enable the collation of on-card rx statistics --- the driver * never sees an RX descriptor with an error status set. * */ static void mc32_update_stats(struct net_device *dev) { struct mc32_local *lp = netdev_priv(dev); volatile struct mc32_stats *st = lp->stats; u32 rx_errors=0; rx_errors+=lp->net_stats.rx_crc_errors +=st->rx_crc_errors; st->rx_crc_errors=0; rx_errors+=lp->net_stats.rx_fifo_errors +=st->rx_overrun_errors; st->rx_overrun_errors=0; rx_errors+=lp->net_stats.rx_frame_errors +=st->rx_alignment_errors; st->rx_alignment_errors=0; rx_errors+=lp->net_stats.rx_length_errors+=st->rx_tooshort_errors; st->rx_tooshort_errors=0; rx_errors+=lp->net_stats.rx_missed_errors+=st->rx_outofresource_errors; st->rx_outofresource_errors=0; lp->net_stats.rx_errors=rx_errors; /* Number of packets which saw one collision */ lp->net_stats.collisions+=st->dataC[10]; st->dataC[10]=0; /* Number of packets which saw 2--15 collisions */ lp->net_stats.collisions+=st->dataC[11]; st->dataC[11]=0; } /** * mc32_rx_ring - process the receive ring * @dev: 3c527 that needs its receive ring processing * * * We have received one or more indications from the card that a * receive has completed. The buffer ring thus contains dirty * entries. We walk the ring by iterating over the circular rx_ring * array, starting at the next dirty buffer (which happens to be the * one we finished up at last time around). * * For each completed packet, we will either copy it and pass it up * the stack or, if the packet is near MTU sized, we allocate * another buffer and flip the old one up the stack. * * We must succeed in keeping a buffer on the ring. If necessary we * will toss a received packet rather than lose a ring entry. Once * the first uncompleted descriptor is found, we move the * End-Of-List bit to include the buffers just processed. * */ static void mc32_rx_ring(struct net_device *dev) { struct mc32_local *lp = netdev_priv(dev); volatile struct skb_header *p; u16 rx_ring_tail; u16 rx_old_tail; int x=0; rx_old_tail = rx_ring_tail = lp->rx_ring_tail; do { p=lp->rx_ring[rx_ring_tail].p; if(!(p->status & (1<<7))) { /* Not COMPLETED */ break; } if(p->status & (1<<6)) /* COMPLETED_OK */ { u16 length=p->length; struct sk_buff *skb; struct sk_buff *newskb; /* Try to save time by avoiding a copy on big frames */ if ((length > RX_COPYBREAK) && ((newskb=dev_alloc_skb(1532)) != NULL)) { skb=lp->rx_ring[rx_ring_tail].skb; skb_put(skb, length); skb_reserve(newskb,18); lp->rx_ring[rx_ring_tail].skb=newskb; p->data=isa_virt_to_bus(newskb->data); } else { skb=dev_alloc_skb(length+2); if(skb==NULL) { lp->net_stats.rx_dropped++; goto dropped; } skb_reserve(skb,2); memcpy(skb_put(skb, length), lp->rx_ring[rx_ring_tail].skb->data, length); } skb->protocol=eth_type_trans(skb,dev); skb->dev=dev; dev->last_rx = jiffies; lp->net_stats.rx_packets++; lp->net_stats.rx_bytes += length; netif_rx(skb); } dropped: p->length = 1532; p->status = 0; rx_ring_tail=next_rx(rx_ring_tail); } while(x++<48); /* If there was actually a frame to be processed, place the EOL bit */ /* at the descriptor prior to the one to be filled next */ if (rx_ring_tail != rx_old_tail) { lp->rx_ring[prev_rx(rx_ring_tail)].p->control |= CONTROL_EOL; lp->rx_ring[prev_rx(rx_old_tail)].p->control &= ~CONTROL_EOL; lp->rx_ring_tail=rx_ring_tail; } } /** * mc32_tx_ring - process completed transmits * @dev: 3c527 that needs its transmit ring processing * * * This operates in a similar fashion to mc32_rx_ring. We iterate * over the transmit ring. For each descriptor which has been * processed by the card, we free its associated buffer and note * any errors. This continues until the transmit ring is emptied * or we reach a descriptor that hasn't yet been processed by the * card. * */ static void mc32_tx_ring(struct net_device *dev) { struct mc32_local *lp = netdev_priv(dev); volatile struct skb_header *np; /* * We rely on head==tail to mean 'queue empty'. * This is why lp->tx_count=TX_RING_LEN-1: in order to prevent * tx_ring_head wrapping to tail and confusing a 'queue empty' * condition with 'queue full' */ while (lp->tx_ring_tail != atomic_read(&lp->tx_ring_head)) { u16 t; t=next_tx(lp->tx_ring_tail); np=lp->tx_ring[t].p; if(!(np->status & (1<<7))) { /* Not COMPLETED */ break; } lp->net_stats.tx_packets++; if(!(np->status & (1<<6))) /* Not COMPLETED_OK */ { lp->net_stats.tx_errors++; switch(np->status&0x0F) { case 1: lp->net_stats.tx_aborted_errors++; break; /* Max collisions */ case 2: lp->net_stats.tx_fifo_errors++; break; case 3: lp->net_stats.tx_carrier_errors++; break; case 4: lp->net_stats.tx_window_errors++; break; /* CTS Lost */ case 5: lp->net_stats.tx_aborted_errors++; break; /* Transmit timeout */ } } /* Packets are sent in order - this is basically a FIFO queue of buffers matching the card ring */ lp->net_stats.tx_bytes+=lp->tx_ring[t].skb->len; dev_kfree_skb_irq(lp->tx_ring[t].skb); lp->tx_ring[t].skb=NULL; atomic_inc(&lp->tx_count); netif_wake_queue(dev); lp->tx_ring_tail=t; } } /** * mc32_interrupt - handle an interrupt from a 3c527 * @irq: Interrupt number * @dev_id: 3c527 that requires servicing * @regs: Registers (unused) * * * An interrupt is raised whenever the 3c527 writes to the command * register. This register contains the message it wishes to send us * packed into a single byte field. We keep reading status entries * until we have processed all the control items, but simply count * transmit and receive reports. When all reports are in we empty the * transceiver rings as appropriate. This saves the overhead of * multiple command requests. * * Because MCA is level-triggered, we shouldn't miss indications. * Therefore, we needn't ask the card to suspend interrupts within * this handler. The card receives an implicit acknowledgment of the * current interrupt when we read the command register. * */ static irqreturn_t mc32_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct mc32_local *lp; int ioaddr, status, boguscount = 0; int rx_event = 0; int tx_event = 0; ioaddr = dev->base_addr; lp = netdev_priv(dev); /* See whats cooking */ while((inb(ioaddr+HOST_STATUS)&HOST_STATUS_CWR) && boguscount++<2000) { status=inb(ioaddr+HOST_CMD); #ifdef DEBUG_IRQ printk("Status TX%d RX%d EX%d OV%d BC%d\n", (status&7), (status>>3)&7, (status>>6)&1, (status>>7)&1, boguscount); #endif switch(status&7) { case 0: break; case 6: /* TX fail */ case 2: /* TX ok */ tx_event = 1; break; case 3: /* Halt */ case 4: /* Abort */ complete(&lp->xceiver_cmd); break; default: printk("%s: strange tx ack %d\n", dev->name, status&7); } status>>=3; switch(status&7) { case 0: break; case 2: /* RX */ rx_event=1; break; case 3: /* Halt */ case 4: /* Abort */ complete(&lp->xceiver_cmd); break; case 6: /* Out of RX buffers stat */ /* Must restart rx */ lp->net_stats.rx_dropped++; mc32_rx_ring(dev); mc32_start_transceiver(dev); break; default: printk("%s: strange rx ack %d\n", dev->name, status&7); } status>>=3; if(status&1) { /* * No thread is waiting: we need to tidy * up ourself. */ if (lp->cmd_nonblocking) { up(&lp->cmd_mutex); if (lp->mc_reload_wait) mc32_reset_multicast_list(dev); } else complete(&lp->execution_cmd); } if(status&2) { /* * We get interrupted once per * counter that is about to overflow. */ mc32_update_stats(dev); } } /* * Process the transmit and receive rings */ if(tx_event) mc32_tx_ring(dev); if(rx_event) mc32_rx_ring(dev); return IRQ_HANDLED; } /** * mc32_close - user configuring the 3c527 down * @dev: 3c527 card to shut down * * The 3c527 is a bus mastering device. We must be careful how we * shut it down. It may also be running shared interrupt so we have * to be sure to silence it properly * * We indicate that the card is closing to the rest of the * driver. Otherwise, it is possible that the card may run out * of receive buffers and restart the transceiver while we're * trying to close it. * * We abort any receive and transmits going on and then wait until * any pending exec commands have completed in other code threads. * In theory we can't get here while that is true, in practice I am * paranoid * * We turn off the interrupt enable for the board to be sure it can't * intefere with other devices. */ static int mc32_close(struct net_device *dev) { struct mc32_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; u8 regs; u16 one=1; lp->xceiver_desired_state = HALTED; netif_stop_queue(dev); /* * Send the indications on command (handy debug check) */ mc32_command(dev, 4, &one, 2); /* Shut down the transceiver */ mc32_halt_transceiver(dev); /* Ensure we issue no more commands beyond this point */ down(&lp->cmd_mutex); /* Ok the card is now stopping */ regs=inb(ioaddr+HOST_CTRL); regs&=~HOST_CTRL_INTE; outb(regs, ioaddr+HOST_CTRL); mc32_flush_rx_ring(dev); mc32_flush_tx_ring(dev); mc32_update_stats(dev); return 0; } /** * mc32_get_stats - hand back stats to network layer * @dev: The 3c527 card to handle * * We've collected all the stats we can in software already. Now * it's time to update those kept on-card and return the lot. * */ static struct net_device_stats *mc32_get_stats(struct net_device *dev) { struct mc32_local *lp = netdev_priv(dev); mc32_update_stats(dev); return &lp->net_stats; } /** * do_mc32_set_multicast_list - attempt to update multicasts * @dev: 3c527 device to load the list on * @retry: indicates this is not the first call. * * * Actually set or clear the multicast filter for this adaptor. The * locking issues are handled by this routine. We have to track * state as it may take multiple calls to get the command sequence * completed. We just keep trying to schedule the loads until we * manage to process them all. * * num_addrs == -1 Promiscuous mode, receive all packets * * num_addrs == 0 Normal mode, clear multicast list * * num_addrs > 0 Multicast mode, receive normal and MC packets, * and do best-effort filtering. * * See mc32_update_stats() regards setting the SAV BP bit. * */ static void do_mc32_set_multicast_list(struct net_device *dev, int retry) { struct mc32_local *lp = netdev_priv(dev); u16 filt = (1<<2); /* Save Bad Packets, for stats purposes */ if (dev->flags&IFF_PROMISC) /* Enable promiscuous mode */ filt |= 1; else if((dev->flags&IFF_ALLMULTI) || dev->mc_count > 10) { dev->flags|=IFF_PROMISC; filt |= 1; } else if(dev->mc_count) { unsigned char block[62]; unsigned char *bp; struct dev_mc_list *dmc=dev->mc_list; int i; if(retry==0) lp->mc_list_valid = 0; if(!lp->mc_list_valid) { block[1]=0; block[0]=dev->mc_count; bp=block+2; for(i=0;i<dev->mc_count;i++) { memcpy(bp, dmc->dmi_addr, 6); bp+=6; dmc=dmc->next; } if(mc32_command_nowait(dev, 2, block, 2+6*dev->mc_count)==-1) { lp->mc_reload_wait = 1; return; } lp->mc_list_valid=1; } } if(mc32_command_nowait(dev, 0, &filt, 2)==-1) { lp->mc_reload_wait = 1; } else { lp->mc_reload_wait = 0; } } /** * mc32_set_multicast_list - queue multicast list update * @dev: The 3c527 to use * * Commence loading the multicast list. This is called when the kernel * changes the lists. It will override any pending list we are trying to * load. */ static void mc32_set_multicast_list(struct net_device *dev) { do_mc32_set_multicast_list(dev,0); } /** * mc32_reset_multicast_list - reset multicast list * @dev: The 3c527 to use * * Attempt the next step in loading the multicast lists. If this attempt * fails to complete then it will be scheduled and this function called * again later from elsewhere. */ static void mc32_reset_multicast_list(struct net_device *dev) { do_mc32_set_multicast_list(dev,1); } static void netdev_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { strcpy(info->driver, DRV_NAME); strcpy(info->version, DRV_VERSION); sprintf(info->bus_info, "MCA 0x%lx", dev->base_addr); } static u32 netdev_get_msglevel(struct net_device *dev) { return mc32_debug; } static void netdev_set_msglevel(struct net_device *dev, u32 level) { mc32_debug = level; } static const struct ethtool_ops netdev_ethtool_ops = { .get_drvinfo = netdev_get_drvinfo, .get_msglevel = netdev_get_msglevel, .set_msglevel = netdev_set_msglevel, }; #ifdef MODULE static struct net_device *this_device; /** * init_module - entry point * * Probe and locate a 3c527 card. This really should probe and locate * all the 3c527 cards in the machine not just one of them. Yes you can * insmod multiple modules for now but it's a hack. */ int __init init_module(void) { this_device = mc32_probe(-1); if (IS_ERR(this_device)) return PTR_ERR(this_device); return 0; } /** * cleanup_module - free resources for an unload * * Unloading time. We release the MCA bus resources and the interrupt * at which point everything is ready to unload. The card must be stopped * at this point or we would not have been called. When we unload we * leave the card stopped but not totally shut down. When the card is * initialized it must be rebooted or the rings reloaded before any * transmit operations are allowed to start scribbling into memory. */ void cleanup_module(void) { unregister_netdev(this_device); cleanup_card(this_device); free_netdev(this_device); } #endif /* MODULE */