FreeBSD/Linux Kernel Cross Reference
sys/dev/pci/mlx_pci.c
1 /* $NetBSD: mlx_pci.c,v 1.11 2002/10/02 16:51:43 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 2001 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Andrew Doran.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*-
40 * Copyright (c) 1999 Michael Smith
41 * All rights reserved.
42 *
43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions
45 * are met:
46 * 1. Redistributions of source code must retain the above copyright
47 * notice, this list of conditions and the following disclaimer.
48 * 2. Redistributions in binary form must reproduce the above copyright
49 * notice, this list of conditions and the following disclaimer in the
50 * documentation and/or other materials provided with the distribution.
51 *
52 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62 * SUCH DAMAGE.
63 *
64 * from FreeBSD: mlx_pci.c,v 1.4.2.4 2000/10/28 10:48:09 msmith Exp
65 */
66
67 /*
68 * PCI front-end for the mlx(4) driver.
69 */
70
71 #include <sys/cdefs.h>
72 __KERNEL_RCSID(0, "$NetBSD: mlx_pci.c,v 1.11 2002/10/02 16:51:43 thorpej Exp $");
73
74 #include <sys/param.h>
75 #include <sys/systm.h>
76 #include <sys/kernel.h>
77 #include <sys/device.h>
78 #include <sys/queue.h>
79 #include <sys/callout.h>
80
81 #include <machine/endian.h>
82 #include <machine/bus.h>
83
84 #include <dev/ic/mlxreg.h>
85 #include <dev/ic/mlxio.h>
86 #include <dev/ic/mlxvar.h>
87
88 #include <dev/pci/pcireg.h>
89 #include <dev/pci/pcivar.h>
90 #include <dev/pci/pcidevs.h>
91
92 static void mlx_pci_attach(struct device *, struct device *, void *);
93 static int mlx_pci_match(struct device *, struct cfdata *, void *);
94 static const struct mlx_pci_ident *mlx_pci_findmpi(struct pci_attach_args *);
95
96 static int mlx_v3_submit(struct mlx_softc *, struct mlx_ccb *);
97 static int mlx_v3_findcomplete(struct mlx_softc *, u_int *, u_int *);
98 static void mlx_v3_intaction(struct mlx_softc *, int);
99 static int mlx_v3_fw_handshake(struct mlx_softc *, int *, int *, int *);
100 #ifdef MLX_RESET
101 static int mlx_v3_reset(struct mlx_softc *);
102 #endif
103
104 static int mlx_v4_submit(struct mlx_softc *, struct mlx_ccb *);
105 static int mlx_v4_findcomplete(struct mlx_softc *, u_int *, u_int *);
106 static void mlx_v4_intaction(struct mlx_softc *, int);
107 static int mlx_v4_fw_handshake(struct mlx_softc *, int *, int *, int *);
108
109 static int mlx_v5_submit(struct mlx_softc *, struct mlx_ccb *);
110 static int mlx_v5_findcomplete(struct mlx_softc *, u_int *, u_int *);
111 static void mlx_v5_intaction(struct mlx_softc *, int);
112 static int mlx_v5_fw_handshake(struct mlx_softc *, int *, int *, int *);
113
114 struct mlx_pci_ident {
115 u_short mpi_vendor;
116 u_short mpi_product;
117 u_short mpi_subvendor;
118 u_short mpi_subproduct;
119 int mpi_iftype;
120 } static const mlx_pci_ident[] = {
121 {
122 PCI_VENDOR_MYLEX,
123 PCI_PRODUCT_MYLEX_RAID_V2,
124 0x0000,
125 0x0000,
126 2,
127 },
128 {
129 PCI_VENDOR_MYLEX,
130 PCI_PRODUCT_MYLEX_RAID_V3,
131 0x0000,
132 0x0000,
133 3,
134 },
135 {
136 PCI_VENDOR_MYLEX,
137 PCI_PRODUCT_MYLEX_RAID_V4,
138 0x0000,
139 0x0000,
140 4,
141 },
142 {
143 PCI_VENDOR_DEC,
144 PCI_PRODUCT_DEC_SWXCR,
145 PCI_VENDOR_MYLEX,
146 PCI_PRODUCT_MYLEX_RAID_V5,
147 5,
148 },
149 };
150
151 CFATTACH_DECL(mlx_pci, sizeof(struct mlx_softc),
152 mlx_pci_match, mlx_pci_attach, NULL, NULL);
153
154 /*
155 * Try to find a `mlx_pci_ident' entry corresponding to this board.
156 */
157 static const struct mlx_pci_ident *
158 mlx_pci_findmpi(struct pci_attach_args *pa)
159 {
160 const struct mlx_pci_ident *mpi, *maxmpi;
161 pcireg_t reg;
162
163 mpi = mlx_pci_ident;
164 maxmpi = mpi + sizeof(mlx_pci_ident) / sizeof(mlx_pci_ident[0]);
165
166 for (; mpi < maxmpi; mpi++) {
167 if (PCI_VENDOR(pa->pa_id) != mpi->mpi_vendor ||
168 PCI_PRODUCT(pa->pa_id) != mpi->mpi_product)
169 continue;
170
171 if (mpi->mpi_subvendor == 0x0000)
172 return (mpi);
173
174 reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
175
176 if (PCI_VENDOR(reg) == mpi->mpi_subvendor &&
177 PCI_PRODUCT(reg) == mpi->mpi_subproduct)
178 return (mpi);
179 }
180
181 return (NULL);
182 }
183
184 /*
185 * Match a supported board.
186 */
187 static int
188 mlx_pci_match(struct device *parent, struct cfdata *cfdata, void *aux)
189 {
190
191 return (mlx_pci_findmpi(aux) != NULL);
192 }
193
194 /*
195 * Attach a supported board.
196 */
197 static void
198 mlx_pci_attach(struct device *parent, struct device *self, void *aux)
199 {
200 struct pci_attach_args *pa;
201 struct mlx_softc *mlx;
202 pci_chipset_tag_t pc;
203 pci_intr_handle_t ih;
204 bus_space_handle_t memh, ioh;
205 bus_space_tag_t memt, iot;
206 pcireg_t reg;
207 const char *intrstr;
208 int ior, memr, i;
209 const struct mlx_pci_ident *mpi;
210
211 mlx = (struct mlx_softc *)self;
212 pa = aux;
213 pc = pa->pa_pc;
214 mpi = mlx_pci_findmpi(aux);
215
216 mlx->mlx_dmat = pa->pa_dmat;
217 mlx->mlx_ci.ci_iftype = mpi->mpi_iftype;
218
219 printf(": Mylex RAID (v%d interface)\n", mpi->mpi_iftype);
220
221 /*
222 * Map the PCI register window.
223 */
224 memr = -1;
225 ior = -1;
226
227 for (i = 0x10; i <= 0x14; i += 4) {
228 reg = pci_conf_read(pa->pa_pc, pa->pa_tag, i);
229
230 if (PCI_MAPREG_TYPE(reg) == PCI_MAPREG_TYPE_IO) {
231 if (ior == -1 && PCI_MAPREG_IO_SIZE(reg) != 0)
232 ior = i;
233 } else {
234 if (memr == -1 && PCI_MAPREG_MEM_SIZE(reg) != 0)
235 memr = i;
236 }
237 }
238
239 if (memr != -1)
240 if (pci_mapreg_map(pa, memr, PCI_MAPREG_TYPE_MEM, 0,
241 &memt, &memh, NULL, NULL))
242 memr = -1;
243 if (ior != -1)
244 if (pci_mapreg_map(pa, ior, PCI_MAPREG_TYPE_IO, 0,
245 &iot, &ioh, NULL, NULL))
246 ior = -1;
247
248 if (memr != -1) {
249 mlx->mlx_iot = memt;
250 mlx->mlx_ioh = memh;
251 } else if (ior != -1) {
252 mlx->mlx_iot = iot;
253 mlx->mlx_ioh = ioh;
254 } else {
255 printf("%s: can't map i/o or memory space\n", self->dv_xname);
256 return;
257 }
258
259 /* Enable the device. */
260 reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
261 pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
262 reg | PCI_COMMAND_MASTER_ENABLE);
263
264 /* Map and establish the interrupt. */
265 if (pci_intr_map(pa, &ih)) {
266 printf("%s: can't map interrupt\n", self->dv_xname);
267 return;
268 }
269 intrstr = pci_intr_string(pc, ih);
270 mlx->mlx_ih = pci_intr_establish(pc, ih, IPL_BIO, mlx_intr, mlx);
271 if (mlx->mlx_ih == NULL) {
272 printf("%s: can't establish interrupt", self->dv_xname);
273 if (intrstr != NULL)
274 printf(" at %s", intrstr);
275 printf("\n");
276 return;
277 }
278
279 /* Select linkage based on controller interface type. */
280 switch (mlx->mlx_ci.ci_iftype) {
281 case 2:
282 case 3:
283 mlx->mlx_submit = mlx_v3_submit;
284 mlx->mlx_findcomplete = mlx_v3_findcomplete;
285 mlx->mlx_intaction = mlx_v3_intaction;
286 mlx->mlx_fw_handshake = mlx_v3_fw_handshake;
287 #ifdef MLX_RESET
288 mlx->mlx_reset = mlx_v3_reset;
289 #endif
290 break;
291
292 case 4:
293 mlx->mlx_submit = mlx_v4_submit;
294 mlx->mlx_findcomplete = mlx_v4_findcomplete;
295 mlx->mlx_intaction = mlx_v4_intaction;
296 mlx->mlx_fw_handshake = mlx_v4_fw_handshake;
297 break;
298
299 case 5:
300 mlx->mlx_submit = mlx_v5_submit;
301 mlx->mlx_findcomplete = mlx_v5_findcomplete;
302 mlx->mlx_intaction = mlx_v5_intaction;
303 mlx->mlx_fw_handshake = mlx_v5_fw_handshake;
304 break;
305 }
306
307 mlx_init(mlx, intrstr);
308 }
309
310 /*
311 * ================= V3 interface linkage =================
312 */
313
314 /*
315 * Try to give (mc) to the controller. Returns 1 if successful, 0 on
316 * failure (the controller is not ready to take a command).
317 *
318 * Must be called at splbio or in a fashion that prevents reentry.
319 */
320 static int
321 mlx_v3_submit(struct mlx_softc *mlx, struct mlx_ccb *mc)
322 {
323
324 /* Ready for our command? */
325 if ((mlx_inb(mlx, MLX_V3REG_IDB) & MLX_V3_IDB_FULL) == 0) {
326 /* Copy mailbox data to window. */
327 bus_space_write_region_1(mlx->mlx_iot, mlx->mlx_ioh,
328 MLX_V3REG_MAILBOX, mc->mc_mbox, 13);
329 bus_space_barrier(mlx->mlx_iot, mlx->mlx_ioh,
330 MLX_V3REG_MAILBOX, 13,
331 BUS_SPACE_BARRIER_WRITE);
332
333 /* Post command. */
334 mlx_outb(mlx, MLX_V3REG_IDB, MLX_V3_IDB_FULL);
335 return (1);
336 }
337
338 return (0);
339 }
340
341 /*
342 * See if a command has been completed, if so acknowledge its completion and
343 * recover the slot number and status code.
344 *
345 * Must be called at splbio or in a fashion that prevents reentry.
346 */
347 static int
348 mlx_v3_findcomplete(struct mlx_softc *mlx, u_int *slot, u_int *status)
349 {
350
351 /* Status available? */
352 if ((mlx_inb(mlx, MLX_V3REG_ODB) & MLX_V3_ODB_SAVAIL) != 0) {
353 *slot = mlx_inb(mlx, MLX_V3REG_STATUS_IDENT);
354 *status = mlx_inw(mlx, MLX_V3REG_STATUS);
355
356 /* Acknowledge completion. */
357 mlx_outb(mlx, MLX_V3REG_ODB, MLX_V3_ODB_SAVAIL);
358 mlx_outb(mlx, MLX_V3REG_IDB, MLX_V3_IDB_SACK);
359 return (1);
360 }
361
362 return (0);
363 }
364
365 /*
366 * Enable/disable interrupts as requested. (No acknowledge required)
367 *
368 * Must be called at splbio or in a fashion that prevents reentry.
369 */
370 static void
371 mlx_v3_intaction(struct mlx_softc *mlx, int action)
372 {
373
374 mlx_outb(mlx, MLX_V3REG_IE, action != 0);
375 }
376
377 /*
378 * Poll for firmware error codes during controller initialisation.
379 *
380 * Returns 0 if initialisation is complete, 1 if still in progress but no
381 * error has been fetched, 2 if an error has been retrieved.
382 */
383 static int
384 mlx_v3_fw_handshake(struct mlx_softc *mlx, int *error, int *param1, int *param2)
385 {
386 u_int8_t fwerror;
387
388 /* First time around, clear any hardware completion status. */
389 if ((mlx->mlx_flags & MLXF_FW_INITTED) == 0) {
390 mlx_outb(mlx, MLX_V3REG_IDB, MLX_V3_IDB_SACK);
391 DELAY(1000);
392 mlx->mlx_flags |= MLXF_FW_INITTED;
393 }
394
395 /* Init in progress? */
396 if ((mlx_inb(mlx, MLX_V3REG_IDB) & MLX_V3_IDB_INIT_BUSY) == 0)
397 return (0);
398
399 /* Test error value. */
400 fwerror = mlx_inb(mlx, MLX_V3REG_FWERROR);
401
402 if ((fwerror & MLX_V3_FWERROR_PEND) == 0)
403 return (1);
404
405 /* Mask status pending bit, fetch status. */
406 *error = fwerror & ~MLX_V3_FWERROR_PEND;
407 *param1 = mlx_inb(mlx, MLX_V3REG_FWERROR_PARAM1);
408 *param2 = mlx_inb(mlx, MLX_V3REG_FWERROR_PARAM2);
409
410 /* Acknowledge. */
411 mlx_outb(mlx, MLX_V3REG_FWERROR, 0);
412
413 return (2);
414 }
415
416 #ifdef MLX_RESET
417 /*
418 * Reset the controller. Return non-zero on failure.
419 */
420 static int
421 mlx_v3_reset(struct mlx_softc *mlx)
422 {
423 int i;
424
425 mlx_outb(mlx, MLX_V3REG_IDB, MLX_V3_IDB_SACK);
426 delay(1000000);
427
428 /* Wait up to 2 minutes for the bit to clear. */
429 for (i = 120; i != 0; i--) {
430 delay(1000000);
431 if ((mlx_inb(mlx, MLX_V3REG_IDB) & MLX_V3_IDB_SACK) == 0)
432 break;
433 }
434 if (i == 0) {
435 /* ZZZ */
436 printf("mlx0: SACK didn't clear\n");
437 return (-1);
438 }
439
440 mlx_outb(mlx, MLX_V3REG_IDB, MLX_V3_IDB_RESET);
441
442 /* Wait up to 5 seconds for the bit to clear. */
443 for (i = 5; i != 0; i--) {
444 delay(1000000);
445 if ((mlx_inb(mlx, MLX_V3REG_IDB) & MLX_V3_IDB_RESET) == 0)
446 break;
447 }
448 if (i == 0) {
449 /* ZZZ */
450 printf("mlx0: RESET didn't clear\n");
451 return (-1);
452 }
453
454 return (0);
455 }
456 #endif /* MLX_RESET */
457
458 /*
459 * ================= V4 interface linkage =================
460 */
461
462 /*
463 * Try to give (mc) to the controller. Returns 1 if successful, 0 on
464 * failure (the controller is not ready to take a command).
465 *
466 * Must be called at splbio or in a fashion that prevents reentry.
467 */
468 static int
469 mlx_v4_submit(struct mlx_softc *mlx, struct mlx_ccb *mc)
470 {
471
472 /* Ready for our command? */
473 if ((mlx_inl(mlx, MLX_V4REG_IDB) & MLX_V4_IDB_FULL) == 0) {
474 /* Copy mailbox data to window. */
475 bus_space_write_region_1(mlx->mlx_iot, mlx->mlx_ioh,
476 MLX_V4REG_MAILBOX, mc->mc_mbox, 13);
477 bus_space_barrier(mlx->mlx_iot, mlx->mlx_ioh,
478 MLX_V4REG_MAILBOX, 13,
479 BUS_SPACE_BARRIER_WRITE);
480
481 /* Post command. */
482 mlx_outl(mlx, MLX_V4REG_IDB, MLX_V4_IDB_HWMBOX_CMD);
483 return (1);
484 }
485
486 return (0);
487 }
488
489 /*
490 * See if a command has been completed, if so acknowledge its completion and
491 * recover the slot number and status code.
492 *
493 * Must be called at splbio or in a fashion that prevents reentry.
494 */
495 static int
496 mlx_v4_findcomplete(struct mlx_softc *mlx, u_int *slot, u_int *status)
497 {
498
499 /* Status available? */
500 if ((mlx_inl(mlx, MLX_V4REG_ODB) & MLX_V4_ODB_HWSAVAIL) != 0) {
501 *slot = mlx_inb(mlx, MLX_V4REG_STATUS_IDENT);
502 *status = mlx_inw(mlx, MLX_V4REG_STATUS);
503
504 /* Acknowledge completion. */
505 mlx_outl(mlx, MLX_V4REG_ODB, MLX_V4_ODB_HWMBOX_ACK);
506 mlx_outl(mlx, MLX_V4REG_IDB, MLX_V4_IDB_SACK);
507 return (1);
508 }
509
510 return (0);
511 }
512
513 /*
514 * Enable/disable interrupts as requested.
515 *
516 * Must be called at splbio or in a fashion that prevents reentry.
517 */
518 static void
519 mlx_v4_intaction(struct mlx_softc *mlx, int action)
520 {
521 u_int32_t ier;
522
523 if (!action)
524 ier = MLX_V4_IE_MASK | MLX_V4_IE_DISINT;
525 else
526 ier = MLX_V4_IE_MASK & ~MLX_V4_IE_DISINT;
527
528 mlx_outl(mlx, MLX_V4REG_IE, ier);
529 }
530
531 /*
532 * Poll for firmware error codes during controller initialisation.
533 *
534 * Returns 0 if initialisation is complete, 1 if still in progress but no
535 * error has been fetched, 2 if an error has been retrieved.
536 */
537 static int
538 mlx_v4_fw_handshake(struct mlx_softc *mlx, int *error, int *param1, int *param2)
539 {
540 u_int8_t fwerror;
541
542 /* First time around, clear any hardware completion status. */
543 if ((mlx->mlx_flags & MLXF_FW_INITTED) == 0) {
544 mlx_outl(mlx, MLX_V4REG_IDB, MLX_V4_IDB_SACK);
545 DELAY(1000);
546 mlx->mlx_flags |= MLXF_FW_INITTED;
547 }
548
549 /* Init in progress? */
550 if ((mlx_inl(mlx, MLX_V4REG_IDB) & MLX_V4_IDB_INIT_BUSY) == 0)
551 return (0);
552
553 /* Test error value */
554 fwerror = mlx_inb(mlx, MLX_V4REG_FWERROR);
555 if ((fwerror & MLX_V4_FWERROR_PEND) == 0)
556 return (1);
557
558 /* Mask status pending bit, fetch status. */
559 *error = fwerror & ~MLX_V4_FWERROR_PEND;
560 *param1 = mlx_inb(mlx, MLX_V4REG_FWERROR_PARAM1);
561 *param2 = mlx_inb(mlx, MLX_V4REG_FWERROR_PARAM2);
562
563 /* Acknowledge. */
564 mlx_outb(mlx, MLX_V4REG_FWERROR, 0);
565
566 return (2);
567 }
568
569 /*
570 * ================= V5 interface linkage =================
571 */
572
573 /*
574 * Try to give (mc) to the controller. Returns 1 if successful, 0 on failure
575 * (the controller is not ready to take a command).
576 *
577 * Must be called at splbio or in a fashion that prevents reentry.
578 */
579 static int
580 mlx_v5_submit(struct mlx_softc *mlx, struct mlx_ccb *mc)
581 {
582
583 /* Ready for our command? */
584 if ((mlx_inb(mlx, MLX_V5REG_IDB) & MLX_V5_IDB_EMPTY) != 0) {
585 /* Copy mailbox data to window. */
586 bus_space_write_region_1(mlx->mlx_iot, mlx->mlx_ioh,
587 MLX_V5REG_MAILBOX, mc->mc_mbox, 13);
588 bus_space_barrier(mlx->mlx_iot, mlx->mlx_ioh,
589 MLX_V5REG_MAILBOX, 13,
590 BUS_SPACE_BARRIER_WRITE);
591
592 /* Post command */
593 mlx_outb(mlx, MLX_V5REG_IDB, MLX_V5_IDB_HWMBOX_CMD);
594 return (1);
595 }
596
597 return (0);
598 }
599
600 /*
601 * See if a command has been completed, if so acknowledge its completion and
602 * recover the slot number and status code.
603 *
604 * Must be called at splbio or in a fashion that prevents reentry.
605 */
606 static int
607 mlx_v5_findcomplete(struct mlx_softc *mlx, u_int *slot, u_int *status)
608 {
609
610 /* Status available? */
611 if ((mlx_inb(mlx, MLX_V5REG_ODB) & MLX_V5_ODB_HWSAVAIL) != 0) {
612 *slot = mlx_inb(mlx, MLX_V5REG_STATUS_IDENT);
613 *status = mlx_inw(mlx, MLX_V5REG_STATUS);
614
615 /* Acknowledge completion. */
616 mlx_outb(mlx, MLX_V5REG_ODB, MLX_V5_ODB_HWMBOX_ACK);
617 mlx_outb(mlx, MLX_V5REG_IDB, MLX_V5_IDB_SACK);
618 return (1);
619 }
620
621 return (0);
622 }
623
624 /*
625 * Enable/disable interrupts as requested.
626 *
627 * Must be called at splbio or in a fashion that prevents reentry.
628 */
629 static void
630 mlx_v5_intaction(struct mlx_softc *mlx, int action)
631 {
632 u_int8_t ier;
633
634 if (!action)
635 ier = 0xff & MLX_V5_IE_DISINT;
636 else
637 ier = 0xff & ~MLX_V5_IE_DISINT;
638
639 mlx_outb(mlx, MLX_V5REG_IE, ier);
640 }
641
642 /*
643 * Poll for firmware error codes during controller initialisation.
644 *
645 * Returns 0 if initialisation is complete, 1 if still in progress but no
646 * error has been fetched, 2 if an error has been retrieved.
647 */
648 static int
649 mlx_v5_fw_handshake(struct mlx_softc *mlx, int *error, int *param1, int *param2)
650 {
651 u_int8_t fwerror;
652
653 /* First time around, clear any hardware completion status. */
654 if ((mlx->mlx_flags & MLXF_FW_INITTED) == 0) {
655 mlx_outb(mlx, MLX_V5REG_IDB, MLX_V5_IDB_SACK);
656 DELAY(1000);
657 mlx->mlx_flags |= MLXF_FW_INITTED;
658 }
659
660 /* Init in progress? */
661 if ((mlx_inb(mlx, MLX_V5REG_IDB) & MLX_V5_IDB_INIT_DONE) != 0)
662 return (0);
663
664 /* Test for error value. */
665 fwerror = mlx_inb(mlx, MLX_V5REG_FWERROR);
666 if ((fwerror & MLX_V5_FWERROR_PEND) == 0)
667 return (1);
668
669 /* Mask status pending bit, fetch status. */
670 *error = fwerror & ~MLX_V5_FWERROR_PEND;
671 *param1 = mlx_inb(mlx, MLX_V5REG_FWERROR_PARAM1);
672 *param2 = mlx_inb(mlx, MLX_V5REG_FWERROR_PARAM2);
673
674 /* Acknowledge. */
675 mlx_outb(mlx, MLX_V5REG_FWERROR, 0xff);
676
677 return (2);
678 }
Cache object: 5b2bc4bf5b2b41d4a8db35c2d4cf6ba3
|