Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | ** ----------------------------------------------------------------------------- | |
3 | ** | |
4 | ** Perle Specialix driver for Linux | |
5 | ** Ported from existing RIO Driver for SCO sources. | |
6 | * | |
7 | * (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK. | |
8 | * | |
9 | * This program is free software; you can redistribute it and/or modify | |
10 | * it under the terms of the GNU General Public License as published by | |
11 | * the Free Software Foundation; either version 2 of the License, or | |
12 | * (at your option) any later version. | |
13 | * | |
14 | * This program is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | * GNU General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU General Public License | |
20 | * along with this program; if not, write to the Free Software | |
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
22 | ** | |
23 | ** Module : rioboot.c | |
24 | ** SID : 1.3 | |
25 | ** Last Modified : 11/6/98 10:33:36 | |
26 | ** Retrieved : 11/6/98 10:33:48 | |
27 | ** | |
28 | ** ident @(#)rioboot.c 1.3 | |
29 | ** | |
30 | ** ----------------------------------------------------------------------------- | |
31 | */ | |
32 | ||
1da177e4 LT |
33 | #include <linux/module.h> |
34 | #include <linux/slab.h> | |
b6c6b602 AC |
35 | #include <linux/termios.h> |
36 | #include <linux/serial.h> | |
655fdeab | 37 | #include <linux/vmalloc.h> |
b6c6b602 AC |
38 | #include <asm/semaphore.h> |
39 | #include <linux/generic_serial.h> | |
1da177e4 LT |
40 | #include <linux/errno.h> |
41 | #include <linux/interrupt.h> | |
b6c6b602 | 42 | #include <linux/delay.h> |
1da177e4 LT |
43 | #include <asm/io.h> |
44 | #include <asm/system.h> | |
45 | #include <asm/string.h> | |
b6c6b602 | 46 | #include <asm/uaccess.h> |
1da177e4 LT |
47 | |
48 | ||
49 | #include "linux_compat.h" | |
50 | #include "rio_linux.h" | |
1da177e4 LT |
51 | #include "pkt.h" |
52 | #include "daemon.h" | |
53 | #include "rio.h" | |
54 | #include "riospace.h" | |
1da177e4 LT |
55 | #include "cmdpkt.h" |
56 | #include "map.h" | |
1da177e4 LT |
57 | #include "rup.h" |
58 | #include "port.h" | |
59 | #include "riodrvr.h" | |
60 | #include "rioinfo.h" | |
61 | #include "func.h" | |
62 | #include "errors.h" | |
63 | #include "pci.h" | |
64 | ||
65 | #include "parmmap.h" | |
66 | #include "unixrup.h" | |
67 | #include "board.h" | |
68 | #include "host.h" | |
1da177e4 LT |
69 | #include "phb.h" |
70 | #include "link.h" | |
71 | #include "cmdblk.h" | |
72 | #include "route.h" | |
73 | ||
d886cb58 | 74 | static int RIOBootComplete(struct rio_info *p, struct Host *HostP, unsigned int Rup, struct PktCmd __iomem *PktCmdP); |
3b8e3f1e | 75 | |
b6c6b602 | 76 | static const unsigned char RIOAtVec2Ctrl[] = { |
3b8e3f1e AC |
77 | /* 0 */ INTERRUPT_DISABLE, |
78 | /* 1 */ INTERRUPT_DISABLE, | |
79 | /* 2 */ INTERRUPT_DISABLE, | |
80 | /* 3 */ INTERRUPT_DISABLE, | |
81 | /* 4 */ INTERRUPT_DISABLE, | |
82 | /* 5 */ INTERRUPT_DISABLE, | |
83 | /* 6 */ INTERRUPT_DISABLE, | |
84 | /* 7 */ INTERRUPT_DISABLE, | |
85 | /* 8 */ INTERRUPT_DISABLE, | |
86 | /* 9 */ IRQ_9 | INTERRUPT_ENABLE, | |
1da177e4 | 87 | /* 10 */ INTERRUPT_DISABLE, |
3b8e3f1e AC |
88 | /* 11 */ IRQ_11 | INTERRUPT_ENABLE, |
89 | /* 12 */ IRQ_12 | INTERRUPT_ENABLE, | |
1da177e4 LT |
90 | /* 13 */ INTERRUPT_DISABLE, |
91 | /* 14 */ INTERRUPT_DISABLE, | |
3b8e3f1e | 92 | /* 15 */ IRQ_15 | INTERRUPT_ENABLE |
1da177e4 LT |
93 | }; |
94 | ||
b6c6b602 AC |
95 | /** |
96 | * RIOBootCodeRTA - Load RTA boot code | |
97 | * @p: RIO to load | |
98 | * @rbp: Download descriptor | |
99 | * | |
100 | * Called when the user process initiates booting of the card firmware. | |
101 | * Lads the firmware | |
102 | */ | |
103 | ||
104 | int RIOBootCodeRTA(struct rio_info *p, struct DownLoad * rbp) | |
1da177e4 LT |
105 | { |
106 | int offset; | |
107 | ||
3b8e3f1e | 108 | func_enter(); |
1da177e4 | 109 | |
b6c6b602 | 110 | rio_dprintk(RIO_DEBUG_BOOT, "Data at user address %p\n", rbp->DataP); |
1da177e4 LT |
111 | |
112 | /* | |
3b8e3f1e AC |
113 | ** Check that we have set asside enough memory for this |
114 | */ | |
115 | if (rbp->Count > SIXTY_FOUR_K) { | |
116 | rio_dprintk(RIO_DEBUG_BOOT, "RTA Boot Code Too Large!\n"); | |
1da177e4 | 117 | p->RIOError.Error = HOST_FILE_TOO_LARGE; |
3b8e3f1e | 118 | func_exit(); |
1da177e4 LT |
119 | return -ENOMEM; |
120 | } | |
121 | ||
3b8e3f1e AC |
122 | if (p->RIOBooting) { |
123 | rio_dprintk(RIO_DEBUG_BOOT, "RTA Boot Code : BUSY BUSY BUSY!\n"); | |
1da177e4 | 124 | p->RIOError.Error = BOOT_IN_PROGRESS; |
3b8e3f1e | 125 | func_exit(); |
1da177e4 LT |
126 | return -EBUSY; |
127 | } | |
128 | ||
129 | /* | |
3b8e3f1e AC |
130 | ** The data we load in must end on a (RTA_BOOT_DATA_SIZE) byte boundary, |
131 | ** so calculate how far we have to move the data up the buffer | |
132 | ** to achieve this. | |
133 | */ | |
134 | offset = (RTA_BOOT_DATA_SIZE - (rbp->Count % RTA_BOOT_DATA_SIZE)) % RTA_BOOT_DATA_SIZE; | |
1da177e4 LT |
135 | |
136 | /* | |
3b8e3f1e AC |
137 | ** Be clean, and clear the 'unused' portion of the boot buffer, |
138 | ** because it will (eventually) be part of the Rta run time environment | |
139 | ** and so should be zeroed. | |
140 | */ | |
b6c6b602 | 141 | memset(p->RIOBootPackets, 0, offset); |
1da177e4 LT |
142 | |
143 | /* | |
b6c6b602 | 144 | ** Copy the data from user space into the array |
3b8e3f1e | 145 | */ |
1da177e4 | 146 | |
b6c6b602 | 147 | if (copy_from_user(((u8 *)p->RIOBootPackets) + offset, rbp->DataP, rbp->Count)) { |
3b8e3f1e | 148 | rio_dprintk(RIO_DEBUG_BOOT, "Bad data copy from user space\n"); |
1da177e4 | 149 | p->RIOError.Error = COPYIN_FAILED; |
3b8e3f1e | 150 | func_exit(); |
1da177e4 LT |
151 | return -EFAULT; |
152 | } | |
153 | ||
154 | /* | |
3b8e3f1e AC |
155 | ** Make sure that our copy of the size includes that offset we discussed |
156 | ** earlier. | |
157 | */ | |
158 | p->RIONumBootPkts = (rbp->Count + offset) / RTA_BOOT_DATA_SIZE; | |
159 | p->RIOBootCount = rbp->Count; | |
1da177e4 | 160 | |
1da177e4 LT |
161 | func_exit(); |
162 | return 0; | |
163 | } | |
164 | ||
b6c6b602 AC |
165 | /** |
166 | * rio_start_card_running - host card start | |
167 | * @HostP: The RIO to kick off | |
168 | * | |
169 | * Start a RIO processor unit running. Encapsulates the knowledge | |
170 | * of the card type. | |
171 | */ | |
172 | ||
3b8e3f1e | 173 | void rio_start_card_running(struct Host *HostP) |
1da177e4 | 174 | { |
3b8e3f1e | 175 | switch (HostP->Type) { |
1da177e4 | 176 | case RIO_AT: |
3b8e3f1e | 177 | rio_dprintk(RIO_DEBUG_BOOT, "Start ISA card running\n"); |
b6c6b602 | 178 | writeb(BOOT_FROM_RAM | EXTERNAL_BUS_ON | HostP->Mode | RIOAtVec2Ctrl[HostP->Ivec & 0xF], &HostP->Control); |
1da177e4 | 179 | break; |
1da177e4 | 180 | case RIO_PCI: |
3b8e3f1e AC |
181 | /* |
182 | ** PCI is much the same as MCA. Everything is once again memory | |
183 | ** mapped, so we are writing to memory registers instead of io | |
184 | ** ports. | |
185 | */ | |
186 | rio_dprintk(RIO_DEBUG_BOOT, "Start PCI card running\n"); | |
b6c6b602 | 187 | writeb(PCITpBootFromRam | PCITpBusEnable | HostP->Mode, &HostP->Control); |
1da177e4 LT |
188 | break; |
189 | default: | |
3b8e3f1e | 190 | rio_dprintk(RIO_DEBUG_BOOT, "Unknown host type %d\n", HostP->Type); |
1da177e4 LT |
191 | break; |
192 | } | |
1da177e4 LT |
193 | return; |
194 | } | |
195 | ||
196 | /* | |
197 | ** Load in the host boot code - load it directly onto all halted hosts | |
198 | ** of the correct type. | |
199 | ** | |
200 | ** Put your rubber pants on before messing with this code - even the magic | |
201 | ** numbers have trouble understanding what they are doing here. | |
202 | */ | |
b6c6b602 AC |
203 | |
204 | int RIOBootCodeHOST(struct rio_info *p, struct DownLoad *rbp) | |
1da177e4 | 205 | { |
b6c6b602 | 206 | struct Host *HostP; |
d886cb58 AV |
207 | u8 __iomem *Cad; |
208 | PARM_MAP __iomem *ParmMapP; | |
b6c6b602 | 209 | int RupN; |
1da177e4 | 210 | int PortN; |
b6c6b602 | 211 | unsigned int host; |
d886cb58 AV |
212 | u8 __iomem *StartP; |
213 | u8 __iomem *DestP; | |
1da177e4 | 214 | int wait_count; |
b6c6b602 AC |
215 | u16 OldParmMap; |
216 | u16 offset; /* It is very important that this is a u16 */ | |
217 | u8 *DownCode = NULL; | |
1da177e4 LT |
218 | unsigned long flags; |
219 | ||
3b8e3f1e | 220 | HostP = NULL; /* Assure the compiler we've initialized it */ |
b6c6b602 AC |
221 | |
222 | ||
223 | /* Walk the hosts */ | |
3b8e3f1e AC |
224 | for (host = 0; host < p->RIONumHosts; host++) { |
225 | rio_dprintk(RIO_DEBUG_BOOT, "Attempt to boot host %d\n", host); | |
1da177e4 | 226 | HostP = &p->RIOHosts[host]; |
1da177e4 | 227 | |
3b8e3f1e | 228 | rio_dprintk(RIO_DEBUG_BOOT, "Host Type = 0x%x, Mode = 0x%x, IVec = 0x%x\n", HostP->Type, HostP->Mode, HostP->Ivec); |
1da177e4 | 229 | |
b6c6b602 | 230 | /* Don't boot hosts already running */ |
3b8e3f1e AC |
231 | if ((HostP->Flags & RUN_STATE) != RC_WAITING) { |
232 | rio_dprintk(RIO_DEBUG_BOOT, "%s %d already running\n", "Host", host); | |
1da177e4 LT |
233 | continue; |
234 | } | |
235 | ||
236 | /* | |
b6c6b602 | 237 | ** Grab a pointer to the card (ioremapped) |
3b8e3f1e | 238 | */ |
1da177e4 LT |
239 | Cad = HostP->Caddr; |
240 | ||
241 | /* | |
3b8e3f1e AC |
242 | ** We are going to (try) and load in rbp->Count bytes. |
243 | ** The last byte will reside at p->RIOConf.HostLoadBase-1; | |
244 | ** Therefore, we need to start copying at address | |
245 | ** (caddr+p->RIOConf.HostLoadBase-rbp->Count) | |
246 | */ | |
b6c6b602 | 247 | StartP = &Cad[p->RIOConf.HostLoadBase - rbp->Count]; |
3b8e3f1e | 248 | |
b6c6b602 AC |
249 | rio_dprintk(RIO_DEBUG_BOOT, "kernel virtual address for host is %p\n", Cad); |
250 | rio_dprintk(RIO_DEBUG_BOOT, "kernel virtual address for download is %p\n", StartP); | |
3b8e3f1e AC |
251 | rio_dprintk(RIO_DEBUG_BOOT, "host loadbase is 0x%x\n", p->RIOConf.HostLoadBase); |
252 | rio_dprintk(RIO_DEBUG_BOOT, "size of download is 0x%x\n", rbp->Count); | |
253 | ||
b6c6b602 | 254 | /* Make sure it fits */ |
3b8e3f1e AC |
255 | if (p->RIOConf.HostLoadBase < rbp->Count) { |
256 | rio_dprintk(RIO_DEBUG_BOOT, "Bin too large\n"); | |
1da177e4 | 257 | p->RIOError.Error = HOST_FILE_TOO_LARGE; |
3b8e3f1e | 258 | func_exit(); |
1da177e4 LT |
259 | return -EFBIG; |
260 | } | |
261 | /* | |
3b8e3f1e AC |
262 | ** Ensure that the host really is stopped. |
263 | ** Disable it's external bus & twang its reset line. | |
264 | */ | |
d886cb58 | 265 | RIOHostReset(HostP->Type, HostP->CardP, HostP->Slot); |
1da177e4 LT |
266 | |
267 | /* | |
3b8e3f1e AC |
268 | ** Copy the data directly from user space to the SRAM. |
269 | ** This ain't going to be none too clever if the download | |
270 | ** code is bigger than this segment. | |
271 | */ | |
272 | rio_dprintk(RIO_DEBUG_BOOT, "Copy in code\n"); | |
1da177e4 | 273 | |
b6c6b602 AC |
274 | /* Buffer to local memory as we want to use I/O space and |
275 | some cards only do 8 or 16 bit I/O */ | |
1da177e4 | 276 | |
b6c6b602 AC |
277 | DownCode = vmalloc(rbp->Count); |
278 | if (!DownCode) { | |
279 | p->RIOError.Error = NOT_ENOUGH_CORE_FOR_PCI_COPY; | |
280 | func_exit(); | |
281 | return -ENOMEM; | |
282 | } | |
283 | if (copy_from_user(rbp->DataP, DownCode, rbp->Count)) { | |
284 | kfree(DownCode); | |
1da177e4 | 285 | p->RIOError.Error = COPYIN_FAILED; |
3b8e3f1e | 286 | func_exit(); |
1da177e4 LT |
287 | return -EFAULT; |
288 | } | |
b6c6b602 AC |
289 | HostP->Copy(DownCode, StartP, rbp->Count); |
290 | vfree(DownCode); | |
1da177e4 | 291 | |
3b8e3f1e | 292 | rio_dprintk(RIO_DEBUG_BOOT, "Copy completed\n"); |
1da177e4 LT |
293 | |
294 | /* | |
3b8e3f1e AC |
295 | ** S T O P ! |
296 | ** | |
297 | ** Upto this point the code has been fairly rational, and possibly | |
298 | ** even straight forward. What follows is a pile of crud that will | |
299 | ** magically turn into six bytes of transputer assembler. Normally | |
300 | ** you would expect an array or something, but, being me, I have | |
301 | ** chosen [been told] to use a technique whereby the startup code | |
302 | ** will be correct if we change the loadbase for the code. Which | |
303 | ** brings us onto another issue - the loadbase is the *end* of the | |
304 | ** code, not the start. | |
305 | ** | |
306 | ** If I were you I wouldn't start from here. | |
307 | */ | |
1da177e4 LT |
308 | |
309 | /* | |
3b8e3f1e AC |
310 | ** We now need to insert a short boot section into |
311 | ** the memory at the end of Sram2. This is normally (de)composed | |
312 | ** of the last eight bytes of the download code. The | |
313 | ** download has been assembled/compiled to expect to be | |
314 | ** loaded from 0x7FFF downwards. We have loaded it | |
315 | ** at some other address. The startup code goes into the small | |
316 | ** ram window at Sram2, in the last 8 bytes, which are really | |
317 | ** at addresses 0x7FF8-0x7FFF. | |
318 | ** | |
319 | ** If the loadbase is, say, 0x7C00, then we need to branch to | |
320 | ** address 0x7BFE to run the host.bin startup code. We assemble | |
321 | ** this jump manually. | |
322 | ** | |
323 | ** The two byte sequence 60 08 is loaded into memory at address | |
324 | ** 0x7FFE,F. This is a local branch to location 0x7FF8 (60 is nfix 0, | |
325 | ** which adds '0' to the .O register, complements .O, and then shifts | |
326 | ** it left by 4 bit positions, 08 is a jump .O+8 instruction. This will | |
327 | ** add 8 to .O (which was 0xFFF0), and will branch RELATIVE to the new | |
328 | ** location. Now, the branch starts from the value of .PC (or .IP or | |
329 | ** whatever the bloody register is called on this chip), and the .PC | |
330 | ** will be pointing to the location AFTER the branch, in this case | |
331 | ** .PC == 0x8000, so the branch will be to 0x8000+0xFFF8 = 0x7FF8. | |
332 | ** | |
333 | ** A long branch is coded at 0x7FF8. This consists of loading a four | |
334 | ** byte offset into .O using nfix (as above) and pfix operators. The | |
335 | ** pfix operates in exactly the same way as the nfix operator, but | |
336 | ** without the complement operation. The offset, of course, must be | |
337 | ** relative to the address of the byte AFTER the branch instruction, | |
338 | ** which will be (urm) 0x7FFC, so, our final destination of the branch | |
339 | ** (loadbase-2), has to be reached from here. Imagine that the loadbase | |
340 | ** is 0x7C00 (which it is), then we will need to branch to 0x7BFE (which | |
341 | ** is the first byte of the initial two byte short local branch of the | |
342 | ** download code). | |
343 | ** | |
344 | ** To code a jump from 0x7FFC (which is where the branch will start | |
345 | ** from) to 0x7BFE, we will need to branch 0xFC02 bytes (0x7FFC+0xFC02)= | |
346 | ** 0x7BFE. | |
347 | ** This will be coded as four bytes: | |
348 | ** 60 2C 20 02 | |
349 | ** being nfix .O+0 | |
350 | ** pfix .O+C | |
351 | ** pfix .O+0 | |
352 | ** jump .O+2 | |
353 | ** | |
354 | ** The nfix operator is used, so that the startup code will be | |
355 | ** compatible with the whole Tp family. (lies, damn lies, it'll never | |
356 | ** work in a month of Sundays). | |
357 | ** | |
358 | ** The nfix nyble is the 1s complement of the nyble value you | |
359 | ** want to load - in this case we wanted 'F' so we nfix loaded '0'. | |
360 | */ | |
1da177e4 LT |
361 | |
362 | ||
363 | /* | |
3b8e3f1e AC |
364 | ** Dest points to the top 8 bytes of Sram2. The Tp jumps |
365 | ** to 0x7FFE at reset time, and starts executing. This is | |
366 | ** a short branch to 0x7FF8, where a long branch is coded. | |
367 | */ | |
1da177e4 | 368 | |
d886cb58 | 369 | DestP = &Cad[0x7FF8]; /* <<<---- READ THE ABOVE COMMENTS */ |
1da177e4 LT |
370 | |
371 | #define NFIX(N) (0x60 | (N)) /* .O = (~(.O + N))<<4 */ | |
372 | #define PFIX(N) (0x20 | (N)) /* .O = (.O + N)<<4 */ | |
3b8e3f1e | 373 | #define JUMP(N) (0x00 | (N)) /* .PC = .PC + .O */ |
1da177e4 LT |
374 | |
375 | /* | |
3b8e3f1e AC |
376 | ** 0x7FFC is the address of the location following the last byte of |
377 | ** the four byte jump instruction. | |
378 | ** READ THE ABOVE COMMENTS | |
379 | ** | |
380 | ** offset is (TO-FROM) % MEMSIZE, but with compound buggering about. | |
381 | ** Memsize is 64K for this range of Tp, so offset is a short (unsigned, | |
382 | ** cos I don't understand 2's complement). | |
383 | */ | |
384 | offset = (p->RIOConf.HostLoadBase - 2) - 0x7FFC; | |
3b8e3f1e | 385 | |
554b7c80 | 386 | writeb(NFIX(((unsigned short) (~offset) >> (unsigned short) 12) & 0xF), DestP); |
b6c6b602 AC |
387 | writeb(PFIX((offset >> 8) & 0xF), DestP + 1); |
388 | writeb(PFIX((offset >> 4) & 0xF), DestP + 2); | |
389 | writeb(JUMP(offset & 0xF), DestP + 3); | |
390 | ||
391 | writeb(NFIX(0), DestP + 6); | |
392 | writeb(JUMP(8), DestP + 7); | |
3b8e3f1e AC |
393 | |
394 | rio_dprintk(RIO_DEBUG_BOOT, "host loadbase is 0x%x\n", p->RIOConf.HostLoadBase); | |
395 | rio_dprintk(RIO_DEBUG_BOOT, "startup offset is 0x%x\n", offset); | |
1da177e4 LT |
396 | |
397 | /* | |
3b8e3f1e AC |
398 | ** Flag what is going on |
399 | */ | |
1da177e4 LT |
400 | HostP->Flags &= ~RUN_STATE; |
401 | HostP->Flags |= RC_STARTUP; | |
402 | ||
403 | /* | |
3b8e3f1e AC |
404 | ** Grab a copy of the current ParmMap pointer, so we |
405 | ** can tell when it has changed. | |
406 | */ | |
b6c6b602 | 407 | OldParmMap = readw(&HostP->__ParmMapR); |
1da177e4 | 408 | |
3b8e3f1e | 409 | rio_dprintk(RIO_DEBUG_BOOT, "Original parmmap is 0x%x\n", OldParmMap); |
1da177e4 LT |
410 | |
411 | /* | |
3b8e3f1e AC |
412 | ** And start it running (I hope). |
413 | ** As there is nothing dodgy or obscure about the | |
414 | ** above code, this is guaranteed to work every time. | |
415 | */ | |
416 | rio_dprintk(RIO_DEBUG_BOOT, "Host Type = 0x%x, Mode = 0x%x, IVec = 0x%x\n", HostP->Type, HostP->Mode, HostP->Ivec); | |
1da177e4 LT |
417 | |
418 | rio_start_card_running(HostP); | |
419 | ||
3b8e3f1e | 420 | rio_dprintk(RIO_DEBUG_BOOT, "Set control port\n"); |
1da177e4 LT |
421 | |
422 | /* | |
3b8e3f1e AC |
423 | ** Now, wait for upto five seconds for the Tp to setup the parmmap |
424 | ** pointer: | |
425 | */ | |
b6c6b602 AC |
426 | for (wait_count = 0; (wait_count < p->RIOConf.StartupTime) && (readw(&HostP->__ParmMapR) == OldParmMap); wait_count++) { |
427 | rio_dprintk(RIO_DEBUG_BOOT, "Checkout %d, 0x%x\n", wait_count, readw(&HostP->__ParmMapR)); | |
428 | mdelay(100); | |
1da177e4 LT |
429 | |
430 | } | |
431 | ||
432 | /* | |
3b8e3f1e AC |
433 | ** If the parmmap pointer is unchanged, then the host code |
434 | ** has crashed & burned in a really spectacular way | |
435 | */ | |
b6c6b602 AC |
436 | if (readw(&HostP->__ParmMapR) == OldParmMap) { |
437 | rio_dprintk(RIO_DEBUG_BOOT, "parmmap 0x%x\n", readw(&HostP->__ParmMapR)); | |
3b8e3f1e AC |
438 | rio_dprintk(RIO_DEBUG_BOOT, "RIO Mesg Run Fail\n"); |
439 | HostP->Flags &= ~RUN_STATE; | |
440 | HostP->Flags |= RC_STUFFED; | |
d886cb58 | 441 | RIOHostReset( HostP->Type, HostP->CardP, HostP->Slot ); |
b6c6b602 AC |
442 | continue; |
443 | } | |
3b8e3f1e | 444 | |
b6c6b602 | 445 | rio_dprintk(RIO_DEBUG_BOOT, "Running 0x%x\n", readw(&HostP->__ParmMapR)); |
1da177e4 LT |
446 | |
447 | /* | |
3b8e3f1e AC |
448 | ** Well, the board thought it was OK, and setup its parmmap |
449 | ** pointer. For the time being, we will pretend that this | |
450 | ** board is running, and check out what the error flag says. | |
451 | */ | |
1da177e4 LT |
452 | |
453 | /* | |
3b8e3f1e AC |
454 | ** Grab a 32 bit pointer to the parmmap structure |
455 | */ | |
d886cb58 | 456 | ParmMapP = (PARM_MAP __iomem *) RIO_PTR(Cad, readw(&HostP->__ParmMapR)); |
b6c6b602 | 457 | rio_dprintk(RIO_DEBUG_BOOT, "ParmMapP : %p\n", ParmMapP); |
d886cb58 | 458 | ParmMapP = (PARM_MAP __iomem *)(Cad + readw(&HostP->__ParmMapR)); |
b6c6b602 | 459 | rio_dprintk(RIO_DEBUG_BOOT, "ParmMapP : %p\n", ParmMapP); |
1da177e4 LT |
460 | |
461 | /* | |
3b8e3f1e AC |
462 | ** The links entry should be 0xFFFF; we set it up |
463 | ** with a mask to say how many PHBs to use, and | |
464 | ** which links to use. | |
465 | */ | |
b6c6b602 | 466 | if (readw(&ParmMapP->links) != 0xFFFF) { |
3b8e3f1e | 467 | rio_dprintk(RIO_DEBUG_BOOT, "RIO Mesg Run Fail %s\n", HostP->Name); |
b6c6b602 | 468 | rio_dprintk(RIO_DEBUG_BOOT, "Links = 0x%x\n", readw(&ParmMapP->links)); |
3b8e3f1e AC |
469 | HostP->Flags &= ~RUN_STATE; |
470 | HostP->Flags |= RC_STUFFED; | |
d886cb58 | 471 | RIOHostReset( HostP->Type, HostP->CardP, HostP->Slot ); |
b6c6b602 AC |
472 | continue; |
473 | } | |
3b8e3f1e | 474 | |
b6c6b602 | 475 | writew(RIO_LINK_ENABLE, &ParmMapP->links); |
1da177e4 LT |
476 | |
477 | /* | |
3b8e3f1e AC |
478 | ** now wait for the card to set all the parmmap->XXX stuff |
479 | ** this is a wait of upto two seconds.... | |
480 | */ | |
481 | rio_dprintk(RIO_DEBUG_BOOT, "Looking for init_done - %d ticks\n", p->RIOConf.StartupTime); | |
1da177e4 | 482 | HostP->timeout_id = 0; |
b6c6b602 | 483 | for (wait_count = 0; (wait_count < p->RIOConf.StartupTime) && !readw(&ParmMapP->init_done); wait_count++) { |
3b8e3f1e | 484 | rio_dprintk(RIO_DEBUG_BOOT, "Waiting for init_done\n"); |
b6c6b602 | 485 | mdelay(100); |
1da177e4 | 486 | } |
3b8e3f1e | 487 | rio_dprintk(RIO_DEBUG_BOOT, "OK! init_done!\n"); |
1da177e4 | 488 | |
b6c6b602 | 489 | if (readw(&ParmMapP->error) != E_NO_ERROR || !readw(&ParmMapP->init_done)) { |
3b8e3f1e AC |
490 | rio_dprintk(RIO_DEBUG_BOOT, "RIO Mesg Run Fail %s\n", HostP->Name); |
491 | rio_dprintk(RIO_DEBUG_BOOT, "Timedout waiting for init_done\n"); | |
492 | HostP->Flags &= ~RUN_STATE; | |
493 | HostP->Flags |= RC_STUFFED; | |
d886cb58 | 494 | RIOHostReset( HostP->Type, HostP->CardP, HostP->Slot ); |
b6c6b602 AC |
495 | continue; |
496 | } | |
1da177e4 | 497 | |
3b8e3f1e | 498 | rio_dprintk(RIO_DEBUG_BOOT, "Got init_done\n"); |
1da177e4 LT |
499 | |
500 | /* | |
3b8e3f1e AC |
501 | ** It runs! It runs! |
502 | */ | |
503 | rio_dprintk(RIO_DEBUG_BOOT, "Host ID %x Running\n", HostP->UniqueNum); | |
1da177e4 LT |
504 | |
505 | /* | |
3b8e3f1e AC |
506 | ** set the time period between interrupts. |
507 | */ | |
b6c6b602 | 508 | writew(p->RIOConf.Timer, &ParmMapP->timer); |
1da177e4 LT |
509 | |
510 | /* | |
3b8e3f1e | 511 | ** Translate all the 16 bit pointers in the __ParmMapR into |
b6c6b602 | 512 | ** 32 bit pointers for the driver in ioremap space. |
3b8e3f1e AC |
513 | */ |
514 | HostP->ParmMapP = ParmMapP; | |
d886cb58 AV |
515 | HostP->PhbP = (struct PHB __iomem *) RIO_PTR(Cad, readw(&ParmMapP->phb_ptr)); |
516 | HostP->RupP = (struct RUP __iomem *) RIO_PTR(Cad, readw(&ParmMapP->rups)); | |
517 | HostP->PhbNumP = (unsigned short __iomem *) RIO_PTR(Cad, readw(&ParmMapP->phb_num_ptr)); | |
518 | HostP->LinkStrP = (struct LPB __iomem *) RIO_PTR(Cad, readw(&ParmMapP->link_str_ptr)); | |
1da177e4 LT |
519 | |
520 | /* | |
3b8e3f1e AC |
521 | ** point the UnixRups at the real Rups |
522 | */ | |
523 | for (RupN = 0; RupN < MAX_RUP; RupN++) { | |
524 | HostP->UnixRups[RupN].RupP = &HostP->RupP[RupN]; | |
525 | HostP->UnixRups[RupN].Id = RupN + 1; | |
1da177e4 LT |
526 | HostP->UnixRups[RupN].BaseSysPort = NO_PORT; |
527 | spin_lock_init(&HostP->UnixRups[RupN].RupLock); | |
528 | } | |
529 | ||
3b8e3f1e AC |
530 | for (RupN = 0; RupN < LINKS_PER_UNIT; RupN++) { |
531 | HostP->UnixRups[RupN + MAX_RUP].RupP = &HostP->LinkStrP[RupN].rup; | |
532 | HostP->UnixRups[RupN + MAX_RUP].Id = 0; | |
533 | HostP->UnixRups[RupN + MAX_RUP].BaseSysPort = NO_PORT; | |
534 | spin_lock_init(&HostP->UnixRups[RupN + MAX_RUP].RupLock); | |
1da177e4 LT |
535 | } |
536 | ||
537 | /* | |
3b8e3f1e AC |
538 | ** point the PortP->Phbs at the real Phbs |
539 | */ | |
540 | for (PortN = p->RIOFirstPortsMapped; PortN < p->RIOLastPortsMapped + PORTS_PER_RTA; PortN++) { | |
541 | if (p->RIOPortp[PortN]->HostP == HostP) { | |
1da177e4 | 542 | struct Port *PortP = p->RIOPortp[PortN]; |
d886cb58 | 543 | struct PHB __iomem *PhbP; |
1da177e4 LT |
544 | /* int oldspl; */ |
545 | ||
3b8e3f1e | 546 | if (!PortP->Mapped) |
1da177e4 LT |
547 | continue; |
548 | ||
549 | PhbP = &HostP->PhbP[PortP->HostPort]; | |
550 | rio_spin_lock_irqsave(&PortP->portSem, flags); | |
551 | ||
552 | PortP->PhbP = PhbP; | |
553 | ||
d886cb58 AV |
554 | PortP->TxAdd = (u16 __iomem *) RIO_PTR(Cad, readw(&PhbP->tx_add)); |
555 | PortP->TxStart = (u16 __iomem *) RIO_PTR(Cad, readw(&PhbP->tx_start)); | |
556 | PortP->TxEnd = (u16 __iomem *) RIO_PTR(Cad, readw(&PhbP->tx_end)); | |
557 | PortP->RxRemove = (u16 __iomem *) RIO_PTR(Cad, readw(&PhbP->rx_remove)); | |
558 | PortP->RxStart = (u16 __iomem *) RIO_PTR(Cad, readw(&PhbP->rx_start)); | |
559 | PortP->RxEnd = (u16 __iomem *) RIO_PTR(Cad, readw(&PhbP->rx_end)); | |
1da177e4 LT |
560 | |
561 | rio_spin_unlock_irqrestore(&PortP->portSem, flags); | |
562 | /* | |
3b8e3f1e AC |
563 | ** point the UnixRup at the base SysPort |
564 | */ | |
565 | if (!(PortN % PORTS_PER_RTA)) | |
1da177e4 LT |
566 | HostP->UnixRups[PortP->RupNum].BaseSysPort = PortN; |
567 | } | |
568 | } | |
569 | ||
3b8e3f1e | 570 | rio_dprintk(RIO_DEBUG_BOOT, "Set the card running... \n"); |
1da177e4 | 571 | /* |
3b8e3f1e AC |
572 | ** last thing - show the world that everything is in place |
573 | */ | |
1da177e4 LT |
574 | HostP->Flags &= ~RUN_STATE; |
575 | HostP->Flags |= RC_RUNNING; | |
576 | } | |
577 | /* | |
3b8e3f1e AC |
578 | ** MPX always uses a poller. This is actually patched into the system |
579 | ** configuration and called directly from each clock tick. | |
580 | ** | |
581 | */ | |
1da177e4 LT |
582 | p->RIOPolling = 1; |
583 | ||
584 | p->RIOSystemUp++; | |
3b8e3f1e AC |
585 | |
586 | rio_dprintk(RIO_DEBUG_BOOT, "Done everything %x\n", HostP->Ivec); | |
587 | func_exit(); | |
1da177e4 LT |
588 | return 0; |
589 | } | |
590 | ||
591 | ||
592 | ||
b6c6b602 AC |
593 | /** |
594 | * RIOBootRup - Boot an RTA | |
595 | * @p: rio we are working with | |
596 | * @Rup: Rup number | |
597 | * @HostP: host object | |
598 | * @PacketP: packet to use | |
599 | * | |
600 | * If we have successfully processed this boot, then | |
601 | * return 1. If we havent, then return 0. | |
602 | */ | |
603 | ||
d886cb58 | 604 | int RIOBootRup(struct rio_info *p, unsigned int Rup, struct Host *HostP, struct PKT __iomem *PacketP) |
1da177e4 | 605 | { |
d886cb58 | 606 | struct PktCmd __iomem *PktCmdP = (struct PktCmd __iomem *) PacketP->data; |
1da177e4 LT |
607 | struct PktCmd_M *PktReplyP; |
608 | struct CmdBlk *CmdBlkP; | |
b6c6b602 | 609 | unsigned int sequence; |
1da177e4 | 610 | |
1da177e4 | 611 | /* |
3b8e3f1e AC |
612 | ** If we haven't been told what to boot, we can't boot it. |
613 | */ | |
614 | if (p->RIONumBootPkts == 0) { | |
615 | rio_dprintk(RIO_DEBUG_BOOT, "No RTA code to download yet\n"); | |
1da177e4 LT |
616 | return 0; |
617 | } | |
618 | ||
1da177e4 | 619 | /* |
3b8e3f1e AC |
620 | ** Special case of boot completed - if we get one of these then we |
621 | ** don't need a command block. For all other cases we do, so handle | |
622 | ** this first and then get a command block, then handle every other | |
623 | ** case, relinquishing the command block if disaster strikes! | |
624 | */ | |
b6c6b602 | 625 | if ((readb(&PacketP->len) & PKT_CMD_BIT) && (readb(&PktCmdP->Command) == BOOT_COMPLETED)) |
3b8e3f1e | 626 | return RIOBootComplete(p, HostP, Rup, PktCmdP); |
1da177e4 LT |
627 | |
628 | /* | |
b6c6b602 | 629 | ** Try to allocate a command block. This is in kernel space |
3b8e3f1e AC |
630 | */ |
631 | if (!(CmdBlkP = RIOGetCmdBlk())) { | |
632 | rio_dprintk(RIO_DEBUG_BOOT, "No command blocks to boot RTA! come back later.\n"); | |
1da177e4 LT |
633 | return 0; |
634 | } | |
635 | ||
636 | /* | |
3b8e3f1e AC |
637 | ** Fill in the default info on the command block |
638 | */ | |
554b7c80 | 639 | CmdBlkP->Packet.dest_unit = Rup < (unsigned short) MAX_RUP ? Rup : 0; |
1da177e4 | 640 | CmdBlkP->Packet.dest_port = BOOT_RUP; |
3b8e3f1e AC |
641 | CmdBlkP->Packet.src_unit = 0; |
642 | CmdBlkP->Packet.src_port = BOOT_RUP; | |
1da177e4 LT |
643 | |
644 | CmdBlkP->PreFuncP = CmdBlkP->PostFuncP = NULL; | |
3b8e3f1e | 645 | PktReplyP = (struct PktCmd_M *) CmdBlkP->Packet.data; |
1da177e4 LT |
646 | |
647 | /* | |
3b8e3f1e AC |
648 | ** process COMMANDS on the boot rup! |
649 | */ | |
b6c6b602 | 650 | if (readb(&PacketP->len) & PKT_CMD_BIT) { |
1da177e4 | 651 | /* |
3b8e3f1e AC |
652 | ** We only expect one type of command - a BOOT_REQUEST! |
653 | */ | |
b6c6b602 AC |
654 | if (readb(&PktCmdP->Command) != BOOT_REQUEST) { |
655 | rio_dprintk(RIO_DEBUG_BOOT, "Unexpected command %d on BOOT RUP %d of host %Zd\n", readb(&PktCmdP->Command), Rup, HostP - p->RIOHosts); | |
3b8e3f1e | 656 | RIOFreeCmdBlk(CmdBlkP); |
1da177e4 LT |
657 | return 1; |
658 | } | |
659 | ||
660 | /* | |
3b8e3f1e AC |
661 | ** Build a Boot Sequence command block |
662 | ** | |
3b8e3f1e AC |
663 | ** We no longer need to use "Boot Mode", we'll always allow |
664 | ** boot requests - the boot will not complete if the device | |
665 | ** appears in the bindings table. | |
3b8e3f1e AC |
666 | ** |
667 | ** We'll just (always) set the command field in packet reply | |
668 | ** to allow an attempted boot sequence : | |
669 | */ | |
1da177e4 LT |
670 | PktReplyP->Command = BOOT_SEQUENCE; |
671 | ||
672 | PktReplyP->BootSequence.NumPackets = p->RIONumBootPkts; | |
3b8e3f1e AC |
673 | PktReplyP->BootSequence.LoadBase = p->RIOConf.RtaLoadBase; |
674 | PktReplyP->BootSequence.CodeSize = p->RIOBootCount; | |
1da177e4 | 675 | |
3b8e3f1e | 676 | CmdBlkP->Packet.len = BOOT_SEQUENCE_LEN | PKT_CMD_BIT; |
1da177e4 | 677 | |
b6c6b602 | 678 | memcpy((void *) &CmdBlkP->Packet.data[BOOT_SEQUENCE_LEN], "BOOT", 4); |
1da177e4 | 679 | |
b6c6b602 | 680 | rio_dprintk(RIO_DEBUG_BOOT, "Boot RTA on Host %Zd Rup %d - %d (0x%x) packets to 0x%x\n", HostP - p->RIOHosts, Rup, p->RIONumBootPkts, p->RIONumBootPkts, p->RIOConf.RtaLoadBase); |
1da177e4 LT |
681 | |
682 | /* | |
3b8e3f1e AC |
683 | ** If this host is in slave mode, send the RTA an invalid boot |
684 | ** sequence command block to force it to kill the boot. We wait | |
685 | ** for half a second before sending this packet to prevent the RTA | |
686 | ** attempting to boot too often. The master host should then grab | |
687 | ** the RTA and make it its own. | |
688 | */ | |
1da177e4 | 689 | p->RIOBooting++; |
3b8e3f1e | 690 | RIOQueueCmdBlk(HostP, Rup, CmdBlkP); |
1da177e4 LT |
691 | return 1; |
692 | } | |
693 | ||
694 | /* | |
3b8e3f1e AC |
695 | ** It is a request for boot data. |
696 | */ | |
b6c6b602 | 697 | sequence = readw(&PktCmdP->Sequence); |
1da177e4 | 698 | |
b6c6b602 | 699 | rio_dprintk(RIO_DEBUG_BOOT, "Boot block %d on Host %Zd Rup%d\n", sequence, HostP - p->RIOHosts, Rup); |
1da177e4 | 700 | |
3b8e3f1e AC |
701 | if (sequence >= p->RIONumBootPkts) { |
702 | rio_dprintk(RIO_DEBUG_BOOT, "Got a request for packet %d, max is %d\n", sequence, p->RIONumBootPkts); | |
1da177e4 LT |
703 | } |
704 | ||
705 | PktReplyP->Sequence = sequence; | |
b6c6b602 | 706 | memcpy(PktReplyP->BootData, p->RIOBootPackets[p->RIONumBootPkts - sequence - 1], RTA_BOOT_DATA_SIZE); |
1da177e4 | 707 | CmdBlkP->Packet.len = PKT_MAX_DATA_LEN; |
3b8e3f1e | 708 | RIOQueueCmdBlk(HostP, Rup, CmdBlkP); |
1da177e4 LT |
709 | return 1; |
710 | } | |
711 | ||
b6c6b602 AC |
712 | /** |
713 | * RIOBootComplete - RTA boot is done | |
714 | * @p: RIO we are working with | |
715 | * @HostP: Host structure | |
716 | * @Rup: RUP being used | |
717 | * @PktCmdP: Packet command that was used | |
718 | * | |
719 | * This function is called when an RTA been booted. | |
720 | * If booted by a host, HostP->HostUniqueNum is the booting host. | |
721 | * If booted by an RTA, HostP->Mapping[Rup].RtaUniqueNum is the booting RTA. | |
722 | * RtaUniq is the booted RTA. | |
723 | */ | |
724 | ||
d886cb58 | 725 | static int RIOBootComplete(struct rio_info *p, struct Host *HostP, unsigned int Rup, struct PktCmd __iomem *PktCmdP) |
1da177e4 | 726 | { |
3b8e3f1e AC |
727 | struct Map *MapP = NULL; |
728 | struct Map *MapP2 = NULL; | |
729 | int Flag; | |
730 | int found; | |
731 | int host, rta; | |
732 | int EmptySlot = -1; | |
733 | int entry, entry2; | |
734 | char *MyType, *MyName; | |
b6c6b602 AC |
735 | unsigned int MyLink; |
736 | unsigned short RtaType; | |
737 | u32 RtaUniq = (readb(&PktCmdP->UniqNum[0])) + (readb(&PktCmdP->UniqNum[1]) << 8) + (readb(&PktCmdP->UniqNum[2]) << 16) + (readb(&PktCmdP->UniqNum[3]) << 24); | |
1da177e4 | 738 | |
1da177e4 LT |
739 | p->RIOBooting = 0; |
740 | ||
3b8e3f1e | 741 | rio_dprintk(RIO_DEBUG_BOOT, "RTA Boot completed - BootInProgress now %d\n", p->RIOBooting); |
1da177e4 LT |
742 | |
743 | /* | |
3b8e3f1e AC |
744 | ** Determine type of unit (16/8 port RTA). |
745 | */ | |
b6c6b602 | 746 | |
1da177e4 | 747 | RtaType = GetUnitType(RtaUniq); |
554b7c80 | 748 | if (Rup >= (unsigned short) MAX_RUP) |
b6c6b602 AC |
749 | rio_dprintk(RIO_DEBUG_BOOT, "RIO: Host %s has booted an RTA(%d) on link %c\n", HostP->Name, 8 * RtaType, readb(&PktCmdP->LinkNum) + 'A'); |
750 | else | |
751 | rio_dprintk(RIO_DEBUG_BOOT, "RIO: RTA %s has booted an RTA(%d) on link %c\n", HostP->Mapping[Rup].Name, 8 * RtaType, readb(&PktCmdP->LinkNum) + 'A'); | |
1da177e4 | 752 | |
3b8e3f1e | 753 | rio_dprintk(RIO_DEBUG_BOOT, "UniqNum is 0x%x\n", RtaUniq); |
1da177e4 | 754 | |
b6c6b602 | 755 | if (RtaUniq == 0x00000000 || RtaUniq == 0xffffffff) { |
3b8e3f1e | 756 | rio_dprintk(RIO_DEBUG_BOOT, "Illegal RTA Uniq Number\n"); |
554b7c80 | 757 | return 1; |
1da177e4 LT |
758 | } |
759 | ||
760 | /* | |
3b8e3f1e AC |
761 | ** If this RTA has just booted an RTA which doesn't belong to this |
762 | ** system, or the system is in slave mode, do not attempt to create | |
763 | ** a new table entry for it. | |
764 | */ | |
b6c6b602 | 765 | |
3b8e3f1e | 766 | if (!RIOBootOk(p, HostP, RtaUniq)) { |
b6c6b602 AC |
767 | MyLink = readb(&PktCmdP->LinkNum); |
768 | if (Rup < (unsigned short) MAX_RUP) { | |
3b8e3f1e AC |
769 | /* |
770 | ** RtaUniq was clone booted (by this RTA). Instruct this RTA | |
771 | ** to hold off further attempts to boot on this link for 30 | |
772 | ** seconds. | |
773 | */ | |
774 | if (RIOSuspendBootRta(HostP, HostP->Mapping[Rup].ID, MyLink)) { | |
775 | rio_dprintk(RIO_DEBUG_BOOT, "RTA failed to suspend booting on link %c\n", 'A' + MyLink); | |
776 | } | |
b6c6b602 | 777 | } else |
3b8e3f1e AC |
778 | /* |
779 | ** RtaUniq was booted by this host. Set the booting link | |
780 | ** to hold off for 30 seconds to give another unit a | |
781 | ** chance to boot it. | |
782 | */ | |
b6c6b602 | 783 | writew(30, &HostP->LinkStrP[MyLink].WaitNoBoot); |
3b8e3f1e | 784 | rio_dprintk(RIO_DEBUG_BOOT, "RTA %x not owned - suspend booting down link %c on unit %x\n", RtaUniq, 'A' + MyLink, HostP->Mapping[Rup].RtaUniqueNum); |
554b7c80 | 785 | return 1; |
1da177e4 LT |
786 | } |
787 | ||
788 | /* | |
3b8e3f1e AC |
789 | ** Check for a SLOT_IN_USE entry for this RTA attached to the |
790 | ** current host card in the driver table. | |
791 | ** | |
792 | ** If it exists, make a note that we have booted it. Other parts of | |
793 | ** the driver are interested in this information at a later date, | |
794 | ** in particular when the booting RTA asks for an ID for this unit, | |
795 | ** we must have set the BOOTED flag, and the NEWBOOT flag is used | |
796 | ** to force an open on any ports that where previously open on this | |
797 | ** unit. | |
798 | */ | |
799 | for (entry = 0; entry < MAX_RUP; entry++) { | |
b6c6b602 | 800 | unsigned int sysport; |
3b8e3f1e AC |
801 | |
802 | if ((HostP->Mapping[entry].Flags & SLOT_IN_USE) && (HostP->Mapping[entry].RtaUniqueNum == RtaUniq)) { | |
803 | HostP->Mapping[entry].Flags |= RTA_BOOTED | RTA_NEWBOOT; | |
3b8e3f1e AC |
804 | if ((sysport = HostP->Mapping[entry].SysPort) != NO_PORT) { |
805 | if (sysport < p->RIOFirstPortsBooted) | |
806 | p->RIOFirstPortsBooted = sysport; | |
807 | if (sysport > p->RIOLastPortsBooted) | |
808 | p->RIOLastPortsBooted = sysport; | |
809 | /* | |
810 | ** For a 16 port RTA, check the second bank of 8 ports | |
811 | */ | |
812 | if (RtaType == TYPE_RTA16) { | |
813 | entry2 = HostP->Mapping[entry].ID2 - 1; | |
814 | HostP->Mapping[entry2].Flags |= RTA_BOOTED | RTA_NEWBOOT; | |
3b8e3f1e AC |
815 | sysport = HostP->Mapping[entry2].SysPort; |
816 | if (sysport < p->RIOFirstPortsBooted) | |
817 | p->RIOFirstPortsBooted = sysport; | |
818 | if (sysport > p->RIOLastPortsBooted) | |
819 | p->RIOLastPortsBooted = sysport; | |
820 | } | |
821 | } | |
b6c6b602 | 822 | if (RtaType == TYPE_RTA16) |
3b8e3f1e | 823 | rio_dprintk(RIO_DEBUG_BOOT, "RTA will be given IDs %d+%d\n", entry + 1, entry2 + 1); |
b6c6b602 | 824 | else |
3b8e3f1e | 825 | rio_dprintk(RIO_DEBUG_BOOT, "RTA will be given ID %d\n", entry + 1); |
554b7c80 | 826 | return 1; |
1da177e4 | 827 | } |
1da177e4 LT |
828 | } |
829 | ||
3b8e3f1e | 830 | rio_dprintk(RIO_DEBUG_BOOT, "RTA not configured for this host\n"); |
1da177e4 | 831 | |
b6c6b602 | 832 | if (Rup >= (unsigned short) MAX_RUP) { |
3b8e3f1e AC |
833 | /* |
834 | ** It was a host that did the booting | |
835 | */ | |
836 | MyType = "Host"; | |
837 | MyName = HostP->Name; | |
838 | } else { | |
839 | /* | |
840 | ** It was an RTA that did the booting | |
841 | */ | |
842 | MyType = "RTA"; | |
843 | MyName = HostP->Mapping[Rup].Name; | |
1da177e4 | 844 | } |
b6c6b602 | 845 | MyLink = readb(&PktCmdP->LinkNum); |
1da177e4 LT |
846 | |
847 | /* | |
3b8e3f1e AC |
848 | ** There is no SLOT_IN_USE entry for this RTA attached to the current |
849 | ** host card in the driver table. | |
850 | ** | |
851 | ** Check for a SLOT_TENTATIVE entry for this RTA attached to the | |
852 | ** current host card in the driver table. | |
853 | ** | |
854 | ** If we find one, then we re-use that slot. | |
855 | */ | |
856 | for (entry = 0; entry < MAX_RUP; entry++) { | |
857 | if ((HostP->Mapping[entry].Flags & SLOT_TENTATIVE) && (HostP->Mapping[entry].RtaUniqueNum == RtaUniq)) { | |
858 | if (RtaType == TYPE_RTA16) { | |
859 | entry2 = HostP->Mapping[entry].ID2 - 1; | |
860 | if ((HostP->Mapping[entry2].Flags & SLOT_TENTATIVE) && (HostP->Mapping[entry2].RtaUniqueNum == RtaUniq)) | |
861 | rio_dprintk(RIO_DEBUG_BOOT, "Found previous tentative slots (%d+%d)\n", entry, entry2); | |
862 | else | |
863 | continue; | |
864 | } else | |
865 | rio_dprintk(RIO_DEBUG_BOOT, "Found previous tentative slot (%d)\n", entry); | |
866 | if (!p->RIONoMessage) | |
b6c6b602 | 867 | printk("RTA connected to %s '%s' (%c) not configured.\n", MyType, MyName, MyLink + 'A'); |
554b7c80 | 868 | return 1; |
1da177e4 | 869 | } |
1da177e4 LT |
870 | } |
871 | ||
872 | /* | |
3b8e3f1e AC |
873 | ** There is no SLOT_IN_USE or SLOT_TENTATIVE entry for this RTA |
874 | ** attached to the current host card in the driver table. | |
875 | ** | |
876 | ** Check if there is a SLOT_IN_USE or SLOT_TENTATIVE entry on another | |
877 | ** host for this RTA in the driver table. | |
878 | ** | |
879 | ** For a SLOT_IN_USE entry on another host, we need to delete the RTA | |
880 | ** entry from the other host and add it to this host (using some of | |
881 | ** the functions from table.c which do this). | |
882 | ** For a SLOT_TENTATIVE entry on another host, we must cope with the | |
883 | ** following scenario: | |
884 | ** | |
885 | ** + Plug 8 port RTA into host A. (This creates SLOT_TENTATIVE entry | |
886 | ** in table) | |
887 | ** + Unplug RTA and plug into host B. (We now have 2 SLOT_TENTATIVE | |
888 | ** entries) | |
889 | ** + Configure RTA on host B. (This slot now becomes SLOT_IN_USE) | |
890 | ** + Unplug RTA and plug back into host A. | |
891 | ** + Configure RTA on host A. We now have the same RTA configured | |
892 | ** with different ports on two different hosts. | |
893 | */ | |
894 | rio_dprintk(RIO_DEBUG_BOOT, "Have we seen RTA %x before?\n", RtaUniq); | |
1da177e4 | 895 | found = 0; |
3b8e3f1e AC |
896 | Flag = 0; /* Convince the compiler this variable is initialized */ |
897 | for (host = 0; !found && (host < p->RIONumHosts); host++) { | |
898 | for (rta = 0; rta < MAX_RUP; rta++) { | |
899 | if ((p->RIOHosts[host].Mapping[rta].Flags & (SLOT_IN_USE | SLOT_TENTATIVE)) && (p->RIOHosts[host].Mapping[rta].RtaUniqueNum == RtaUniq)) { | |
900 | Flag = p->RIOHosts[host].Mapping[rta].Flags; | |
901 | MapP = &p->RIOHosts[host].Mapping[rta]; | |
902 | if (RtaType == TYPE_RTA16) { | |
903 | MapP2 = &p->RIOHosts[host].Mapping[MapP->ID2 - 1]; | |
904 | rio_dprintk(RIO_DEBUG_BOOT, "This RTA is units %d+%d from host %s\n", rta + 1, MapP->ID2, p->RIOHosts[host].Name); | |
905 | } else | |
906 | rio_dprintk(RIO_DEBUG_BOOT, "This RTA is unit %d from host %s\n", rta + 1, p->RIOHosts[host].Name); | |
907 | found = 1; | |
908 | break; | |
909 | } | |
1da177e4 | 910 | } |
1da177e4 LT |
911 | } |
912 | ||
913 | /* | |
3b8e3f1e AC |
914 | ** There is no SLOT_IN_USE or SLOT_TENTATIVE entry for this RTA |
915 | ** attached to the current host card in the driver table. | |
916 | ** | |
917 | ** If we have not found a SLOT_IN_USE or SLOT_TENTATIVE entry on | |
918 | ** another host for this RTA in the driver table... | |
919 | ** | |
920 | ** Check for a SLOT_IN_USE entry for this RTA in the config table. | |
921 | */ | |
922 | if (!MapP) { | |
923 | rio_dprintk(RIO_DEBUG_BOOT, "Look for RTA %x in RIOSavedTable\n", RtaUniq); | |
924 | for (rta = 0; rta < TOTAL_MAP_ENTRIES; rta++) { | |
925 | rio_dprintk(RIO_DEBUG_BOOT, "Check table entry %d (%x)", rta, p->RIOSavedTable[rta].RtaUniqueNum); | |
926 | ||
927 | if ((p->RIOSavedTable[rta].Flags & SLOT_IN_USE) && (p->RIOSavedTable[rta].RtaUniqueNum == RtaUniq)) { | |
928 | MapP = &p->RIOSavedTable[rta]; | |
929 | Flag = p->RIOSavedTable[rta].Flags; | |
930 | if (RtaType == TYPE_RTA16) { | |
931 | for (entry2 = rta + 1; entry2 < TOTAL_MAP_ENTRIES; entry2++) { | |
932 | if (p->RIOSavedTable[entry2].RtaUniqueNum == RtaUniq) | |
933 | break; | |
934 | } | |
935 | MapP2 = &p->RIOSavedTable[entry2]; | |
936 | rio_dprintk(RIO_DEBUG_BOOT, "This RTA is from table entries %d+%d\n", rta, entry2); | |
937 | } else | |
938 | rio_dprintk(RIO_DEBUG_BOOT, "This RTA is from table entry %d\n", rta); | |
939 | break; | |
940 | } | |
1da177e4 | 941 | } |
1da177e4 LT |
942 | } |
943 | ||
944 | /* | |
3b8e3f1e AC |
945 | ** There is no SLOT_IN_USE or SLOT_TENTATIVE entry for this RTA |
946 | ** attached to the current host card in the driver table. | |
947 | ** | |
948 | ** We may have found a SLOT_IN_USE entry on another host for this | |
949 | ** RTA in the config table, or a SLOT_IN_USE or SLOT_TENTATIVE entry | |
950 | ** on another host for this RTA in the driver table. | |
951 | ** | |
952 | ** Check the driver table for room to fit this newly discovered RTA. | |
953 | ** RIOFindFreeID() first looks for free slots and if it does not | |
954 | ** find any free slots it will then attempt to oust any | |
955 | ** tentative entry in the table. | |
956 | */ | |
1da177e4 | 957 | EmptySlot = 1; |
3b8e3f1e AC |
958 | if (RtaType == TYPE_RTA16) { |
959 | if (RIOFindFreeID(p, HostP, &entry, &entry2) == 0) { | |
960 | RIODefaultName(p, HostP, entry); | |
554b7c80 | 961 | rio_fill_host_slot(entry, entry2, RtaUniq, HostP); |
3b8e3f1e AC |
962 | EmptySlot = 0; |
963 | } | |
964 | } else { | |
965 | if (RIOFindFreeID(p, HostP, &entry, NULL) == 0) { | |
966 | RIODefaultName(p, HostP, entry); | |
554b7c80 | 967 | rio_fill_host_slot(entry, 0, RtaUniq, HostP); |
3b8e3f1e AC |
968 | EmptySlot = 0; |
969 | } | |
1da177e4 LT |
970 | } |
971 | ||
972 | /* | |
3b8e3f1e AC |
973 | ** There is no SLOT_IN_USE or SLOT_TENTATIVE entry for this RTA |
974 | ** attached to the current host card in the driver table. | |
975 | ** | |
976 | ** If we found a SLOT_IN_USE entry on another host for this | |
977 | ** RTA in the config or driver table, and there are enough free | |
978 | ** slots in the driver table, then we need to move it over and | |
979 | ** delete it from the other host. | |
980 | ** If we found a SLOT_TENTATIVE entry on another host for this | |
981 | ** RTA in the driver table, just delete the other host entry. | |
982 | */ | |
983 | if (EmptySlot == 0) { | |
984 | if (MapP) { | |
985 | if (Flag & SLOT_IN_USE) { | |
986 | rio_dprintk(RIO_DEBUG_BOOT, "This RTA configured on another host - move entry to current host (1)\n"); | |
987 | HostP->Mapping[entry].SysPort = MapP->SysPort; | |
b6c6b602 | 988 | memcpy(HostP->Mapping[entry].Name, MapP->Name, MAX_NAME_LEN); |
3b8e3f1e | 989 | HostP->Mapping[entry].Flags = SLOT_IN_USE | RTA_BOOTED | RTA_NEWBOOT; |
3b8e3f1e AC |
990 | RIOReMapPorts(p, HostP, &HostP->Mapping[entry]); |
991 | if (HostP->Mapping[entry].SysPort < p->RIOFirstPortsBooted) | |
992 | p->RIOFirstPortsBooted = HostP->Mapping[entry].SysPort; | |
993 | if (HostP->Mapping[entry].SysPort > p->RIOLastPortsBooted) | |
994 | p->RIOLastPortsBooted = HostP->Mapping[entry].SysPort; | |
995 | rio_dprintk(RIO_DEBUG_BOOT, "SysPort %d, Name %s\n", (int) MapP->SysPort, MapP->Name); | |
996 | } else { | |
997 | rio_dprintk(RIO_DEBUG_BOOT, "This RTA has a tentative entry on another host - delete that entry (1)\n"); | |
998 | HostP->Mapping[entry].Flags = SLOT_TENTATIVE | RTA_BOOTED | RTA_NEWBOOT; | |
3b8e3f1e AC |
999 | } |
1000 | if (RtaType == TYPE_RTA16) { | |
1001 | if (Flag & SLOT_IN_USE) { | |
1002 | HostP->Mapping[entry2].Flags = SLOT_IN_USE | RTA_BOOTED | RTA_NEWBOOT | RTA16_SECOND_SLOT; | |
3b8e3f1e AC |
1003 | HostP->Mapping[entry2].SysPort = MapP2->SysPort; |
1004 | /* | |
1005 | ** Map second block of ttys for 16 port RTA | |
1006 | */ | |
1007 | RIOReMapPorts(p, HostP, &HostP->Mapping[entry2]); | |
1008 | if (HostP->Mapping[entry2].SysPort < p->RIOFirstPortsBooted) | |
1009 | p->RIOFirstPortsBooted = HostP->Mapping[entry2].SysPort; | |
1010 | if (HostP->Mapping[entry2].SysPort > p->RIOLastPortsBooted) | |
1011 | p->RIOLastPortsBooted = HostP->Mapping[entry2].SysPort; | |
1012 | rio_dprintk(RIO_DEBUG_BOOT, "SysPort %d, Name %s\n", (int) HostP->Mapping[entry2].SysPort, HostP->Mapping[entry].Name); | |
1013 | } else | |
1014 | HostP->Mapping[entry2].Flags = SLOT_TENTATIVE | RTA_BOOTED | RTA_NEWBOOT | RTA16_SECOND_SLOT; | |
b6c6b602 | 1015 | memset(MapP2, 0, sizeof(struct Map)); |
3b8e3f1e | 1016 | } |
b6c6b602 | 1017 | memset(MapP, 0, sizeof(struct Map)); |
3b8e3f1e | 1018 | if (!p->RIONoMessage) |
b6c6b602 | 1019 | printk("An orphaned RTA has been adopted by %s '%s' (%c).\n", MyType, MyName, MyLink + 'A'); |
3b8e3f1e | 1020 | } else if (!p->RIONoMessage) |
b6c6b602 | 1021 | printk("RTA connected to %s '%s' (%c) not configured.\n", MyType, MyName, MyLink + 'A'); |
3b8e3f1e | 1022 | RIOSetChange(p); |
554b7c80 | 1023 | return 1; |
1da177e4 LT |
1024 | } |
1025 | ||
1026 | /* | |
3b8e3f1e AC |
1027 | ** There is no room in the driver table to make an entry for the |
1028 | ** booted RTA. Keep a note of its Uniq Num in the overflow table, | |
1029 | ** so we can ignore it's ID requests. | |
1030 | */ | |
1031 | if (!p->RIONoMessage) | |
b6c6b602 | 1032 | printk("The RTA connected to %s '%s' (%c) cannot be configured. You cannot configure more than 128 ports to one host card.\n", MyType, MyName, MyLink + 'A'); |
3b8e3f1e AC |
1033 | for (entry = 0; entry < HostP->NumExtraBooted; entry++) { |
1034 | if (HostP->ExtraUnits[entry] == RtaUniq) { | |
1035 | /* | |
1036 | ** already got it! | |
1037 | */ | |
554b7c80 | 1038 | return 1; |
3b8e3f1e | 1039 | } |
1da177e4 LT |
1040 | } |
1041 | /* | |
3b8e3f1e AC |
1042 | ** If there is room, add the unit to the list of extras |
1043 | */ | |
1044 | if (HostP->NumExtraBooted < MAX_EXTRA_UNITS) | |
1045 | HostP->ExtraUnits[HostP->NumExtraBooted++] = RtaUniq; | |
554b7c80 | 1046 | return 1; |
1da177e4 LT |
1047 | } |
1048 | ||
1049 | ||
1050 | /* | |
1051 | ** If the RTA or its host appears in the RIOBindTab[] structure then | |
554b7c80 | 1052 | ** we mustn't boot the RTA and should return 0. |
1da177e4 LT |
1053 | ** This operation is slightly different from the other drivers for RIO |
1054 | ** in that this is designed to work with the new utilities | |
1055 | ** not config.rio and is FAR SIMPLER. | |
1056 | ** We no longer support the RIOBootMode variable. It is all done from the | |
1057 | ** "boot/noboot" field in the rio.cf file. | |
1058 | */ | |
b6c6b602 | 1059 | int RIOBootOk(struct rio_info *p, struct Host *HostP, unsigned long RtaUniq) |
1da177e4 | 1060 | { |
3b8e3f1e | 1061 | int Entry; |
b6c6b602 | 1062 | unsigned int HostUniq = HostP->UniqueNum; |
1da177e4 LT |
1063 | |
1064 | /* | |
3b8e3f1e AC |
1065 | ** Search bindings table for RTA or its parent. |
1066 | ** If it exists, return 0, else 1. | |
1067 | */ | |
1068 | for (Entry = 0; (Entry < MAX_RTA_BINDINGS) && (p->RIOBindTab[Entry] != 0); Entry++) { | |
1069 | if ((p->RIOBindTab[Entry] == HostUniq) || (p->RIOBindTab[Entry] == RtaUniq)) | |
1da177e4 LT |
1070 | return 0; |
1071 | } | |
1072 | return 1; | |
1073 | } | |
1074 | ||
1075 | /* | |
1076 | ** Make an empty slot tentative. If this is a 16 port RTA, make both | |
1077 | ** slots tentative, and the second one RTA_SECOND_SLOT as well. | |
1078 | */ | |
1079 | ||
554b7c80 | 1080 | void rio_fill_host_slot(int entry, int entry2, unsigned int rta_uniq, struct Host *host) |
1da177e4 | 1081 | { |
3b8e3f1e | 1082 | int link; |
1da177e4 | 1083 | |
554b7c80 | 1084 | rio_dprintk(RIO_DEBUG_BOOT, "rio_fill_host_slot(%d, %d, 0x%x...)\n", entry, entry2, rta_uniq); |
1da177e4 | 1085 | |
554b7c80 AC |
1086 | host->Mapping[entry].Flags = (RTA_BOOTED | RTA_NEWBOOT | SLOT_TENTATIVE); |
1087 | host->Mapping[entry].SysPort = NO_PORT; | |
1088 | host->Mapping[entry].RtaUniqueNum = rta_uniq; | |
1089 | host->Mapping[entry].HostUniqueNum = host->UniqueNum; | |
1090 | host->Mapping[entry].ID = entry + 1; | |
1091 | host->Mapping[entry].ID2 = 0; | |
1da177e4 | 1092 | if (entry2) { |
554b7c80 AC |
1093 | host->Mapping[entry2].Flags = (RTA_BOOTED | RTA_NEWBOOT | SLOT_TENTATIVE | RTA16_SECOND_SLOT); |
1094 | host->Mapping[entry2].SysPort = NO_PORT; | |
1095 | host->Mapping[entry2].RtaUniqueNum = rta_uniq; | |
1096 | host->Mapping[entry2].HostUniqueNum = host->UniqueNum; | |
1097 | host->Mapping[entry2].Name[0] = '\0'; | |
1098 | host->Mapping[entry2].ID = entry2 + 1; | |
1099 | host->Mapping[entry2].ID2 = entry + 1; | |
1100 | host->Mapping[entry].ID2 = entry2 + 1; | |
1da177e4 LT |
1101 | } |
1102 | /* | |
3b8e3f1e AC |
1103 | ** Must set these up, so that utilities show |
1104 | ** topology of 16 port RTAs correctly | |
1105 | */ | |
1106 | for (link = 0; link < LINKS_PER_UNIT; link++) { | |
554b7c80 AC |
1107 | host->Mapping[entry].Topology[link].Unit = ROUTE_DISCONNECT; |
1108 | host->Mapping[entry].Topology[link].Link = NO_LINK; | |
1da177e4 | 1109 | if (entry2) { |
554b7c80 AC |
1110 | host->Mapping[entry2].Topology[link].Unit = ROUTE_DISCONNECT; |
1111 | host->Mapping[entry2].Topology[link].Link = NO_LINK; | |
1da177e4 LT |
1112 | } |
1113 | } | |
1114 | } |