1 |
1626 |
jcastillo |
/* ibmtr.c: A shared-memory IBM Token Ring 16/4 driver for linux */
|
2 |
|
|
/*
|
3 |
|
|
Written 1993 by Mark Swanson and Peter De Schrijver.
|
4 |
|
|
This software may be used and distributed according to the terms
|
5 |
|
|
of the GNU Public License, incorporated herein by reference.
|
6 |
|
|
|
7 |
|
|
This device driver should work with Any IBM Token Ring Card that does
|
8 |
|
|
not use DMA.
|
9 |
|
|
|
10 |
|
|
I used Donald Becker's (becker@super.org) device driver work
|
11 |
|
|
as a base for most of my initial work.
|
12 |
|
|
*/
|
13 |
|
|
|
14 |
|
|
/*
|
15 |
|
|
Changes by Peter De Schrijver (Peter.Deschrijver@linux.cc.kuleuven.ac.be) :
|
16 |
|
|
|
17 |
|
|
+ changed name to ibmtr.c in anticipation of other tr boards.
|
18 |
|
|
+ changed reset code and adapter open code.
|
19 |
|
|
+ added SAP open code.
|
20 |
|
|
+ a first attempt to write interrupt, transmit and receive routines.
|
21 |
|
|
|
22 |
|
|
Changes by David W. Morris (dwm@shell.portal.com) :
|
23 |
|
|
941003 dwm: - Restructure tok_probe for multiple adapters, devices
|
24 |
|
|
- Add comments, misc reorg for clarity
|
25 |
|
|
- Flatten interrupt handler levels
|
26 |
|
|
|
27 |
|
|
Changes by Farzad Farid (farzy@zen.via.ecp.fr)
|
28 |
|
|
and Pascal Andre (andre@chimay.via.ecp.fr) (March 9 1995) :
|
29 |
|
|
- multi ring support clean up
|
30 |
|
|
- RFC1042 compliance enhanced
|
31 |
|
|
|
32 |
|
|
Changes by Pascal Andre (andre@chimay.via.ecp.fr) (September 7 1995) :
|
33 |
|
|
- bug correction in tr_tx
|
34 |
|
|
- removed redundant information display
|
35 |
|
|
- some code reworking
|
36 |
|
|
|
37 |
|
|
Changes by Michel Lespinasse (walken@via.ecp.fr),
|
38 |
|
|
Yann Doussot (doussot@via.ecp.fr) and Pascal Andre (andre@via.ecp.fr)
|
39 |
|
|
(February 18, 1996) :
|
40 |
|
|
- modified shared memory and mmio access port the driver to
|
41 |
|
|
alpha platform (structure access -> readb/writeb)
|
42 |
|
|
|
43 |
|
|
Changes by Steve Kipisz (bungy@ibm.net or kipisz@vnet.ibm.com)
|
44 |
|
|
(January 18 1996):
|
45 |
|
|
- swapped WWOR and WWCR in ibmtr.h
|
46 |
|
|
- moved some init code from tok_probe into trdev_init. The
|
47 |
|
|
PCMCIA code can call trdev_init to complete initializing
|
48 |
|
|
the driver.
|
49 |
|
|
- added -DPCMCIA to support PCMCIA
|
50 |
|
|
- detecting PCMCIA Card Removal in interrupt handler. if
|
51 |
|
|
ISRP is FF, then a PCMCIA card has been removed
|
52 |
|
|
|
53 |
|
|
Changes by Paul Norton (pnorton@cts.com) :
|
54 |
|
|
- restructured the READ.LOG logic to prevent the transmit SRB
|
55 |
|
|
from being rudely overwritten before the transmit cycle is
|
56 |
|
|
complete. (August 15 1996)
|
57 |
|
|
|
58 |
|
|
Warnings !!!!!!!!!!!!!!
|
59 |
|
|
This driver is only partially sanitized for support of multiple
|
60 |
|
|
adapters. It will almost definitely fail if more than one
|
61 |
|
|
active adapter is identified.
|
62 |
|
|
*/
|
63 |
|
|
|
64 |
|
|
#ifdef PCMCIA
|
65 |
|
|
#define MODULE
|
66 |
|
|
#endif
|
67 |
|
|
|
68 |
|
|
#include <linux/module.h>
|
69 |
|
|
|
70 |
|
|
#ifdef PCMCIA
|
71 |
|
|
#undef MODULE
|
72 |
|
|
#endif
|
73 |
|
|
|
74 |
|
|
#define NO_AUTODETECT 1
|
75 |
|
|
#undef NO_AUTODETECT
|
76 |
|
|
#undef ENABLE_PAGING
|
77 |
|
|
|
78 |
|
|
#define FALSE 0
|
79 |
|
|
#define TRUE (!FALSE)
|
80 |
|
|
|
81 |
|
|
/* changes the output format of driver initialisation */
|
82 |
|
|
#define TR_NEWFORMAT 1
|
83 |
|
|
#define TR_VERBOSE 0
|
84 |
|
|
|
85 |
|
|
/* some 95 OS send many non UI frame; this allow removing the warning */
|
86 |
|
|
#define TR_FILTERNONUI 1
|
87 |
|
|
|
88 |
|
|
/* version and credits */
|
89 |
|
|
static const char *version =
|
90 |
|
|
"ibmtr.c: v1.3.57 8/7/94 Peter De Schrijver and Mark Swanson\n"
|
91 |
|
|
" modified 10/3/94 DW Morris, modified at VIA, ECP, France\n"
|
92 |
|
|
" (3/9/95 F Farid and P Andre, 9/7/95 PA and 2/20/95 ML/PA/YD)\n";
|
93 |
|
|
|
94 |
|
|
static char pcchannelid[]={0x05, 0x00, 0x04, 0x09,
|
95 |
|
|
0x04, 0x03, 0x04, 0x0f,
|
96 |
|
|
0x03, 0x06, 0x03, 0x01,
|
97 |
|
|
0x03, 0x01, 0x03, 0x00,
|
98 |
|
|
0x03, 0x09, 0x03, 0x09,
|
99 |
|
|
0x03, 0x00, 0x02, 0x00};
|
100 |
|
|
static char mcchannelid[]={0x04, 0x0d, 0x04, 0x01,
|
101 |
|
|
0x05, 0x02, 0x05, 0x03,
|
102 |
|
|
0x03, 0x06, 0x03, 0x03,
|
103 |
|
|
0x05, 0x08, 0x03, 0x04,
|
104 |
|
|
0x03, 0x05, 0x03, 0x01,
|
105 |
|
|
0x03, 0x08, 0x02, 0x00};
|
106 |
|
|
|
107 |
|
|
#include <linux/kernel.h>
|
108 |
|
|
#include <linux/sched.h>
|
109 |
|
|
#include <linux/errno.h>
|
110 |
|
|
#include <linux/sched.h>
|
111 |
|
|
#include <linux/timer.h>
|
112 |
|
|
#include <linux/in.h>
|
113 |
|
|
#include <asm/io.h>
|
114 |
|
|
#include <asm/system.h>
|
115 |
|
|
#include <asm/bitops.h>
|
116 |
|
|
#include <linux/ioport.h>
|
117 |
|
|
#include <linux/errno.h>
|
118 |
|
|
#include <linux/string.h>
|
119 |
|
|
#include <linux/skbuff.h>
|
120 |
|
|
#include <linux/interrupt.h>
|
121 |
|
|
#include <linux/delay.h>
|
122 |
|
|
#include <linux/netdevice.h>
|
123 |
|
|
#include <linux/trdevice.h>
|
124 |
|
|
#include <stddef.h>
|
125 |
|
|
#include "ibmtr.h"
|
126 |
|
|
|
127 |
|
|
|
128 |
|
|
#define DPRINTK(format, args...) printk("%s: " format, dev->name , ## args)
|
129 |
|
|
#define DPRINTD(format, args...) DummyCall("%s: " format, dev->name , ## args)
|
130 |
|
|
|
131 |
|
|
#if TR_NEWFORMAT
|
132 |
|
|
/* this allows displaying full adapter information */
|
133 |
|
|
const char *channel_def[] = { "ISA", "MCA", "ISA P&P" };
|
134 |
|
|
|
135 |
|
|
char *adapter_def(char type)
|
136 |
|
|
{
|
137 |
|
|
switch (type) {
|
138 |
|
|
case 0xF : return "Adapter/A";
|
139 |
|
|
case 0xE : return "16/4 Adapter/II";
|
140 |
|
|
default : return "adapter";
|
141 |
|
|
};
|
142 |
|
|
};
|
143 |
|
|
#endif
|
144 |
|
|
|
145 |
|
|
#if !TR_NEWFORMAT
|
146 |
|
|
unsigned char ibmtr_debug_trace=1; /* Patch or otherwise alter to
|
147 |
|
|
control tokenring tracing. */
|
148 |
|
|
#else
|
149 |
|
|
unsigned char ibmtr_debug_trace=0;
|
150 |
|
|
#endif
|
151 |
|
|
#define TRC_INIT 0x01 /* Trace initialization & PROBEs */
|
152 |
|
|
#define TRC_INITV 0x02 /* verbose init trace points */
|
153 |
|
|
|
154 |
|
|
/* addresses to scan */
|
155 |
|
|
static short TokBaseAddrs[] = { MMIOStartLocP, MMIOStartLocA };
|
156 |
|
|
|
157 |
|
|
|
158 |
|
|
int tok_probe(struct device *dev);
|
159 |
|
|
unsigned char get_sram_size(struct tok_info *adapt_info);
|
160 |
|
|
|
161 |
|
|
static int tok_init_card(struct device *dev);
|
162 |
|
|
int trdev_init(struct device *dev);
|
163 |
|
|
void tok_interrupt(int irq, void *dev_id, struct pt_regs *regs);
|
164 |
|
|
|
165 |
|
|
static void initial_tok_int(struct device *dev);
|
166 |
|
|
|
167 |
|
|
static void open_sap(unsigned char type,struct device *dev);
|
168 |
|
|
void tok_open_adapter(unsigned long dev_addr);
|
169 |
|
|
static void tr_rx(struct device *dev);
|
170 |
|
|
static void tr_tx(struct device *dev);
|
171 |
|
|
|
172 |
|
|
static int tok_open(struct device *dev);
|
173 |
|
|
static int tok_close(struct device *dev);
|
174 |
|
|
static int tok_send_packet(struct sk_buff *skb, struct device *dev);
|
175 |
|
|
static struct enet_statistics * tok_get_stats(struct device *dev);
|
176 |
|
|
void tr_readlog(struct device *dev);
|
177 |
|
|
|
178 |
|
|
static struct timer_list tr_timer={NULL,NULL,0,0L,tok_open_adapter};
|
179 |
|
|
|
180 |
|
|
#if 0
|
181 |
|
|
int DummyCallCount=0;
|
182 |
|
|
|
183 |
|
|
/* This routine combined with the #DEFINE DPRINTD serves
|
184 |
|
|
to workaround the gcc apparent bug. in tr_tx() */
|
185 |
|
|
|
186 |
|
|
static void DummyCall(const char * fmt,...)
|
187 |
|
|
{ DummyCallCount++; return; }
|
188 |
|
|
#endif
|
189 |
|
|
|
190 |
|
|
static void PrtChanID(char *pcid, short stride) {
|
191 |
|
|
short i, j;
|
192 |
|
|
for (i=0, j=0; i<24; i++, j+=stride)
|
193 |
|
|
printk("%1x", ((int) pcid[j]) & 0x0f);
|
194 |
|
|
printk("\n");
|
195 |
|
|
}
|
196 |
|
|
|
197 |
|
|
static void HWPrtChanID (__u32 pcid, short stride)
|
198 |
|
|
{
|
199 |
|
|
short i, j;
|
200 |
|
|
for (i=0, j=0; i<24; i++, j+=stride)
|
201 |
|
|
printk("%1x", ((int)readb(pcid + j)) & 0x0f);
|
202 |
|
|
printk("\n");
|
203 |
|
|
}
|
204 |
|
|
|
205 |
|
|
/* tok_probe(): Routine specified in the network device structure
|
206 |
|
|
to probe for an IBM Token Ring Adapter. Routine outline:
|
207 |
|
|
I. Interrogate hardware to determine if an adapter exists
|
208 |
|
|
and what the speeds and feeds are
|
209 |
|
|
II. Setup data structures to control execution based upon
|
210 |
|
|
adapter characteristics.
|
211 |
|
|
III. Initialize adapter operation
|
212 |
|
|
We expect tok_probe to be called once for each device entry
|
213 |
|
|
which references it.
|
214 |
|
|
*/
|
215 |
|
|
|
216 |
|
|
int tok_probe(struct device *dev)
|
217 |
|
|
{
|
218 |
|
|
unsigned char segment=0, intr=0, irq=0, i=0, j=0, cardpresent=NOTOK,temp=0;
|
219 |
|
|
__u32 t_mmio=0;
|
220 |
|
|
short PIOaddr=0, iAddr;
|
221 |
|
|
struct tok_info *ti=0;
|
222 |
|
|
static struct tok_info *badti=0; /* if fail after kmalloc, reuse */
|
223 |
|
|
|
224 |
|
|
static unsigned char Shared_Ram_Base = IBMTR_SHARED_RAM_BASE;
|
225 |
|
|
|
226 |
|
|
/* this is the major adapter probe loop. For each call to tok_probe,
|
227 |
|
|
we try each remaining entry in TokBaseAddrs[] as a possible
|
228 |
|
|
adapter. Once an entry is rejected or assigned, we zero it to
|
229 |
|
|
avoid duplicate use or worthless trial for the tok probe call*/
|
230 |
|
|
|
231 |
|
|
for (iAddr=0;
|
232 |
|
|
iAddr < (sizeof(TokBaseAddrs)/sizeof(short))&&PIOaddr==0; iAddr++) {
|
233 |
|
|
|
234 |
|
|
__u32 cd_chanid;
|
235 |
|
|
unsigned char *tchanid, ctemp;
|
236 |
|
|
|
237 |
|
|
PIOaddr=TokBaseAddrs[iAddr]; /* address to try */
|
238 |
|
|
TokBaseAddrs[iAddr] = 0; /* (and marked already used */
|
239 |
|
|
if (PIOaddr == 0) continue; /* already tried this addr */
|
240 |
|
|
|
241 |
|
|
/* Make sure PIO address not already assigned
|
242 |
|
|
elsewhere before we muck with IO address */
|
243 |
|
|
if (check_region(PIOaddr,TR_IO_EXTENT)) {
|
244 |
|
|
if (ibmtr_debug_trace & TRC_INIT)
|
245 |
|
|
DPRINTK("check_region(%4hx,%d) failed.\n", PIOaddr, TR_IO_EXTENT);
|
246 |
|
|
PIOaddr = 0;
|
247 |
|
|
continue; /* clear to flag fail and try next */
|
248 |
|
|
}
|
249 |
|
|
/* Query the adapter PIO base port which will return
|
250 |
|
|
indication of where MMIO was placed (per tech ref
|
251 |
|
|
this assignment is done by BIOS - what is rational for
|
252 |
|
|
where it is?). We also have a coded interrupt address. */
|
253 |
|
|
|
254 |
|
|
segment = inb(PIOaddr);
|
255 |
|
|
/* out of range values so we'll assume non-existent IO device */
|
256 |
|
|
if (segment < 0x40 || segment > 0xe0) {
|
257 |
|
|
PIOaddr = 0;
|
258 |
|
|
continue; /* clear to flag fail and try next */
|
259 |
|
|
}
|
260 |
|
|
|
261 |
|
|
/* Compute the linear base address of the MMIO area
|
262 |
|
|
as LINUX doesn't care about segments */
|
263 |
|
|
t_mmio=(((__u32)(segment & 0xfc) << 11) + 0x80000);
|
264 |
|
|
intr = segment & 0x03; /* low bits is coded interrupt # */
|
265 |
|
|
if (ibmtr_debug_trace & TRC_INIT)
|
266 |
|
|
DPRINTK("PIOaddr: %4hx seg/intr: %2x mmio base: %08X intr: %d\n", PIOaddr, (int)segment, t_mmio, (int)intr);
|
267 |
|
|
|
268 |
|
|
/* Now we will compare expected 'channelid' strings with
|
269 |
|
|
what we is there to learn of ISA/MCA or not TR card */
|
270 |
|
|
/* !!!WARNING:!!!! It seems pretty silly to blunder ahead
|
271 |
|
|
w/o verification that the mmio address we have found
|
272 |
|
|
is valid storage -- perhaps this is tolerable for current
|
273 |
|
|
hardware state??? */
|
274 |
|
|
|
275 |
|
|
cd_chanid = (CHANNEL_ID + t_mmio); /* for efficiency */
|
276 |
|
|
tchanid=pcchannelid;
|
277 |
|
|
cardpresent=TR_ISA; /* try ISA */
|
278 |
|
|
|
279 |
|
|
/* suboptimize knowing first byte different */
|
280 |
|
|
ctemp = readb(cd_chanid) & 0x0f;
|
281 |
|
|
if (ctemp != *tchanid) { /* NOT ISA card, try MCA */
|
282 |
|
|
tchanid=mcchannelid;
|
283 |
|
|
cardpresent=TR_MCA;
|
284 |
|
|
if (ctemp != *tchanid) /* Neither ISA nor MCA */
|
285 |
|
|
cardpresent=NOTOK;
|
286 |
|
|
}
|
287 |
|
|
|
288 |
|
|
if (cardpresent != NOTOK) { /* know presumed type, try rest of ID */
|
289 |
|
|
for (i=2,j=1; i<=46; i=i+2,j++) {
|
290 |
|
|
if ((readb(cd_chanid+i) & 0x0f) != tchanid[j]) {
|
291 |
|
|
cardpresent=NOTOK; /* match failed, not TR card */
|
292 |
|
|
break;
|
293 |
|
|
}
|
294 |
|
|
}
|
295 |
|
|
}
|
296 |
|
|
|
297 |
|
|
/* If we have an ISA board check for the ISA P&P version,
|
298 |
|
|
as it has different IRQ settings */
|
299 |
|
|
if (cardpresent == TR_ISA && (readb(AIPFID + t_mmio)==0x0e))
|
300 |
|
|
cardpresent=TR_ISAPNP;
|
301 |
|
|
|
302 |
|
|
if (cardpresent == NOTOK) { /* "channel_id" did not match, report */
|
303 |
|
|
if (ibmtr_debug_trace & TRC_INIT) {
|
304 |
|
|
DPRINTK("Channel ID string not found for PIOaddr: %4hx\n", PIOaddr);
|
305 |
|
|
DPRINTK("Expected for ISA: "); PrtChanID(pcchannelid,1);
|
306 |
|
|
DPRINTK(" found: "); HWPrtChanID(cd_chanid,2);
|
307 |
|
|
DPRINTK("Expected for MCA: "); PrtChanID(mcchannelid,1);
|
308 |
|
|
}
|
309 |
|
|
PIOaddr = 0; /* all to know not found yet */
|
310 |
|
|
continue;
|
311 |
|
|
}
|
312 |
|
|
|
313 |
|
|
/* !!!! we could tighten validation by checking the HW Address
|
314 |
|
|
against the 1-s complement.. Move the get HW logic to here */
|
315 |
|
|
|
316 |
|
|
}
|
317 |
|
|
|
318 |
|
|
/* The search loop has either completed with a presumed TR adapter
|
319 |
|
|
or none found. Check situation ... march on if possible */
|
320 |
|
|
|
321 |
|
|
if (PIOaddr == 0) { /* failed to find a valid TR adapter */
|
322 |
|
|
if (ibmtr_debug_trace & TRC_INIT)
|
323 |
|
|
DPRINTK("Unable to assign adapter to device.\n");
|
324 |
|
|
return ENODEV;
|
325 |
|
|
}
|
326 |
|
|
|
327 |
|
|
/*?? Now, allocate some of the pl0 buffers for this driver.. */
|
328 |
|
|
|
329 |
|
|
if (!badti) {
|
330 |
|
|
ti = (struct tok_info *)kmalloc(sizeof(struct tok_info), GFP_KERNEL);
|
331 |
|
|
if (ti == NULL) return -ENOMEM;
|
332 |
|
|
} else {
|
333 |
|
|
ti = badti;
|
334 |
|
|
badti = NULL;
|
335 |
|
|
} /*?? dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); */
|
336 |
|
|
|
337 |
|
|
memset(ti, 0, sizeof(struct tok_info));
|
338 |
|
|
|
339 |
|
|
ti->mmio= t_mmio;
|
340 |
|
|
ti->readlog_pending = 0;
|
341 |
|
|
|
342 |
|
|
dev->priv = ti; /* this seems like the logical use of the
|
343 |
|
|
field ... let's try some empirical tests
|
344 |
|
|
using the token-info structure -- that
|
345 |
|
|
should fit with out future hope of multiple
|
346 |
|
|
adapter support as well /dwm */
|
347 |
|
|
|
348 |
|
|
switch (cardpresent) {
|
349 |
|
|
case TR_ISA:
|
350 |
|
|
if (intr==0) irq=9; /* irq2 really is irq9 */
|
351 |
|
|
if (intr==1) irq=3;
|
352 |
|
|
if (intr==2) irq=6;
|
353 |
|
|
if (intr==3) irq=7;
|
354 |
|
|
ti->global_int_enable=GLOBAL_INT_ENABLE+((irq==9) ? 2 : irq);
|
355 |
|
|
ti->sram=0;
|
356 |
|
|
#if !TR_NEWFORMAT
|
357 |
|
|
DPRINTK("ti->global_int_enable: %04X\n",ti->global_int_enable);
|
358 |
|
|
#endif
|
359 |
|
|
break;
|
360 |
|
|
case TR_MCA:
|
361 |
|
|
if (intr==0) irq=9;
|
362 |
|
|
if (intr==1) irq=3;
|
363 |
|
|
if (intr==2) irq=10;
|
364 |
|
|
if (intr==3) irq=11;
|
365 |
|
|
ti->global_int_enable=0;
|
366 |
|
|
ti->sram=((__u32)(inb(PIOaddr+ADAPTRESETREL) & 0xfe) << 12);
|
367 |
|
|
break;
|
368 |
|
|
case TR_ISAPNP:
|
369 |
|
|
if (intr==0) irq=9;
|
370 |
|
|
if (intr==1) irq=3;
|
371 |
|
|
if (intr==2) irq=10;
|
372 |
|
|
if (intr==3) irq=11;
|
373 |
|
|
while(!readb(ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN));
|
374 |
|
|
ti->sram=((__u32)readb(ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN)<<12);
|
375 |
|
|
ti->global_int_enable=PIOaddr+ADAPTINTREL;
|
376 |
|
|
break;
|
377 |
|
|
|
378 |
|
|
}
|
379 |
|
|
|
380 |
|
|
if (ibmtr_debug_trace & TRC_INIT) { /* just report int */
|
381 |
|
|
DPRINTK("irq=%d",irq);
|
382 |
|
|
if (ibmtr_debug_trace & TRC_INITV) { /* full chat in verbose only */
|
383 |
|
|
DPRINTK(", ti->mmio=%08X",ti->mmio);
|
384 |
|
|
printk(", segment=%02X",segment);
|
385 |
|
|
}
|
386 |
|
|
printk(".\n");
|
387 |
|
|
}
|
388 |
|
|
|
389 |
|
|
/* Get hw address of token ring card */
|
390 |
|
|
#if !TR_NEWFORMAT
|
391 |
|
|
DPRINTK("hw address: ");
|
392 |
|
|
#endif
|
393 |
|
|
j=0;
|
394 |
|
|
for (i=0; i<0x18; i=i+2) {
|
395 |
|
|
/* technical reference states to do this */
|
396 |
|
|
temp = readb(ti->mmio + AIP + i) & 0x0f;
|
397 |
|
|
#if !TR_NEWFORMAT
|
398 |
|
|
printk("%1X",ti->hw_address[j]=temp);
|
399 |
|
|
#else
|
400 |
|
|
ti->hw_address[j]=temp;
|
401 |
|
|
#endif
|
402 |
|
|
if(j&1)
|
403 |
|
|
dev->dev_addr[(j/2)]=ti->hw_address[j]+(ti->hw_address[j-1]<<4);
|
404 |
|
|
++j;
|
405 |
|
|
}
|
406 |
|
|
#ifndef TR_NEWFORMAT
|
407 |
|
|
printk("\n");
|
408 |
|
|
#endif
|
409 |
|
|
|
410 |
|
|
/* get Adapter type: 'F' = Adapter/A, 'E' = 16/4 Adapter II,...*/
|
411 |
|
|
ti->adapter_type = readb(ti->mmio + AIPADAPTYPE);
|
412 |
|
|
|
413 |
|
|
/* get Data Rate: F=4Mb, E=16Mb, D=4Mb & 16Mb ?? */
|
414 |
|
|
ti->data_rate = readb(ti->mmio + AIPDATARATE);
|
415 |
|
|
|
416 |
|
|
/* Get Early Token Release support?: F=no, E=4Mb, D=16Mb, C=4&16Mb */
|
417 |
|
|
ti->token_release = readb(ti->mmio + AIPEARLYTOKEN);
|
418 |
|
|
|
419 |
|
|
/* How much shared RAM is on adapter ? */
|
420 |
|
|
ti->avail_shared_ram = get_sram_size(ti);
|
421 |
|
|
|
422 |
|
|
/* We need to set or do a bunch of work here based on previous results.. */
|
423 |
|
|
/* Support paging? What sizes?: F=no, E=16k, D=32k, C=16 & 32k */
|
424 |
|
|
ti->shared_ram_paging = readb(ti->mmio + AIPSHRAMPAGE);
|
425 |
|
|
|
426 |
|
|
/* Available DHB 4Mb size: F=2048, E=4096, D=4464 */
|
427 |
|
|
ti->dhb_size4mb = readb(ti->mmio + AIP4MBDHB);
|
428 |
|
|
|
429 |
|
|
/* Available DHB 16Mb size: F=2048, E=4096, D=8192, C=16384, B=17960 */
|
430 |
|
|
ti->dhb_size16mb = readb(ti->mmio + AIP16MBDHB);
|
431 |
|
|
|
432 |
|
|
#if !TR_NEWFORMAT
|
433 |
|
|
DPRINTK("atype=%x, drate=%x, trel=%x, asram=%dK, srp=%x, "
|
434 |
|
|
"dhb(4mb=%x, 16mb=%x)\n",ti->adapter_type,
|
435 |
|
|
ti->data_rate, ti->token_release, ti->avail_shared_ram/2,
|
436 |
|
|
ti->shared_ram_paging, ti->dhb_size4mb, ti->dhb_size16mb);
|
437 |
|
|
#endif
|
438 |
|
|
|
439 |
|
|
/* We must figure out how much shared memory space this adapter
|
440 |
|
|
will occupy so that if there are two adapters we can fit both
|
441 |
|
|
in. Given a choice, we will limit this adapter to 32K. The
|
442 |
|
|
maximum space will use for two adapters is 64K so if the adapter
|
443 |
|
|
we are working on demands 64K (it also doesn't support paging),
|
444 |
|
|
then only one adapter can be supported. */
|
445 |
|
|
|
446 |
|
|
/* determine how much of total RAM is mapped into PC space */
|
447 |
|
|
ti->mapped_ram_size=1<<((((readb(ti->mmio+ ACA_OFFSET + ACA_RW + RRR_ODD)) >>2) & 0x03) + 4);
|
448 |
|
|
ti->page_mask=0;
|
449 |
|
|
if (ti->shared_ram_paging == 0xf) { /* No paging in adapter */
|
450 |
|
|
ti->mapped_ram_size = ti->avail_shared_ram;
|
451 |
|
|
} else {
|
452 |
|
|
#ifdef ENABLE_PAGING
|
453 |
|
|
unsigned char pg_size;
|
454 |
|
|
#endif
|
455 |
|
|
|
456 |
|
|
#if !TR_NEWFORMAT
|
457 |
|
|
DPRINTK("shared ram page size: %dK\n",ti->mapped_ram_size/2);
|
458 |
|
|
#endif
|
459 |
|
|
#ifdef ENABLE_PAGING
|
460 |
|
|
switch(ti->shared_ram_paging) {
|
461 |
|
|
case 0xf:
|
462 |
|
|
break;
|
463 |
|
|
case 0xe:
|
464 |
|
|
ti->page_mask=(ti->mapped_ram_size==32) ? 0xc0 : 0;
|
465 |
|
|
pg_size=32; /* 16KB page size */
|
466 |
|
|
break;
|
467 |
|
|
case 0xd:
|
468 |
|
|
ti->page_mask=(ti->mapped_ram_size==64) ? 0x80 : 0;
|
469 |
|
|
pg_size=64; /* 32KB page size */
|
470 |
|
|
break;
|
471 |
|
|
case 0xc:
|
472 |
|
|
ti->page_mask=(ti->mapped_ram_size==32) ? 0xc0 : 0;
|
473 |
|
|
ti->page_mask=(ti->mapped_ram_size==64) ? 0x80 : 0;
|
474 |
|
|
DPRINTK("Dual size shared RAM page (code=0xC), don't support it!\n");
|
475 |
|
|
/* nb/dwm: I did this because RRR (3,2) bits are documented as
|
476 |
|
|
R/O and I can't find how to select which page size
|
477 |
|
|
Also, the above conditional statement sequence is invalid
|
478 |
|
|
as page_mask will always be set by the second stmt */
|
479 |
|
|
badti=ti;
|
480 |
|
|
break;
|
481 |
|
|
default:
|
482 |
|
|
DPRINTK("Unknown shared ram paging info %01X\n",ti->shared_ram_paging);
|
483 |
|
|
badti=ti; /* bail out if bad code */
|
484 |
|
|
break;
|
485 |
|
|
}
|
486 |
|
|
if (ti->page_mask) {
|
487 |
|
|
if (pg_size > ti->mapped_ram_size) {
|
488 |
|
|
DPRINTK("Page size (%d) > mapped ram window (%d), can't page.\n",
|
489 |
|
|
pg_size, ti->mapped_ram_size);
|
490 |
|
|
ti->page_mask = 0; /* reset paging */
|
491 |
|
|
} else {
|
492 |
|
|
ti->mapped_ram_size=ti->avail_shared_ram;
|
493 |
|
|
DPRINTK("Shared RAM paging enabled. Page size : %uK\n",
|
494 |
|
|
((ti->page_mask^ 0xff)+1)>>2);
|
495 |
|
|
}
|
496 |
|
|
#endif
|
497 |
|
|
}
|
498 |
|
|
|
499 |
|
|
/* finish figuring the shared RAM address */
|
500 |
|
|
if (cardpresent==TR_ISA) {
|
501 |
|
|
static unsigned char ram_bndry_mask[]={0xfe, 0xfc, 0xf8, 0xf0};
|
502 |
|
|
unsigned char new_base, rrr_32, chk_base, rbm;
|
503 |
|
|
rrr_32 = ((readb(ti->mmio+ ACA_OFFSET + ACA_RW + RRR_ODD))>>2) & 0x03;
|
504 |
|
|
rbm = ram_bndry_mask[rrr_32];
|
505 |
|
|
new_base = (Shared_Ram_Base + (~rbm)) & rbm; /* up to boundary */
|
506 |
|
|
chk_base = new_base + (ti->mapped_ram_size>>3);
|
507 |
|
|
if (chk_base > (IBMTR_SHARED_RAM_BASE+IBMTR_SHARED_RAM_SIZE)) {
|
508 |
|
|
DPRINTK("Shared RAM for this adapter (%05x) exceeds driver"
|
509 |
|
|
" limit (%05x), adapter not started.\n",
|
510 |
|
|
chk_base<<12, (IBMTR_SHARED_RAM_BASE+
|
511 |
|
|
IBMTR_SHARED_RAM_SIZE)<<12);
|
512 |
|
|
badti=ti;
|
513 |
|
|
} else { /* seems cool, record what we have figured out */
|
514 |
|
|
ti->sram_base = new_base;
|
515 |
|
|
Shared_Ram_Base = new_base;
|
516 |
|
|
}
|
517 |
|
|
}
|
518 |
|
|
|
519 |
|
|
/* dwm: irq and other final setup moved here so if we find other
|
520 |
|
|
unrecognized values OR shared ram conflicts, we can still
|
521 |
|
|
bail out in a rather benign fashion. */
|
522 |
|
|
|
523 |
|
|
if (badti) return ENODEV;
|
524 |
|
|
#if !TR_NEWFORMAT
|
525 |
|
|
DPRINTK("Using %dK shared RAM\n",ti->mapped_ram_size/2);
|
526 |
|
|
#endif
|
527 |
|
|
|
528 |
|
|
if (request_irq (dev->irq = irq, &tok_interrupt,0,"IBM TR", NULL) != 0) {
|
529 |
|
|
DPRINTK("Could not grab irq %d. Halting Token Ring driver.\n",irq);
|
530 |
|
|
badti = ti; /* keep track of unused tok_info */
|
531 |
|
|
return ENODEV;
|
532 |
|
|
}
|
533 |
|
|
irq2dev_map[irq]=dev;
|
534 |
|
|
|
535 |
|
|
/*?? Now, allocate some of the PIO PORTs for this driver.. */
|
536 |
|
|
request_region(PIOaddr,TR_IO_EXTENT,"ibmtr"); /* record PIOaddr range
|
537 |
|
|
as busy */
|
538 |
|
|
#if !TR_NEWFORMAT
|
539 |
|
|
DPRINTK("%s",version); /* As we have passed card identification,
|
540 |
|
|
let the world know we're here! */
|
541 |
|
|
#else
|
542 |
|
|
printk("%s",version);
|
543 |
|
|
DPRINTK("%s %s found using irq %d, PIOaddr %4hx, %dK shared RAM.\n",
|
544 |
|
|
channel_def[cardpresent-1], adapter_def(ti->adapter_type), irq,
|
545 |
|
|
PIOaddr, ti->mapped_ram_size/2);
|
546 |
|
|
DPRINTK("Hardware address : %02X:%02X:%02X:%02X:%02X:%02X\n",
|
547 |
|
|
dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
|
548 |
|
|
dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
|
549 |
|
|
#endif
|
550 |
|
|
|
551 |
|
|
dev->base_addr=PIOaddr; /* set the value for device */
|
552 |
|
|
|
553 |
|
|
trdev_init(dev);
|
554 |
|
|
tok_init_card(dev);
|
555 |
|
|
|
556 |
|
|
return 0; /* Return 0 to indicate we have found a Token Ring card. */
|
557 |
|
|
}
|
558 |
|
|
|
559 |
|
|
/* query the adapter for the size of shared RAM */
|
560 |
|
|
|
561 |
|
|
unsigned char get_sram_size(struct tok_info *adapt_info)
|
562 |
|
|
{
|
563 |
|
|
|
564 |
|
|
unsigned char avail_sram_code;
|
565 |
|
|
static unsigned char size_code[]={ 0,16,32,64,127,128 };
|
566 |
|
|
|
567 |
|
|
/* Adapter gives
|
568 |
|
|
'F' -- use RRR bits 3,2
|
569 |
|
|
'E' -- 8kb 'D' -- 16kb
|
570 |
|
|
'C' -- 32kb 'A' -- 64KB
|
571 |
|
|
'B' - 64KB less 512 bytes at top
|
572 |
|
|
(WARNING ... must zero top bytes in INIT */
|
573 |
|
|
|
574 |
|
|
avail_sram_code=0xf-readb(adapt_info->mmio + AIPAVAILSHRAM);
|
575 |
|
|
if (avail_sram_code)
|
576 |
|
|
return size_code[avail_sram_code];
|
577 |
|
|
else /* for code 'F', must compute size from RRR(3,2) bits */
|
578 |
|
|
return 1<<((readb(adapt_info->mmio+ ACA_OFFSET + ACA_RW + RRR_ODD)>>2)+4);
|
579 |
|
|
}
|
580 |
|
|
|
581 |
|
|
int trdev_init(struct device *dev)
|
582 |
|
|
{
|
583 |
|
|
struct tok_info *ti=(struct tok_info *)dev->priv;
|
584 |
|
|
|
585 |
|
|
ti->open_status=CLOSED;
|
586 |
|
|
|
587 |
|
|
dev->init=tok_init_card;
|
588 |
|
|
dev->open=tok_open;
|
589 |
|
|
dev->stop=tok_close;
|
590 |
|
|
dev->hard_start_xmit=tok_send_packet;
|
591 |
|
|
dev->get_stats = NULL;
|
592 |
|
|
dev->get_stats = tok_get_stats;
|
593 |
|
|
dev->set_multicast_list = NULL;
|
594 |
|
|
tr_setup(dev);
|
595 |
|
|
|
596 |
|
|
return 0;
|
597 |
|
|
}
|
598 |
|
|
|
599 |
|
|
|
600 |
|
|
|
601 |
|
|
static int tok_open(struct device *dev)
|
602 |
|
|
{
|
603 |
|
|
struct tok_info *ti=(struct tok_info *)dev->priv;
|
604 |
|
|
|
605 |
|
|
if (ti->open_status==CLOSED) tok_init_card(dev);
|
606 |
|
|
|
607 |
|
|
if (ti->open_status==IN_PROGRESS) sleep_on(&ti->wait_for_reset);
|
608 |
|
|
|
609 |
|
|
if (ti->open_status==SUCCESS) {
|
610 |
|
|
dev->tbusy=0;
|
611 |
|
|
dev->interrupt=0;
|
612 |
|
|
dev->start=1;
|
613 |
|
|
/* NEED to see smem size *AND* reset high 512 bytes if needed */
|
614 |
|
|
|
615 |
|
|
MOD_INC_USE_COUNT;
|
616 |
|
|
|
617 |
|
|
return 0;
|
618 |
|
|
} else return -EAGAIN;
|
619 |
|
|
|
620 |
|
|
}
|
621 |
|
|
|
622 |
|
|
static int tok_close(struct device *dev)
|
623 |
|
|
{
|
624 |
|
|
|
625 |
|
|
struct tok_info *ti=(struct tok_info *) dev->priv;
|
626 |
|
|
|
627 |
|
|
writeb(DIR_CLOSE_ADAPTER,
|
628 |
|
|
ti->srb + offsetof(struct srb_close_adapter, command));
|
629 |
|
|
writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
|
630 |
|
|
|
631 |
|
|
ti->open_status=CLOSED;
|
632 |
|
|
|
633 |
|
|
sleep_on(&ti->wait_for_tok_int);
|
634 |
|
|
|
635 |
|
|
if (readb(ti->srb + offsetof(struct srb_close_adapter, ret_code)))
|
636 |
|
|
DPRINTK("close adapter failed: %02X\n",
|
637 |
|
|
(int)readb(ti->srb + offsetof(struct srb_close_adapter, ret_code)));
|
638 |
|
|
|
639 |
|
|
MOD_DEC_USE_COUNT;
|
640 |
|
|
|
641 |
|
|
return 0;
|
642 |
|
|
}
|
643 |
|
|
|
644 |
|
|
void tok_interrupt (int irq, void *dev_id, struct pt_regs *regs)
|
645 |
|
|
{
|
646 |
|
|
unsigned char status;
|
647 |
|
|
struct tok_info *ti;
|
648 |
|
|
struct device *dev = (struct device *)(irq2dev_map[irq]);
|
649 |
|
|
|
650 |
|
|
#if TR_VERBOSE
|
651 |
|
|
DPRINTK("Int from tok_driver, dev : %p\n",dev);
|
652 |
|
|
#endif
|
653 |
|
|
|
654 |
|
|
ti=(struct tok_info *) dev->priv;
|
655 |
|
|
|
656 |
|
|
switch (ti->do_tok_int) {
|
657 |
|
|
|
658 |
|
|
case NOT_FIRST:
|
659 |
|
|
|
660 |
|
|
/* Begin the regular interrupt handler HERE inline to avoid
|
661 |
|
|
the extra levels of logic and call depth for the
|
662 |
|
|
original solution. */
|
663 |
|
|
|
664 |
|
|
dev->interrupt=1;
|
665 |
|
|
|
666 |
|
|
/* Disable interrupts till processing is finished */
|
667 |
|
|
writeb((~INT_ENABLE), ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_EVEN);
|
668 |
|
|
|
669 |
|
|
/* Reset interrupt for ISA boards */
|
670 |
|
|
if (ti->global_int_enable)
|
671 |
|
|
outb(0, ti->global_int_enable);
|
672 |
|
|
|
673 |
|
|
status=readb(ti->mmio + ACA_OFFSET + ACA_RW + ISRP_ODD);
|
674 |
|
|
#ifdef PCMCIA
|
675 |
|
|
/* Check if the PCMCIA card was pulled. */
|
676 |
|
|
if (status == 0xFF)
|
677 |
|
|
{
|
678 |
|
|
DPRINTK("PCMCIA card removed.\n");
|
679 |
|
|
dev->interrupt = 0;
|
680 |
|
|
return;
|
681 |
|
|
}
|
682 |
|
|
|
683 |
|
|
/* Check ISRP EVEN too. */
|
684 |
|
|
if ( *(unsigned char *)(ti->mmio + ACA_OFFSET + ACA_RW + ISRP_EVEN) == 0xFF)
|
685 |
|
|
{
|
686 |
|
|
DPRINTK("PCMCIA card removed.\n");
|
687 |
|
|
dev->interrupt = 0;
|
688 |
|
|
return;
|
689 |
|
|
}
|
690 |
|
|
#endif
|
691 |
|
|
|
692 |
|
|
|
693 |
|
|
if (status & ADAP_CHK_INT) {
|
694 |
|
|
|
695 |
|
|
int i;
|
696 |
|
|
__u32 check_reason;
|
697 |
|
|
|
698 |
|
|
check_reason=ti->mmio + ntohs(readw(ti->sram + ACA_OFFSET + ACA_RW +WWCR_EVEN));
|
699 |
|
|
|
700 |
|
|
DPRINTK("Adapter check interrupt\n");
|
701 |
|
|
DPRINTK("8 reason bytes follow: ");
|
702 |
|
|
for(i=0; i<8; i++, check_reason++)
|
703 |
|
|
printk("%02X ", (int)readb(check_reason));
|
704 |
|
|
printk("\n");
|
705 |
|
|
|
706 |
|
|
writeb((~ADAP_CHK_INT), ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD);
|
707 |
|
|
writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN);
|
708 |
|
|
dev->interrupt=0;
|
709 |
|
|
|
710 |
|
|
} else if (readb(ti->mmio + ACA_OFFSET + ACA_RW + ISRP_EVEN)
|
711 |
|
|
& (TCR_INT | ERR_INT | ACCESS_INT)) {
|
712 |
|
|
|
713 |
|
|
DPRINTK("adapter error: ISRP_EVEN : %02x\n",
|
714 |
|
|
(int)readb(ti->mmio + ACA_OFFSET + ACA_RW + ISRP_EVEN));
|
715 |
|
|
writeb(~(TCR_INT | ERR_INT | ACCESS_INT),
|
716 |
|
|
ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_EVEN);
|
717 |
|
|
writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN);
|
718 |
|
|
dev->interrupt=0;
|
719 |
|
|
|
720 |
|
|
} else if (status
|
721 |
|
|
& (SRB_RESP_INT | ASB_FREE_INT | ARB_CMD_INT | SSB_RESP_INT)) {
|
722 |
|
|
/* SRB, ASB, ARB or SSB response */
|
723 |
|
|
|
724 |
|
|
if (status & SRB_RESP_INT) { /* SRB response */
|
725 |
|
|
|
726 |
|
|
switch(readb(ti->srb)) { /* SRB command check */
|
727 |
|
|
|
728 |
|
|
case XMIT_DIR_FRAME: {
|
729 |
|
|
unsigned char xmit_ret_code;
|
730 |
|
|
|
731 |
|
|
xmit_ret_code=readb(ti->srb + offsetof(struct srb_xmit, ret_code));
|
732 |
|
|
if (xmit_ret_code != 0xff) {
|
733 |
|
|
DPRINTK("error on xmit_dir_frame request: %02X\n",
|
734 |
|
|
xmit_ret_code);
|
735 |
|
|
if (ti->current_skb) {
|
736 |
|
|
dev_kfree_skb(ti->current_skb, FREE_WRITE);
|
737 |
|
|
ti->current_skb=NULL;
|
738 |
|
|
}
|
739 |
|
|
dev->tbusy=0;
|
740 |
|
|
if (ti->readlog_pending) tr_readlog(dev);
|
741 |
|
|
}
|
742 |
|
|
}
|
743 |
|
|
break;
|
744 |
|
|
|
745 |
|
|
case XMIT_UI_FRAME: {
|
746 |
|
|
unsigned char xmit_ret_code;
|
747 |
|
|
|
748 |
|
|
xmit_ret_code=readb(ti->srb + offsetof(struct srb_xmit, ret_code));
|
749 |
|
|
if (xmit_ret_code != 0xff) {
|
750 |
|
|
DPRINTK("error on xmit_ui_frame request: %02X\n",
|
751 |
|
|
xmit_ret_code);
|
752 |
|
|
if (ti->current_skb) {
|
753 |
|
|
dev_kfree_skb(ti->current_skb, FREE_WRITE);
|
754 |
|
|
ti->current_skb=NULL;
|
755 |
|
|
}
|
756 |
|
|
dev->tbusy=0;
|
757 |
|
|
if (ti->readlog_pending) tr_readlog(dev);
|
758 |
|
|
}
|
759 |
|
|
}
|
760 |
|
|
break;
|
761 |
|
|
|
762 |
|
|
case DIR_OPEN_ADAPTER: {
|
763 |
|
|
unsigned char open_ret_code;
|
764 |
|
|
__u16 open_error_code;
|
765 |
|
|
|
766 |
|
|
ti->srb=ti->sram+ntohs(readw(ti->init_srb +offsetof(struct srb_open_response, srb_addr)));
|
767 |
|
|
ti->ssb=ti->sram+ntohs(readw(ti->init_srb +offsetof(struct srb_open_response, ssb_addr)));
|
768 |
|
|
ti->arb=ti->sram+ntohs(readw(ti->init_srb +offsetof(struct srb_open_response, arb_addr)));
|
769 |
|
|
ti->asb=ti->sram+ntohs(readw(ti->init_srb +offsetof(struct srb_open_response, asb_addr)));
|
770 |
|
|
ti->current_skb=NULL;
|
771 |
|
|
|
772 |
|
|
open_ret_code = readb(ti->init_srb +offsetof(struct srb_open_response, ret_code));
|
773 |
|
|
open_error_code = ntohs(readw(ti->init_srb +offsetof(struct srb_open_response, error_code)));
|
774 |
|
|
|
775 |
|
|
if (open_ret_code==7) {
|
776 |
|
|
|
777 |
|
|
if (!ti->auto_ringspeedsave && (open_error_code==0x24)) {
|
778 |
|
|
DPRINTK("open failed: Adapter speed must match ring "
|
779 |
|
|
"speed if Automatic Ring Speed Save is disabled\n");
|
780 |
|
|
ti->open_status=FAILURE;
|
781 |
|
|
wake_up(&ti->wait_for_reset);
|
782 |
|
|
} else if (open_error_code==0x24)
|
783 |
|
|
DPRINTK("retrying open to adjust to ring speed\n");
|
784 |
|
|
else if ((open_error_code==0x2d) && ti->auto_ringspeedsave)
|
785 |
|
|
DPRINTK("No signal detected for Auto Speed Detection\n");
|
786 |
|
|
else DPRINTK("Unrecoverable error: error code = %04x\n",
|
787 |
|
|
open_error_code);
|
788 |
|
|
|
789 |
|
|
} else if (!open_ret_code) {
|
790 |
|
|
#if !TR_NEWFORMAT
|
791 |
|
|
DPRINTK("board opened...\n");
|
792 |
|
|
#else
|
793 |
|
|
DPRINTK("Adapter initialized and opened.\n");
|
794 |
|
|
#endif
|
795 |
|
|
writeb(~(SRB_RESP_INT),
|
796 |
|
|
ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD);
|
797 |
|
|
writeb(~(CMD_IN_SRB),
|
798 |
|
|
ti->mmio + ACA_OFFSET + ACA_RESET + ISRA_ODD);
|
799 |
|
|
open_sap(EXTENDED_SAP,dev);
|
800 |
|
|
|
801 |
|
|
/* YdW probably hates me */
|
802 |
|
|
goto skip_reset;
|
803 |
|
|
} else
|
804 |
|
|
DPRINTK("open failed: ret_code = %02X, retrying\n",
|
805 |
|
|
open_ret_code);
|
806 |
|
|
|
807 |
|
|
if (ti->open_status != FAILURE) {
|
808 |
|
|
tr_timer.expires=jiffies+TR_RETRY_INTERVAL;
|
809 |
|
|
tr_timer.data=(unsigned long)dev;
|
810 |
|
|
tr_timer.next=tr_timer.prev=NULL;
|
811 |
|
|
add_timer(&tr_timer);
|
812 |
|
|
}
|
813 |
|
|
|
814 |
|
|
}
|
815 |
|
|
break;
|
816 |
|
|
|
817 |
|
|
case DIR_CLOSE_ADAPTER:
|
818 |
|
|
wake_up(&ti->wait_for_tok_int);
|
819 |
|
|
break;
|
820 |
|
|
|
821 |
|
|
case DLC_OPEN_SAP:
|
822 |
|
|
if (readb(ti->srb+offsetof(struct dlc_open_sap, ret_code))) {
|
823 |
|
|
DPRINTK("open_sap failed: ret_code = %02X,retrying\n",
|
824 |
|
|
(int)readb(ti->srb+offsetof(struct dlc_open_sap, ret_code)));
|
825 |
|
|
tr_timer.expires=jiffies+TR_RETRY_INTERVAL;
|
826 |
|
|
tr_timer.data=(unsigned long)dev;
|
827 |
|
|
tr_timer.next=tr_timer.prev=NULL;
|
828 |
|
|
add_timer(&tr_timer);
|
829 |
|
|
} else {
|
830 |
|
|
ti->exsap_station_id=
|
831 |
|
|
readw(ti->srb+offsetof(struct dlc_open_sap, station_id));
|
832 |
|
|
ti->open_status=SUCCESS; /* TR adapter is now available */
|
833 |
|
|
wake_up(&ti->wait_for_reset);
|
834 |
|
|
}
|
835 |
|
|
break;
|
836 |
|
|
|
837 |
|
|
case DIR_INTERRUPT:
|
838 |
|
|
case DIR_MOD_OPEN_PARAMS:
|
839 |
|
|
case DIR_SET_GRP_ADDR:
|
840 |
|
|
case DIR_SET_FUNC_ADDR:
|
841 |
|
|
case DLC_CLOSE_SAP:
|
842 |
|
|
if (readb(ti->srb+offsetof(struct srb_interrupt, ret_code)))
|
843 |
|
|
DPRINTK("error on %02X: %02X\n",
|
844 |
|
|
(int)readb(ti->srb+offsetof(struct srb_interrupt, command)),
|
845 |
|
|
(int)readb(ti->srb+offsetof(struct srb_interrupt, ret_code)));
|
846 |
|
|
break;
|
847 |
|
|
|
848 |
|
|
case DIR_READ_LOG:
|
849 |
|
|
if (readb(ti->srb+offsetof(struct srb_read_log, ret_code)))
|
850 |
|
|
DPRINTK("error on dir_read_log: %02X\n",
|
851 |
|
|
(int)readb(ti->srb+offsetof(struct srb_read_log, ret_code)));
|
852 |
|
|
else
|
853 |
|
|
DPRINTK(
|
854 |
|
|
"Line errors %02X, Internal errors %02X, Burst errors %02X\n"
|
855 |
|
|
"A/C errors %02X, Abort delimiters %02X, Lost frames %02X\n"
|
856 |
|
|
"Receive congestion count %02X, Frame copied errors %02X\n"
|
857 |
|
|
"Frequency errors %02X, Token errors %02X\n",
|
858 |
|
|
(int)readb(ti->srb+offsetof(struct srb_read_log,
|
859 |
|
|
line_errors)),
|
860 |
|
|
(int)readb(ti->srb+offsetof(struct srb_read_log,
|
861 |
|
|
internal_errors)),
|
862 |
|
|
(int)readb(ti->srb+offsetof(struct srb_read_log,
|
863 |
|
|
burst_errors)),
|
864 |
|
|
(int)readb(ti->srb+offsetof(struct srb_read_log, A_C_errors)),
|
865 |
|
|
(int)readb(ti->srb+offsetof(struct srb_read_log,
|
866 |
|
|
abort_delimiters)),
|
867 |
|
|
(int)readb(ti->srb+offsetof(struct srb_read_log,
|
868 |
|
|
lost_frames)),
|
869 |
|
|
(int)readb(ti->srb+offsetof(struct srb_read_log,
|
870 |
|
|
recv_congest_count)),
|
871 |
|
|
(int)readb(ti->srb+offsetof(struct srb_read_log,
|
872 |
|
|
frame_copied_errors)),
|
873 |
|
|
(int)readb(ti->srb+offsetof(struct srb_read_log,
|
874 |
|
|
frequency_errors)),
|
875 |
|
|
(int)readb(ti->srb+offsetof(struct srb_read_log,
|
876 |
|
|
token_errors)));
|
877 |
|
|
dev->tbusy=0;
|
878 |
|
|
break;
|
879 |
|
|
|
880 |
|
|
default:
|
881 |
|
|
DPRINTK("Unknown command %02X encountered\n",
|
882 |
|
|
(int)readb(ti->srb));
|
883 |
|
|
|
884 |
|
|
} /* SRB command check */
|
885 |
|
|
|
886 |
|
|
writeb(~CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_RESET + ISRA_ODD);
|
887 |
|
|
writeb(~SRB_RESP_INT, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD);
|
888 |
|
|
|
889 |
|
|
skip_reset:
|
890 |
|
|
} /* SRB response */
|
891 |
|
|
|
892 |
|
|
if (status & ASB_FREE_INT) { /* ASB response */
|
893 |
|
|
|
894 |
|
|
switch(readb(ti->asb)) { /* ASB command check */
|
895 |
|
|
|
896 |
|
|
case REC_DATA:
|
897 |
|
|
case XMIT_UI_FRAME:
|
898 |
|
|
case XMIT_DIR_FRAME:
|
899 |
|
|
break;
|
900 |
|
|
|
901 |
|
|
default:
|
902 |
|
|
DPRINTK("unknown command in asb %02X\n",
|
903 |
|
|
(int)readb(ti->asb));
|
904 |
|
|
|
905 |
|
|
} /* ASB command check */
|
906 |
|
|
|
907 |
|
|
if (readb(ti->asb+2)!=0xff) /* checks ret_code */
|
908 |
|
|
DPRINTK("ASB error %02X in cmd %02X\n",
|
909 |
|
|
(int)readb(ti->asb+2),(int)readb(ti->asb));
|
910 |
|
|
writeb(~ASB_FREE_INT, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD);
|
911 |
|
|
|
912 |
|
|
} /* ASB response */
|
913 |
|
|
|
914 |
|
|
if (status & ARB_CMD_INT) { /* ARB response */
|
915 |
|
|
|
916 |
|
|
switch (readb(ti->arb)) { /* ARB command check */
|
917 |
|
|
|
918 |
|
|
case DLC_STATUS:
|
919 |
|
|
DPRINTK("DLC_STATUS new status: %02X on station %02X\n",
|
920 |
|
|
ntohs(readw(ti->arb + offsetof(struct arb_dlc_status, status))),
|
921 |
|
|
ntohs(readw(ti->arb
|
922 |
|
|
+offsetof(struct arb_dlc_status, station_id))));
|
923 |
|
|
break;
|
924 |
|
|
|
925 |
|
|
case REC_DATA:
|
926 |
|
|
tr_rx(dev);
|
927 |
|
|
break;
|
928 |
|
|
|
929 |
|
|
case RING_STAT_CHANGE: {
|
930 |
|
|
unsigned short ring_status;
|
931 |
|
|
|
932 |
|
|
ring_status=ntohs(readw(ti->arb
|
933 |
|
|
+offsetof(struct arb_ring_stat_change, ring_status)));
|
934 |
|
|
|
935 |
|
|
if (ring_status & (SIGNAL_LOSS | LOBE_FAULT)) {
|
936 |
|
|
|
937 |
|
|
DPRINTK("Signal loss/Lobe fault\n");
|
938 |
|
|
DPRINTK("We try to reopen the adapter.\n");
|
939 |
|
|
tr_timer.expires=jiffies+TR_RETRY_INTERVAL;
|
940 |
|
|
tr_timer.data=(unsigned long)dev;
|
941 |
|
|
tr_timer.next=tr_timer.prev=NULL;
|
942 |
|
|
add_timer(&tr_timer);
|
943 |
|
|
|
944 |
|
|
} else if (ring_status & (HARD_ERROR | XMIT_BEACON
|
945 |
|
|
| AUTO_REMOVAL | REMOVE_RECV | RING_RECOVER))
|
946 |
|
|
DPRINTK("New ring status: %02X\n", ring_status);
|
947 |
|
|
|
948 |
|
|
if (ring_status & LOG_OVERFLOW) {
|
949 |
|
|
if (dev->tbusy)
|
950 |
|
|
ti->readlog_pending = 1;
|
951 |
|
|
else
|
952 |
|
|
tr_readlog(dev);
|
953 |
|
|
}
|
954 |
|
|
}
|
955 |
|
|
break;
|
956 |
|
|
|
957 |
|
|
case XMIT_DATA_REQ:
|
958 |
|
|
tr_tx(dev);
|
959 |
|
|
break;
|
960 |
|
|
|
961 |
|
|
default:
|
962 |
|
|
DPRINTK("Unknown command %02X in arb\n",
|
963 |
|
|
(int)readb(ti->arb));
|
964 |
|
|
break;
|
965 |
|
|
|
966 |
|
|
} /* ARB command check */
|
967 |
|
|
|
968 |
|
|
writeb(~ARB_CMD_INT, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD);
|
969 |
|
|
writeb(ARB_FREE, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
|
970 |
|
|
|
971 |
|
|
} /* ARB response */
|
972 |
|
|
|
973 |
|
|
if (status & SSB_RESP_INT) { /* SSB response */
|
974 |
|
|
unsigned char retcode;
|
975 |
|
|
switch (readb(ti->ssb)) { /* SSB command check */
|
976 |
|
|
|
977 |
|
|
case XMIT_DIR_FRAME:
|
978 |
|
|
case XMIT_UI_FRAME:
|
979 |
|
|
retcode = readb(ti->ssb+2);
|
980 |
|
|
if (retcode && (retcode != 0x22)) /* checks ret_code */
|
981 |
|
|
DPRINTK("xmit ret_code: %02X xmit error code: %02X\n",
|
982 |
|
|
(int)retcode, (int)readb(ti->ssb+6));
|
983 |
|
|
else ti->tr_stats.tx_packets++;
|
984 |
|
|
break;
|
985 |
|
|
|
986 |
|
|
case XMIT_XID_CMD:
|
987 |
|
|
DPRINTK("xmit xid ret_code: %02X\n", (int)readb(ti->ssb+2));
|
988 |
|
|
|
989 |
|
|
default:
|
990 |
|
|
DPRINTK("Unknown command %02X in ssb\n", (int)readb(ti->ssb));
|
991 |
|
|
|
992 |
|
|
} /* SSB command check */
|
993 |
|
|
|
994 |
|
|
writeb(~SSB_RESP_INT, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD);
|
995 |
|
|
writeb(SSB_FREE, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
|
996 |
|
|
|
997 |
|
|
} /* SSB response */
|
998 |
|
|
|
999 |
|
|
} /* SRB, ARB, ASB or SSB response */
|
1000 |
|
|
|
1001 |
|
|
dev->interrupt=0;
|
1002 |
|
|
writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN);
|
1003 |
|
|
break;
|
1004 |
|
|
|
1005 |
|
|
case FIRST_INT:
|
1006 |
|
|
initial_tok_int(dev);
|
1007 |
|
|
break;
|
1008 |
|
|
|
1009 |
|
|
default:
|
1010 |
|
|
DPRINTK("Unexpected interrupt from tr adapter\n");
|
1011 |
|
|
|
1012 |
|
|
}
|
1013 |
|
|
}
|
1014 |
|
|
|
1015 |
|
|
static void initial_tok_int(struct device *dev)
|
1016 |
|
|
{
|
1017 |
|
|
|
1018 |
|
|
__u32 encoded_addr;
|
1019 |
|
|
__u32 hw_encoded_addr;
|
1020 |
|
|
struct tok_info *ti;
|
1021 |
|
|
|
1022 |
|
|
ti=(struct tok_info *) dev->priv;
|
1023 |
|
|
|
1024 |
|
|
writeb(~INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_EVEN);
|
1025 |
|
|
|
1026 |
|
|
/* Reset interrupt for ISA boards */
|
1027 |
|
|
if (ti->global_int_enable) outb(0,ti->global_int_enable);
|
1028 |
|
|
|
1029 |
|
|
ti->do_tok_int=NOT_FIRST;
|
1030 |
|
|
|
1031 |
|
|
#ifndef TR_NEWFORMAT
|
1032 |
|
|
DPRINTK("Initial tok int received\n");
|
1033 |
|
|
#endif
|
1034 |
|
|
|
1035 |
|
|
/* we assign the address for ISA devices; set RRR even to D000 for
|
1036 |
|
|
shared RAM address */
|
1037 |
|
|
if(!ti->sram) {
|
1038 |
|
|
writeb(ti->sram_base, ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN);
|
1039 |
|
|
ti->sram=((__u32)ti->sram_base << 12);
|
1040 |
|
|
}
|
1041 |
|
|
ti->init_srb=ti->sram
|
1042 |
|
|
+ntohs((unsigned short)readw(ti->mmio+ ACA_OFFSET + WRBR_EVEN));
|
1043 |
|
|
SET_PAGE(ntohs((unsigned short)readw(ti->mmio+ACA_OFFSET + WRBR_EVEN)));
|
1044 |
|
|
|
1045 |
|
|
#if TR_VERBOSE
|
1046 |
|
|
{
|
1047 |
|
|
int i;
|
1048 |
|
|
DPRINTK("init_srb(%p):", ti->init_srb);
|
1049 |
|
|
for (i=0;i<17;i++) printk("%02X ", (int)readb(ti->init_srb+i));
|
1050 |
|
|
printk("\n");
|
1051 |
|
|
}
|
1052 |
|
|
#endif
|
1053 |
|
|
|
1054 |
|
|
hw_encoded_addr = readw(ti->init_srb
|
1055 |
|
|
+ offsetof(struct srb_init_response, encoded_address));
|
1056 |
|
|
|
1057 |
|
|
#if !TR_NEWFORMAT
|
1058 |
|
|
DPRINTK("srb_init_response->encoded_address: %04X\n", hw_encoded_addr);
|
1059 |
|
|
DPRINTK("ntohs(srb_init_response->encoded_address): %04X\n",
|
1060 |
|
|
ntohs(hw_encoded_addr));
|
1061 |
|
|
#endif
|
1062 |
|
|
|
1063 |
|
|
encoded_addr=(ti->sram + ntohs(hw_encoded_addr));
|
1064 |
|
|
|
1065 |
|
|
#if !TR_NEWFORMAT
|
1066 |
|
|
DPRINTK("encoded addr (%04X,%04X,%08X): ", hw_encoded_addr,
|
1067 |
|
|
ntohs(hw_encoded_addr), encoded_addr);
|
1068 |
|
|
#else
|
1069 |
|
|
DPRINTK("Initial interrupt : shared RAM located at %08X.\n", encoded_addr);
|
1070 |
|
|
#endif
|
1071 |
|
|
|
1072 |
|
|
ti->auto_ringspeedsave=readb(ti->init_srb
|
1073 |
|
|
+offsetof(struct srb_init_response, init_status_2)) & 0x4 ? TRUE : FALSE;
|
1074 |
|
|
|
1075 |
|
|
#if !TR_NEWFORMAT
|
1076 |
|
|
for(i=0;i<TR_ALEN;i++) {
|
1077 |
|
|
dev->dev_addr[i]=readb(encoded_addr + i);
|
1078 |
|
|
printk("%02X%s", dev->dev_addr[i], (i==TR_ALEN-1) ? "" : ":" );
|
1079 |
|
|
}
|
1080 |
|
|
printk("\n");
|
1081 |
|
|
#endif
|
1082 |
|
|
|
1083 |
|
|
tok_open_adapter((unsigned long)dev);
|
1084 |
|
|
}
|
1085 |
|
|
|
1086 |
|
|
static int tok_init_card(struct device *dev)
|
1087 |
|
|
{
|
1088 |
|
|
struct tok_info *ti;
|
1089 |
|
|
short PIOaddr;
|
1090 |
|
|
int i;
|
1091 |
|
|
PIOaddr = dev->base_addr;
|
1092 |
|
|
ti=(struct tok_info *) dev->priv;
|
1093 |
|
|
|
1094 |
|
|
/* Special processing for first interrupt after reset */
|
1095 |
|
|
ti->do_tok_int=FIRST_INT;
|
1096 |
|
|
|
1097 |
|
|
/* Reset adapter */
|
1098 |
|
|
dev->tbusy=1; /* nothing can be done before reset and open completed */
|
1099 |
|
|
|
1100 |
|
|
#ifdef ENABLE_PAGING
|
1101 |
|
|
if(ti->page_mask)
|
1102 |
|
|
writeb(SRPR_ENABLE_PAGING, ti->mmio + ACA_OFFSET + ACA_RW + SRPR_EVEN);
|
1103 |
|
|
#endif
|
1104 |
|
|
|
1105 |
|
|
writeb(~INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_EVEN);
|
1106 |
|
|
|
1107 |
|
|
#if !TR_NEWFORMAT
|
1108 |
|
|
DPRINTK("resetting card\n");
|
1109 |
|
|
#endif
|
1110 |
|
|
|
1111 |
|
|
outb(0, PIOaddr+ADAPTRESET);
|
1112 |
|
|
for (i=jiffies+TR_RESET_INTERVAL; jiffies<=i;); /* wait 50ms */
|
1113 |
|
|
outb(0,PIOaddr+ADAPTRESETREL);
|
1114 |
|
|
|
1115 |
|
|
#if !TR_NEWFORMAT
|
1116 |
|
|
DPRINTK("card reset\n");
|
1117 |
|
|
#endif
|
1118 |
|
|
|
1119 |
|
|
ti->open_status=IN_PROGRESS;
|
1120 |
|
|
writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN);
|
1121 |
|
|
return 0;
|
1122 |
|
|
}
|
1123 |
|
|
|
1124 |
|
|
static void open_sap(unsigned char type,struct device *dev)
|
1125 |
|
|
{
|
1126 |
|
|
int i;
|
1127 |
|
|
struct tok_info *ti=(struct tok_info *) dev->priv;
|
1128 |
|
|
|
1129 |
|
|
SET_PAGE(ti->srb);
|
1130 |
|
|
for (i=0; i<sizeof(struct dlc_open_sap); i++)
|
1131 |
|
|
writeb(0, ti->srb+i);
|
1132 |
|
|
|
1133 |
|
|
writeb(DLC_OPEN_SAP, ti->srb + offsetof(struct dlc_open_sap, command));
|
1134 |
|
|
writew(htons(MAX_I_FIELD),
|
1135 |
|
|
ti->srb + offsetof(struct dlc_open_sap, max_i_field));
|
1136 |
|
|
writeb(SAP_OPEN_IND_SAP | SAP_OPEN_PRIORITY,
|
1137 |
|
|
ti->srb + offsetof(struct dlc_open_sap, sap_options));
|
1138 |
|
|
writeb(SAP_OPEN_STATION_CNT,
|
1139 |
|
|
ti->srb + offsetof(struct dlc_open_sap, station_count));
|
1140 |
|
|
writeb(type, ti->srb + offsetof(struct dlc_open_sap, sap_value));
|
1141 |
|
|
|
1142 |
|
|
writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
|
1143 |
|
|
|
1144 |
|
|
}
|
1145 |
|
|
|
1146 |
|
|
void tok_open_adapter(unsigned long dev_addr)
|
1147 |
|
|
{
|
1148 |
|
|
|
1149 |
|
|
struct device *dev=(struct device *)dev_addr;
|
1150 |
|
|
struct tok_info *ti;
|
1151 |
|
|
int i;
|
1152 |
|
|
|
1153 |
|
|
ti=(struct tok_info *) dev->priv;
|
1154 |
|
|
|
1155 |
|
|
#if !TR_NEWFORMAT
|
1156 |
|
|
DPRINTK("now opening the board...\n");
|
1157 |
|
|
#endif
|
1158 |
|
|
|
1159 |
|
|
writeb(~SRB_RESP_INT, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD);
|
1160 |
|
|
writeb(~CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_RESET + ISRA_ODD);
|
1161 |
|
|
|
1162 |
|
|
for (i=0; i<sizeof(struct dir_open_adapter); i++)
|
1163 |
|
|
writeb(0, ti->init_srb+i);
|
1164 |
|
|
|
1165 |
|
|
writeb(DIR_OPEN_ADAPTER,
|
1166 |
|
|
ti->init_srb + offsetof(struct dir_open_adapter, command));
|
1167 |
|
|
writew(htons(OPEN_PASS_BCON_MAC),
|
1168 |
|
|
ti->init_srb + offsetof(struct dir_open_adapter, open_options));
|
1169 |
|
|
writew(htons(NUM_RCV_BUF),
|
1170 |
|
|
ti->init_srb + offsetof(struct dir_open_adapter, num_rcv_buf));
|
1171 |
|
|
writew(htons(RCV_BUF_LEN),
|
1172 |
|
|
ti->init_srb + offsetof(struct dir_open_adapter, rcv_buf_len));
|
1173 |
|
|
writew(htons(DHB_LENGTH),
|
1174 |
|
|
ti->init_srb + offsetof(struct dir_open_adapter, dhb_length));
|
1175 |
|
|
writeb(NUM_DHB,
|
1176 |
|
|
ti->init_srb + offsetof(struct dir_open_adapter, num_dhb));
|
1177 |
|
|
writeb(DLC_MAX_SAP,
|
1178 |
|
|
ti->init_srb + offsetof(struct dir_open_adapter, dlc_max_sap));
|
1179 |
|
|
writeb(DLC_MAX_STA,
|
1180 |
|
|
ti->init_srb + offsetof(struct dir_open_adapter, dlc_max_sta));
|
1181 |
|
|
|
1182 |
|
|
ti->srb=ti->init_srb; /* We use this one in the interrupt handler */
|
1183 |
|
|
|
1184 |
|
|
writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN);
|
1185 |
|
|
writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
|
1186 |
|
|
|
1187 |
|
|
}
|
1188 |
|
|
|
1189 |
|
|
static void tr_tx(struct device *dev)
|
1190 |
|
|
{
|
1191 |
|
|
struct tok_info *ti=(struct tok_info *) dev->priv;
|
1192 |
|
|
struct trh_hdr *trhdr=(struct trh_hdr *)ti->current_skb->data;
|
1193 |
|
|
unsigned int hdr_len;
|
1194 |
|
|
__u32 dhb;
|
1195 |
|
|
unsigned char xmit_command;
|
1196 |
|
|
int i;
|
1197 |
|
|
struct trllc *llc;
|
1198 |
|
|
|
1199 |
|
|
if (readb(ti->asb + offsetof(struct asb_xmit_resp, ret_code))!=0xFF)
|
1200 |
|
|
DPRINTK("ASB not free !!!\n");
|
1201 |
|
|
|
1202 |
|
|
/* in providing the transmit interrupts,
|
1203 |
|
|
is telling us it is ready for data and
|
1204 |
|
|
providing a shared memory address for us
|
1205 |
|
|
to stuff with data. Here we compute the
|
1206 |
|
|
effective address where we will place data.*/
|
1207 |
|
|
dhb=ti->sram
|
1208 |
|
|
+ntohs(readw(ti->arb + offsetof(struct arb_xmit_req, dhb_address)));
|
1209 |
|
|
llc = (struct trllc *) &(ti->current_skb->data[sizeof(struct trh_hdr)]);
|
1210 |
|
|
|
1211 |
|
|
xmit_command = readb(ti->srb + offsetof(struct srb_xmit, command));
|
1212 |
|
|
|
1213 |
|
|
writeb(xmit_command, ti->asb + offsetof(struct asb_xmit_resp, command));
|
1214 |
|
|
writew(readb(ti->srb + offsetof(struct srb_xmit, station_id)),
|
1215 |
|
|
ti->asb + offsetof(struct asb_xmit_resp, station_id));
|
1216 |
|
|
writeb(llc->ssap, ti->asb + offsetof(struct asb_xmit_resp, rsap_value));
|
1217 |
|
|
writeb(readb(ti->srb + offsetof(struct srb_xmit, cmd_corr)),
|
1218 |
|
|
ti->asb + offsetof(struct asb_xmit_resp, cmd_corr));
|
1219 |
|
|
writeb(0, ti->asb + offsetof(struct asb_xmit_resp, ret_code));
|
1220 |
|
|
|
1221 |
|
|
if ((xmit_command==XMIT_XID_CMD) || (xmit_command==XMIT_TEST_CMD)) {
|
1222 |
|
|
|
1223 |
|
|
writew(htons(0x11),
|
1224 |
|
|
ti->asb + offsetof(struct asb_xmit_resp, frame_length));
|
1225 |
|
|
writeb(0x0e, ti->asb + offsetof(struct asb_xmit_resp, hdr_length));
|
1226 |
|
|
writeb(AC, dhb);
|
1227 |
|
|
writeb(LLC_FRAME, dhb+1);
|
1228 |
|
|
|
1229 |
|
|
for (i=0; i<TR_ALEN; i++) writeb((int)0x0FF, dhb+i+2);
|
1230 |
|
|
for (i=0; i<TR_ALEN; i++) writeb(0, dhb+i+TR_ALEN+2);
|
1231 |
|
|
|
1232 |
|
|
writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
|
1233 |
|
|
return;
|
1234 |
|
|
|
1235 |
|
|
}
|
1236 |
|
|
|
1237 |
|
|
/* the token ring packet is copied from sk_buff to the adapter
|
1238 |
|
|
buffer identified in the command data received with the
|
1239 |
|
|
interrupt. The sk_buff area was set up with a maximum
|
1240 |
|
|
sized route information field so here we must compress
|
1241 |
|
|
out the extra (all) rif fields. */
|
1242 |
|
|
/* nb/dwm .... I re-arranged code here to avoid copy of extra
|
1243 |
|
|
bytes, ended up with fewer statements as well. */
|
1244 |
|
|
|
1245 |
|
|
/* TR arch. identifies if RIF present by high bit of source
|
1246 |
|
|
address. So here we check if RIF present */
|
1247 |
|
|
|
1248 |
|
|
if (!(trhdr->saddr[0] & 0x80)) { /* RIF present : preserve it */
|
1249 |
|
|
hdr_len=sizeof(struct trh_hdr)-18;
|
1250 |
|
|
|
1251 |
|
|
#if TR_VERBOSE
|
1252 |
|
|
DPRINTK("hdr_length: %d, frame length: %ld\n", hdr_len,
|
1253 |
|
|
ti->current_skb->len-18);
|
1254 |
|
|
#endif
|
1255 |
|
|
} else hdr_len=((ntohs(trhdr->rcf) & TR_RCF_LEN_MASK)>>8)
|
1256 |
|
|
+sizeof(struct trh_hdr)-18;
|
1257 |
|
|
|
1258 |
|
|
/* header length including rif is computed above, now move the data
|
1259 |
|
|
and set fields appropriately. */
|
1260 |
|
|
for (i=0; i<hdr_len; i++)
|
1261 |
|
|
writeb(*(unsigned char *)(ti->current_skb->data +i), dhb++);
|
1262 |
|
|
|
1263 |
|
|
writeb(hdr_len, ti->asb + offsetof(struct asb_xmit_resp, hdr_length));
|
1264 |
|
|
writew(htons(ti->current_skb->len-sizeof(struct trh_hdr)+hdr_len),
|
1265 |
|
|
ti->asb + offsetof(struct asb_xmit_resp, frame_length));
|
1266 |
|
|
|
1267 |
|
|
/* now copy the actual packet data next to hdr */
|
1268 |
|
|
for (i=0; i<ti->current_skb->len-sizeof(struct trh_hdr); i++)
|
1269 |
|
|
writeb(*(unsigned char *)(ti->current_skb->data +sizeof(struct trh_hdr)+i),
|
1270 |
|
|
dhb+i);
|
1271 |
|
|
|
1272 |
|
|
writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
|
1273 |
|
|
dev->tbusy=0;
|
1274 |
|
|
dev_kfree_skb(ti->current_skb,FREE_WRITE);
|
1275 |
|
|
ti->current_skb=NULL;
|
1276 |
|
|
mark_bh(NET_BH);
|
1277 |
|
|
if (ti->readlog_pending) tr_readlog(dev);
|
1278 |
|
|
}
|
1279 |
|
|
|
1280 |
|
|
static void tr_rx(struct device *dev)
|
1281 |
|
|
{
|
1282 |
|
|
int i;
|
1283 |
|
|
struct tok_info *ti=(struct tok_info *) dev->priv;
|
1284 |
|
|
__u32 rbuffer;
|
1285 |
|
|
__u32 llc;
|
1286 |
|
|
unsigned char *data;
|
1287 |
|
|
unsigned int rbuffer_len, lan_hdr_len;
|
1288 |
|
|
unsigned int arb_frame_len;
|
1289 |
|
|
struct sk_buff *skb;
|
1290 |
|
|
unsigned int skb_size = 0;
|
1291 |
|
|
int is8022 = 0;
|
1292 |
|
|
|
1293 |
|
|
rbuffer=(ti->sram
|
1294 |
|
|
+ntohs(readw(ti->arb + offsetof(struct arb_rec_req, rec_buf_addr))));
|
1295 |
|
|
|
1296 |
|
|
if(readb(ti->asb + offsetof(struct asb_rec, ret_code))!=0xFF)
|
1297 |
|
|
DPRINTK("ASB not free !!!\n");
|
1298 |
|
|
|
1299 |
|
|
writeb(REC_DATA,
|
1300 |
|
|
ti->asb + offsetof(struct asb_rec, command));
|
1301 |
|
|
writew(readw(ti->arb + offsetof(struct arb_rec_req, station_id)),
|
1302 |
|
|
ti->asb + offsetof(struct asb_rec, station_id));
|
1303 |
|
|
writew(readw(ti->arb + offsetof(struct arb_rec_req, rec_buf_addr)),
|
1304 |
|
|
ti->asb + offsetof(struct asb_rec, rec_buf_addr));
|
1305 |
|
|
|
1306 |
|
|
lan_hdr_len=readb(ti->arb + offsetof(struct arb_rec_req, lan_hdr_len));
|
1307 |
|
|
|
1308 |
|
|
llc=(rbuffer+offsetof(struct rec_buf, data) + lan_hdr_len);
|
1309 |
|
|
|
1310 |
|
|
#if TR_VERBOSE
|
1311 |
|
|
DPRINTK("offsetof data: %02X lan_hdr_len: %02X\n",
|
1312 |
|
|
(unsigned int)offsetof(struct rec_buf,data), (unsigned int)lan_hdr_len);
|
1313 |
|
|
DPRINTK("llc: %08X rec_buf_addr: %04X ti->sram: %p\n", llc,
|
1314 |
|
|
ntohs(readw(ti->arb + offsetof(struct arb_rec_req, rec_buf_addr))),
|
1315 |
|
|
ti->sram);
|
1316 |
|
|
DPRINTK("dsap: %02X, ssap: %02X, llc: %02X, protid: %02X%02X%02X, "
|
1317 |
|
|
"ethertype: %04X\n",
|
1318 |
|
|
(int)readb(llc + offsetof(struct trllc, dsap)),
|
1319 |
|
|
(int)readb(llc + offsetof(struct trllc, ssap)),
|
1320 |
|
|
(int)readb(llc + offsetof(struct trllc, protid)),
|
1321 |
|
|
(int)readb(llc + offsetof(struct trllc, protid)+1),
|
1322 |
|
|
(int)readb(llc + offsetof(struct trllc, protid)+2),
|
1323 |
|
|
(int)readw(llc + offsetof(struct trllc, ethertype)));
|
1324 |
|
|
#endif
|
1325 |
|
|
|
1326 |
|
|
if (readb(llc + offsetof(struct trllc, llc))!=UI_CMD) {
|
1327 |
|
|
#if !TR_FILTERNONUI
|
1328 |
|
|
DPRINTK("non-UI frame arrived. dropped. llc= %02X\n",
|
1329 |
|
|
(int)readb(llc + offsetof(struct trllc, llc))
|
1330 |
|
|
#endif
|
1331 |
|
|
writeb(DATA_LOST, ti->asb + offsetof(struct asb_rec, ret_code));
|
1332 |
|
|
ti->tr_stats.rx_dropped++;
|
1333 |
|
|
writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
|
1334 |
|
|
return;
|
1335 |
|
|
}
|
1336 |
|
|
|
1337 |
|
|
if ((readb(llc + offsetof(struct trllc, dsap))!=0xAA) ||
|
1338 |
|
|
(readb(llc + offsetof(struct trllc, ssap))!=0xAA)) {
|
1339 |
|
|
is8022 = 1;
|
1340 |
|
|
}
|
1341 |
|
|
|
1342 |
|
|
#if TR_VERBOSE
|
1343 |
|
|
if ((readb(llc + offsetof(struct trllc, dsap))!=0xAA) ||
|
1344 |
|
|
(readb(llc + offsetof(struct trllc, ssap))!=0xAA)) {
|
1345 |
|
|
|
1346 |
|
|
__u32 trhhdr;
|
1347 |
|
|
|
1348 |
|
|
trhhdr=(rbuffer+offsetof(struct rec_buf,data));
|
1349 |
|
|
|
1350 |
|
|
DPRINTK("Probably non-IP frame received.\n");
|
1351 |
|
|
DPRINTK("ssap: %02X dsap: %02X saddr: %02X:%02X:%02X:%02X:%02X:%02X "
|
1352 |
|
|
"daddr: %02X:%02X:%02X:%02X:%02X:%02X\n",
|
1353 |
|
|
(int)readb(llc + offsetof(struct trllc, ssap)),
|
1354 |
|
|
(int)readb(llc + offsetof(struct trllc, dsap)),
|
1355 |
|
|
(int)readb(trhhdr + offsetof(struct trh_hdr, saddr)),
|
1356 |
|
|
(int)readb(trhhdr + offsetof(struct trh_hdr, saddr)+1),
|
1357 |
|
|
(int)readb(trhhdr + offsetof(struct trh_hdr, saddr)+2),
|
1358 |
|
|
(int)readb(trhhdr + offsetof(struct trh_hdr, saddr)+3),
|
1359 |
|
|
(int)readb(trhhdr + offsetof(struct trh_hdr, saddr)+4),
|
1360 |
|
|
(int)readb(trhhdr + offsetof(struct trh_hdr, saddr)+5),
|
1361 |
|
|
(int)readb(trhhdr + offsetof(struct trh_hdr, daddr)),
|
1362 |
|
|
(int)readb(trhhdr + offsetof(struct trh_hdr, daddr)+1),
|
1363 |
|
|
(int)readb(trhhdr + offsetof(struct trh_hdr, daddr)+2),
|
1364 |
|
|
(int)readb(trhhdr + offsetof(struct trh_hdr, daddr)+3),
|
1365 |
|
|
(int)readb(trhhdr + offsetof(struct trh_hdr, daddr)+4),
|
1366 |
|
|
(int)readb(trhhdr + offsetof(struct trh_hdr, daddr)+5));
|
1367 |
|
|
}
|
1368 |
|
|
#endif
|
1369 |
|
|
|
1370 |
|
|
arb_frame_len=ntohs(readw(ti->arb+offsetof(struct arb_rec_req, frame_len)));
|
1371 |
|
|
skb_size = arb_frame_len-lan_hdr_len+sizeof(struct trh_hdr);
|
1372 |
|
|
if (is8022) {
|
1373 |
|
|
skb_size += sizeof(struct trllc);
|
1374 |
|
|
}
|
1375 |
|
|
|
1376 |
|
|
if (!(skb=dev_alloc_skb(skb_size))) {
|
1377 |
|
|
DPRINTK("out of memory. frame dropped.\n");
|
1378 |
|
|
ti->tr_stats.rx_dropped++;
|
1379 |
|
|
writeb(DATA_LOST, ti->asb + offsetof(struct asb_rec, ret_code));
|
1380 |
|
|
writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
|
1381 |
|
|
return;
|
1382 |
|
|
}
|
1383 |
|
|
|
1384 |
|
|
skb_put(skb, skb_size);
|
1385 |
|
|
skb->dev=dev;
|
1386 |
|
|
|
1387 |
|
|
data=skb->data;
|
1388 |
|
|
for (i=0; i<lan_hdr_len; i++)
|
1389 |
|
|
data[i]=readb(rbuffer + offsetof(struct rec_buf, data)+i);
|
1390 |
|
|
|
1391 |
|
|
if (lan_hdr_len<sizeof(struct trh_hdr))
|
1392 |
|
|
memset(data+lan_hdr_len, 0, sizeof(struct trh_hdr)-lan_hdr_len);
|
1393 |
|
|
|
1394 |
|
|
data+=sizeof(struct trh_hdr);
|
1395 |
|
|
rbuffer_len=ntohs(readw(rbuffer + offsetof(struct rec_buf, buf_len)))
|
1396 |
|
|
-lan_hdr_len;
|
1397 |
|
|
if (is8022) {
|
1398 |
|
|
struct trllc *local_llc = (struct trllc *)data;
|
1399 |
|
|
memset(local_llc, 0, sizeof(*local_llc));
|
1400 |
|
|
local_llc->ethertype = htons(ETH_P_TR_802_2);
|
1401 |
|
|
data += sizeof(struct trllc);
|
1402 |
|
|
}
|
1403 |
|
|
|
1404 |
|
|
#if TR_VERBOSE
|
1405 |
|
|
DPRINTK("rbuffer_len: %d, data: %p\n", rbuffer_len, data);
|
1406 |
|
|
#endif
|
1407 |
|
|
|
1408 |
|
|
for (i=0; i<rbuffer_len; i++)
|
1409 |
|
|
data[i]=readb(rbuffer+ offsetof(struct rec_buf, data)+lan_hdr_len+i);
|
1410 |
|
|
data+=rbuffer_len;
|
1411 |
|
|
|
1412 |
|
|
while (readw(rbuffer + offsetof(struct rec_buf, buf_ptr))) {
|
1413 |
|
|
rbuffer=(ti->sram
|
1414 |
|
|
+ntohs(readw(rbuffer + offsetof(struct rec_buf, buf_ptr)))-2);
|
1415 |
|
|
rbuffer_len=ntohs(readw(rbuffer + offsetof(struct rec_buf, buf_len)));
|
1416 |
|
|
for (i=0; i<rbuffer_len; i++)
|
1417 |
|
|
data[i]=readb(rbuffer + offsetof(struct rec_buf, data)+i);
|
1418 |
|
|
data+=rbuffer_len;
|
1419 |
|
|
|
1420 |
|
|
#if TR_VERBOSE
|
1421 |
|
|
DPRINTK("buf_ptr: %d, data =%p\n",
|
1422 |
|
|
ntohs((rbuffer + offsetof(struct rec_buf, buf_ptr))), data);
|
1423 |
|
|
#endif
|
1424 |
|
|
}
|
1425 |
|
|
|
1426 |
|
|
writeb(0, ti->asb + offsetof(struct asb_rec, ret_code));
|
1427 |
|
|
|
1428 |
|
|
writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
|
1429 |
|
|
|
1430 |
|
|
ti->tr_stats.rx_packets++;
|
1431 |
|
|
|
1432 |
|
|
skb->protocol=tr_type_trans(skb,dev);
|
1433 |
|
|
netif_rx(skb);
|
1434 |
|
|
|
1435 |
|
|
}
|
1436 |
|
|
|
1437 |
|
|
static int tok_send_packet(struct sk_buff *skb, struct device *dev)
|
1438 |
|
|
{
|
1439 |
|
|
struct tok_info *ti;
|
1440 |
|
|
ti=(struct tok_info *) dev->priv;
|
1441 |
|
|
|
1442 |
|
|
if (dev->tbusy) {
|
1443 |
|
|
int ticks_waited;
|
1444 |
|
|
|
1445 |
|
|
ticks_waited=jiffies - dev->trans_start;
|
1446 |
|
|
if (ticks_waited<TR_BUSY_INTERVAL) return 1;
|
1447 |
|
|
|
1448 |
|
|
DPRINTK("Arrg. Transmitter busy for more than 50 msec. "
|
1449 |
|
|
"Donald resets adapter, but resetting\n"
|
1450 |
|
|
"the IBM tokenring adapter takes a long time."
|
1451 |
|
|
" It might not even help when the\n"
|
1452 |
|
|
"ring is very busy, so we just wait a little longer "
|
1453 |
|
|
"and hope for the best.\n");
|
1454 |
|
|
dev->trans_start+=5; /* we fake the transmission start time... */
|
1455 |
|
|
return 1;
|
1456 |
|
|
}
|
1457 |
|
|
|
1458 |
|
|
/* Donald does this, so we do too. */
|
1459 |
|
|
if (skb==NULL) {
|
1460 |
|
|
dev_tint(dev);
|
1461 |
|
|
return 0;
|
1462 |
|
|
}
|
1463 |
|
|
|
1464 |
|
|
if (set_bit(0,(void *)&dev->tbusy)!=0) {
|
1465 |
|
|
dev_kfree_skb(skb, FREE_WRITE);
|
1466 |
|
|
DPRINTK("Transmitter access conflict\n");
|
1467 |
|
|
} else {
|
1468 |
|
|
/* Save skb; we'll need it when the adapter asks for the data */
|
1469 |
|
|
ti->current_skb=skb;
|
1470 |
|
|
writeb(XMIT_UI_FRAME, ti->srb + offsetof(struct srb_xmit, command));
|
1471 |
|
|
writew(ti->exsap_station_id, ti->srb
|
1472 |
|
|
+offsetof(struct srb_xmit, station_id));
|
1473 |
|
|
writeb(CMD_IN_SRB, (ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD));
|
1474 |
|
|
dev->trans_start=jiffies;
|
1475 |
|
|
}
|
1476 |
|
|
|
1477 |
|
|
return 0;
|
1478 |
|
|
}
|
1479 |
|
|
|
1480 |
|
|
void tr_readlog(struct device *dev) {
|
1481 |
|
|
struct tok_info *ti;
|
1482 |
|
|
ti=(struct tok_info *) dev->priv;
|
1483 |
|
|
|
1484 |
|
|
ti->readlog_pending = 0;
|
1485 |
|
|
writeb(DIR_READ_LOG, ti->srb);
|
1486 |
|
|
writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN);
|
1487 |
|
|
writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
|
1488 |
|
|
dev->tbusy=1; /* really srb busy... */
|
1489 |
|
|
}
|
1490 |
|
|
|
1491 |
|
|
/* tok_get_stats(): Basically a scaffold routine which will return
|
1492 |
|
|
the address of the tr_statistics structure associated with
|
1493 |
|
|
this device -- the tr.... structure is a ethnet look-alike
|
1494 |
|
|
so at least for this iteration may suffice. */
|
1495 |
|
|
|
1496 |
|
|
static struct enet_statistics * tok_get_stats(struct device *dev) {
|
1497 |
|
|
|
1498 |
|
|
struct tok_info *toki;
|
1499 |
|
|
toki=(struct tok_info *) dev->priv;
|
1500 |
|
|
return (struct enet_statistics *) &toki->tr_stats;
|
1501 |
|
|
}
|
1502 |
|
|
|
1503 |
|
|
#ifdef MODULE
|
1504 |
|
|
|
1505 |
|
|
|
1506 |
|
|
static char devicename[9] = { 0, };
|
1507 |
|
|
static struct device dev_ibmtr = {
|
1508 |
|
|
devicename, /* device name is inserted by linux/drivers/net/net_init.c */
|
1509 |
|
|
0, 0, 0, 0,
|
1510 |
|
|
0, 0,
|
1511 |
|
|
0, 0, 0, NULL, tok_probe };
|
1512 |
|
|
|
1513 |
|
|
static int io = 0xa20;
|
1514 |
|
|
static char *device = NULL;
|
1515 |
|
|
|
1516 |
|
|
int init_module(void)
|
1517 |
|
|
{
|
1518 |
|
|
if (device)
|
1519 |
|
|
strcpy(dev_ibmtr.name,device);
|
1520 |
|
|
else if (!dev_ibmtr.name[0]) strcpy(dev_ibmtr.name,"tr0");
|
1521 |
|
|
|
1522 |
|
|
if (io == 0)
|
1523 |
|
|
printk("ibmtr: You should not use auto-probing with insmod!\n");
|
1524 |
|
|
dev_ibmtr.base_addr = io;
|
1525 |
|
|
dev_ibmtr.irq = 0;
|
1526 |
|
|
|
1527 |
|
|
if (register_netdev(&dev_ibmtr) != 0) {
|
1528 |
|
|
printk("ibmtr: No adapters were found.\n");
|
1529 |
|
|
return -EIO;
|
1530 |
|
|
}
|
1531 |
|
|
return 0;
|
1532 |
|
|
}
|
1533 |
|
|
|
1534 |
|
|
void cleanup_module(void)
|
1535 |
|
|
{
|
1536 |
|
|
unregister_netdev(&dev_ibmtr);
|
1537 |
|
|
|
1538 |
|
|
/* If we don't do this, we can't re-insmod it later. */
|
1539 |
|
|
free_irq(dev_ibmtr.irq, NULL);
|
1540 |
|
|
irq2dev_map[dev_ibmtr.irq] = NULL;
|
1541 |
|
|
release_region(dev_ibmtr.base_addr, TR_IO_EXTENT);
|
1542 |
|
|
}
|
1543 |
|
|
#endif /* MODULE */
|