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