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