Print this page
10886 smatch debug macro cleanup in usr/src/uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/bscbus.c
+++ new/usr/src/uts/common/io/bscbus.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
↓ open down ↓ |
14 lines elided |
↑ open up ↑ |
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 *
25 + * Copyright 2019 Joyent, Inc.
26 + *
25 27 * The "bscbus" driver provides access to the LOMlite2 virtual registers,
26 28 * so that its clients (children) need not be concerned with the details
27 29 * of the access mechanism, which in this case is implemented via a
28 30 * packet-based protocol over a Xbus (similar to ebus) parallel link to the
29 31 * H8 host interface registers.
30 32 *
31 33 * On the other hand, this driver doesn't generally know what the virtual
32 34 * registers signify - only the clients need this information.
33 35 */
34 36
35 37
36 38 #include <sys/note.h>
37 39 #include <sys/types.h>
38 40 #include <sys/conf.h>
39 41 #include <sys/debug.h>
40 42 #include <sys/errno.h>
41 43 #include <sys/file.h>
42 44
43 45 #if defined(__sparc)
44 46 #include <sys/intr.h>
45 47 #include <sys/membar.h>
46 48 #endif
47 49
48 50 #include <sys/kmem.h>
49 51 #include <sys/modctl.h>
50 52 #include <sys/note.h>
51 53 #include <sys/open.h>
52 54 #include <sys/poll.h>
53 55 #include <sys/spl.h>
54 56 #include <sys/stat.h>
55 57 #include <sys/strlog.h>
56 58 #include <sys/atomic.h>
57 59
58 60 #include <sys/ddi.h>
59 61 #include <sys/sunddi.h>
60 62 #include <sys/sunndi.h>
61 63
62 64 #include <sys/bscbus.h>
63 65
64 66 #if defined(NDI_ACC_HDL_V2)
65 67
66 68 /*
67 69 * Compiling for Solaris 10+ with access handle enhancements
68 70 */
69 71 #define HANDLE_TYPE ndi_acc_handle_t
70 72 #define HANDLE_ADDR(hdlp) (hdlp->ah_addr)
71 73 #define HANDLE_FAULT(hdlp) (hdlp->ah_fault)
72 74 #define HANDLE_MAPLEN(hdlp) (hdlp->ah_len)
73 75 #define HANDLE_PRIVATE(hdlp) (hdlp->ah_bus_private)
74 76
75 77 #else
76 78
77 79 /*
78 80 * Compatibility definitions for backport to Solaris 8/9
79 81 */
80 82 #define HANDLE_TYPE ddi_acc_impl_t
81 83 #define HANDLE_ADDR(hdlp) (hdlp->ahi_common.ah_addr)
82 84 #define HANDLE_FAULT(hdlp) (hdlp->ahi_fault)
83 85 #define HANDLE_MAPLEN(hdlp) (hdlp->ahi_common.ah_len)
84 86 #define HANDLE_PRIVATE(hdlp) (hdlp->ahi_common.ah_bus_private)
85 87
86 88 #define ddi_driver_major(dip) ddi_name_to_major(ddi_binding_name(dip))
87 89
88 90 #endif /* NDI_ACC_HDL_V2 */
89 91
90 92
91 93 /*
92 94 * Local definitions
93 95 */
94 96 #define MYNAME "bscbus"
95 97 #define NOMAJOR (~(major_t)0)
96 98 #define DUMMY_VALUE (~(int8_t)0)
97 99
98 100 #define BSCBUS_INST_TO_MINOR(i) (i)
99 101 #define BSCBUS_MINOR_TO_INST(m) (m)
100 102
101 103 #define BSCBUS_MAX_CHANNELS (4)
102 104
103 105 #define BSCBUS_DUMMY_ADDRESS ((caddr_t)0x0CADD1ED)
104 106 #define ADDR_TO_OFFSET(a, hdlp) ((caddr_t)(a) - HANDLE_ADDR(hdlp))
105 107 #define ADDR_TO_VREG(a) ((caddr_t)(a) - BSCBUS_DUMMY_ADDRESS)
106 108 #define VREG_TO_ADDR(v) (BSCBUS_DUMMY_ADDRESS + (v))
107 109
108 110 #ifdef DEBUG
109 111 #define BSCBUS_LOGSTATUS
110 112 #endif /* DEBUG */
111 113
112 114 #ifdef BSCBUS_LOGSTATUS
113 115 /*
114 116 * BSC command logging routines.
115 117 * Record the data passing to and from the BSC
116 118 */
117 119
118 120 typedef enum {
119 121 BSC_CMD_BUSY = 1, /* bsc reports busy */
120 122 BSC_CMD_CLEARING = 2, /* clearing bsc busy */
121 123 BSC_CMD_CLEARED = 3, /* cleared bsc busy */
122 124 BSC_CMD_SENDING = 4, /* sending next byte */
123 125 BSC_CMD_SENT = 5, /* sending last byte */
124 126 BSC_CMD_PENDING = 6, /* got sent byte ack */
125 127 BSC_CMD_REPLY = 7, /* got reply byte */
126 128 BSC_CMD_COMPLETE = 8, /* command complete */
127 129 BSC_CMD_ERROR_SEQ = 9, /* error status */
128 130 BSC_CMD_ERROR_STATUS = 10, /* error status */
129 131 BSC_CMD_ERROR_OFLOW = 11, /* error status */
130 132 BSC_CMD_ERROR_TOUT = 12, /* error status */
131 133
132 134 BSC_CMD_PROCESS = 13, /* async intr */
133 135 BSC_CMD_V1INTR = 14, /* v1 intr */
134 136 BSC_CMD_V1INTRUNCL = 15, /* v1 intr unclaim */
135 137 BSC_CMD_DOGPAT = 17 /* watchdog pat */
136 138 } bsc_cmd_stamp_t;
137 139
138 140 typedef struct {
139 141 hrtime_t bcl_now;
140 142 int bcl_seq;
141 143 bsc_cmd_stamp_t bcl_cat;
142 144 uint8_t bcl_chno;
143 145 uint8_t bcl_cmdstate;
144 146 uint8_t bcl_status;
145 147 uint8_t bcl_data;
146 148 } bsc_cmd_log_t;
147 149
148 150 uint32_t bscbus_cmd_log_size = 1024;
149 151
150 152 uint32_t bscbus_cmd_log_flags = 0xffffffff;
151 153
152 154 #endif /* BSCBUS_LOGSTATUS */
153 155
154 156 /*
155 157 * The following definitions are taken from the Hardware Manual for
156 158 * the Hitachi H8S/2148 in conjunction with the hardware specification
157 159 * for the Stiletto blade.
158 160 *
159 161 * Each instance of the host interface has 3 registers on the H8:
160 162 * IDRn - Input Data Register - write-only for Solaris.
161 163 * writes to this can be done via two
162 164 * addresses - control and data.
163 165 * The H8 can determine which address was
164 166 * written by examining the C/D bit in
165 167 * the status register.
166 168 * ODRn - Output Data Register - read-only for Solaris.
167 169 * A read has the side effect of acknowledging
168 170 * interrupts.
169 171 * STRn - Status Register - read-only for Solaris.
170 172 *
171 173 *
172 174 *
173 175 * In terms of host access to this the Input and Output data registers are
174 176 * mapped at the same address.
175 177 */
176 178 #define H8_IDRD 0
177 179 #define H8_IDRC 1
178 180 #define H8_ODR 0
179 181 #define H8_STR 1
180 182
181 183 #define H8_STR_OBF 0x01 /* data available in ODR */
182 184 #define H8_STR_IBF 0x02 /* data for H8 in IDR */
183 185 #define H8_STR_IDRC 0x08 /* last write to IDR was to IDRC */
184 186 /* 0=data, 1=command */
185 187 #define H8_STR_BUSY 0x04 /* H8 busy processing command */
186 188 #define H8_STR_TOKENPROTOCOL 0x80 /* token-passing protocol */
187 189
188 190 /*
189 191 * Packet format ...
190 192 */
191 193 #define BSCBUS_MASK 0xc0 /* Byte-type bits */
192 194 #define BSCBUS_PARAM 0x00 /* Parameter byte: 0b0xxxxxxx */
193 195 #define BSCBUS_LAST 0x80 /* Last byte of packet */
194 196 #define BSCBUS_CMD 0x80 /* Command byte: 0b10###XWV */
195 197 #define BSCBUS_STATUS 0xc0 /* Status byte: 0b11###AEV */
196 198
197 199 #define BSCBUS_SEQ 0x38 /* Sequence number bits */
198 200 #define BSCBUS_SEQ_LSB 0x08 /* Sequence number LSB */
199 201 #define BSCBUS_CMD_XADDR 0x04 /* Extended (2-byte) addressing */
200 202 #define BSCBUS_CMD_WRITE 0x02 /* Write command */
201 203 #define BSCBUS_CMD_WMSB 0x01 /* Set MSB on Write */
202 204 #define BSCBUS_CMD_READ 0x01 /* Read command */
203 205 #define BSCBUS_CMD_NOP 0x00 /* NOP command */
204 206
205 207 #define BSCBUS_STATUS_ASYNC 0x04 /* Asynchronous event pending */
206 208 #define BSCBUS_STATUS_ERR 0x02 /* Error in command processing */
207 209 #define BSCBUS_STATUS_MSB 0x01 /* MSB of Value read */
208 210
209 211 #define BSCBUS_VREG_LO(x) ((x) & ((1 << 7) - 1))
210 212 #define BSCBUS_VREG_HI(x) ((x) >> 7)
211 213
212 214 #define BSCBUS_BUFSIZE 8
213 215
214 216 #define BSCBUS_CHANNEL_TO_OFFSET(chno) ((chno) * 2) /* Register offset */
215 217
216 218 /*
217 219 * Time periods, in nanoseconds
218 220 *
219 221 * Note that LOMBUS_ONE_SEC and some other time
220 222 * periods are defined in <sys/lombus.h>
221 223 */
222 224 #define BSCBUS_CMD_POLL (LOMBUS_ONE_SEC)
223 225 #define BSCBUS_CMD_POLLNOINTS (LOMBUS_ONE_SEC/20)
224 226 #define BSCBUS_HWRESET_POLL (LOMBUS_ONE_SEC/20)
225 227 #define BSCBUS_HWRESET_TIMEOUT (LOMBUS_ONE_SEC*2)
226 228
227 229 #define BSCBUS_DOG_PAT_POLL_LIMIT (1000)
228 230 #define BSCBUS_DOG_PAT_POLL (1)
229 231 #define BSCBUS_PAT_RETRY_LIMIT 5
230 232
231 233 /*
232 234 * Local datatypes
233 235 */
234 236 enum bscbus_cmdstate {
235 237 BSCBUS_CMDSTATE_IDLE, /* No transaction in progress */
236 238 BSCBUS_CMDSTATE_BUSY, /* Setting up command */
237 239 BSCBUS_CMDSTATE_CLEARING, /* Clearing firmware busy status */
238 240 BSCBUS_CMDSTATE_SENDING, /* Waiting to send data to f/w */
239 241 BSCBUS_CMDSTATE_PENDING, /* Waiting for ack from f/w */
240 242 BSCBUS_CMDSTATE_WAITING, /* Waiting for status from f/w */
241 243 BSCBUS_CMDSTATE_READY, /* Status received/command done */
242 244 BSCBUS_CMDSTATE_ERROR /* Command failed with error */
243 245 };
244 246
245 247 struct bscbus_channel_state {
246 248 /* Changes to these are protected by the instance ch_mutex mutex */
247 249 struct bscbus_state *ssp;
248 250 uint8_t *ch_regs;
249 251 ddi_acc_handle_t ch_handle; /* per channel access handle */
250 252 unsigned int chno;
251 253 unsigned int map_count; /* Number of mappings to channel */
252 254 boolean_t map_dog; /* channel is mapped for watchdog */
253 255
254 256 /*
255 257 * Flag to indicate that we've incurred a hardware fault on
256 258 * accesses to the H8; once this is set, we fake all further
257 259 * accesses in order not to provoke additional bus errors.
258 260 */
259 261 boolean_t xio_fault;
260 262
261 263 /*
262 264 * Data protected by the dog_mutex: the watchdog-patting
263 265 * protocol data (since the dog can be patted from a high-level
264 266 * cyclic), and the interrupt-enabled flag.
265 267 */
266 268 kmutex_t dog_mutex[1];
267 269 unsigned int pat_retry_count;
268 270 unsigned int pat_fail_count;
269 271
270 272 /*
271 273 * Serial protocol state data, protected by lo_mutex
272 274 * (which is initialised using <lo_iblk>)
273 275 */
274 276 kmutex_t lo_mutex[1];
275 277 ddi_iblock_cookie_t lo_iblk;
276 278 kcondvar_t lo_cv[1];
277 279 int unclaimed_count;
278 280
279 281 volatile enum bscbus_cmdstate cmdstate;
280 282 clock_t deadline;
281 283 clock_t poll_hz;
282 284 boolean_t interrupt_failed;
283 285 uint8_t cmdbuf[BSCBUS_BUFSIZE];
284 286 uint8_t *cmdp; /* Points to last tx'd in cmdbuf */
285 287 uint8_t reply[BSCBUS_BUFSIZE];
286 288 uint8_t async;
287 289 uint8_t index;
288 290 uint8_t result;
289 291 uint8_t sequence;
290 292 uint32_t error;
291 293 };
292 294
293 295 #define BSCBUS_TX_PENDING(csp) ((csp)->cmdp > (csp)->cmdbuf)
294 296
295 297 /*
296 298 * This driver's soft-state structure
297 299 */
298 300
299 301 struct bscbus_state {
300 302 /*
301 303 * Configuration data, set during attach
302 304 */
303 305 dev_info_t *dip;
304 306 major_t majornum;
305 307 int instance;
306 308
307 309 ddi_acc_handle_t h8_handle;
308 310 uint8_t *h8_regs;
309 311
310 312 /*
311 313 * Parameters derived from .conf properties
312 314 */
313 315 uint32_t debug;
314 316
315 317 /*
316 318 * Flag to indicate that we are using per channel
317 319 * mapping of the register sets and interrupts.
318 320 * reg set 0 is chan 0
319 321 * reg set 1 is chan 1 ...
320 322 *
321 323 * Interrupts are specified in that order but later
322 324 * channels may not have interrupts.
323 325 */
324 326 boolean_t per_channel_regs;
325 327
326 328 /*
327 329 * channel state data, protected by ch_mutex
328 330 * channel claim/release requests are protected by this mutex.
329 331 */
330 332 kmutex_t ch_mutex[1];
331 333 struct bscbus_channel_state channel[BSCBUS_MAX_CHANNELS];
332 334
333 335 #ifdef BSCBUS_LOGSTATUS
334 336 /*
335 337 * Command logging buffer for recording transactions with the
336 338 * BSC. This is useful for debugging failed transactions and other
337 339 * such funnies.
338 340 */
339 341 bsc_cmd_log_t *cmd_log;
340 342 uint32_t cmd_log_idx;
341 343 uint32_t cmd_log_size;
342 344 uint32_t cmd_log_flags;
343 345 #endif /* BSCBUS_LOGSTATUS */
344 346 };
345 347
346 348 /*
347 349 * The auxiliary structure attached to each child
348 350 * (the child's parent-private-data points to this).
349 351 */
350 352 struct bscbus_child_info {
351 353 lombus_regspec_t *rsp;
352 354 int nregs;
353 355 };
354 356
355 357 #ifdef BSCBUS_LOGSTATUS
356 358 void bscbus_cmd_log(struct bscbus_channel_state *, bsc_cmd_stamp_t,
357 359 uint8_t, uint8_t);
358 360 #else /* BSCBUS_LOGSTATUS */
359 361 #define bscbus_cmd_log(state, stamp, status, data)
360 362 #endif /* BSCBUS_LOGSTATUS */
361 363
362 364
363 365 /*
364 366 * Local data
365 367 */
366 368
367 369 static void *bscbus_statep;
368 370
369 371 static major_t bscbus_major = NOMAJOR;
370 372
371 373 static ddi_device_acc_attr_t bscbus_dev_acc_attr[1] = {
372 374 DDI_DEVICE_ATTR_V0,
373 375 DDI_STRUCTURE_LE_ACC,
374 376 DDI_STRICTORDER_ACC
375 377 };
376 378
377 379
378 380 /*
379 381 * General utility routines ...
380 382 */
381 383
382 384 #ifdef DEBUG
383 385 static void
384 386 bscbus_trace(struct bscbus_channel_state *csp, char code, const char *caller,
385 387 const char *fmt, ...)
386 388 {
387 389 char buf[256];
388 390 char *p;
389 391 va_list va;
390 392
391 393 if (csp->ssp->debug & (1 << (code-'@'))) {
392 394 p = buf;
393 395 (void) snprintf(p, sizeof (buf) - (p - buf),
394 396 "%s/%s: ", MYNAME, caller);
395 397 p += strlen(p);
396 398
↓ open down ↓ |
362 lines elided |
↑ open up ↑ |
397 399 va_start(va, fmt);
398 400 (void) vsnprintf(p, sizeof (buf) - (p - buf), fmt, va);
399 401 va_end(va);
400 402
401 403 buf[sizeof (buf) - 1] = '\0';
402 404 (void) strlog(csp->ssp->majornum, csp->ssp->instance,
403 405 code, SL_TRACE, buf);
404 406 }
405 407 }
406 408 #else /* DEBUG */
407 -#define bscbus_trace
409 +#define bscbus_trace(...) (void)(0)
408 410 #endif /* DEBUG */
409 411
410 412 static struct bscbus_state *
411 413 bscbus_getstate(dev_info_t *dip, int instance, const char *caller)
412 414 {
413 415 struct bscbus_state *ssp = NULL;
414 416 dev_info_t *sdip = NULL;
415 417 major_t dmaj = NOMAJOR;
416 418
417 419 if (dip != NULL) {
418 420 /*
419 421 * Use the instance number from the <dip>; also,
420 422 * check that it really corresponds to this driver
421 423 */
422 424 instance = ddi_get_instance(dip);
423 425 dmaj = ddi_driver_major(dip);
424 426 if (bscbus_major == NOMAJOR && dmaj != NOMAJOR)
425 427 bscbus_major = dmaj;
426 428 else if (dmaj != bscbus_major) {
427 429 cmn_err(CE_WARN,
428 430 "%s: major number mismatch (%d vs. %d) in %s(),"
429 431 "probably due to child misconfiguration",
430 432 MYNAME, bscbus_major, dmaj, caller);
431 433 instance = -1;
432 434 }
433 435 }
434 436
435 437 if (instance >= 0)
436 438 ssp = ddi_get_soft_state(bscbus_statep, instance);
437 439 if (ssp != NULL) {
438 440 sdip = ssp->dip;
439 441 if (dip == NULL && sdip == NULL)
440 442 ssp = NULL;
441 443 else if (dip != NULL && sdip != NULL && sdip != dip) {
442 444 cmn_err(CE_WARN,
443 445 "%s: devinfo mismatch (%p vs. %p) in %s(), "
444 446 "probably due to child misconfiguration",
445 447 MYNAME, (void *)dip, (void *)sdip, caller);
446 448 ssp = NULL;
447 449 }
448 450 }
449 451
450 452 return (ssp);
451 453 }
452 454
453 455 /*
454 456 * Lowest-level I/O register read/write
455 457 */
456 458
457 459 static void
458 460 bscbus_put_reg(struct bscbus_channel_state *csp, uint_t reg, uint8_t val)
459 461 {
460 462 if (csp->ch_handle != NULL && !csp->xio_fault) {
461 463 ddi_put8(csp->ch_handle,
462 464 csp->ch_regs + reg, val);
463 465 }
464 466 }
465 467
466 468 static uint8_t
467 469 bscbus_get_reg(struct bscbus_channel_state *csp, uint_t reg)
468 470 {
469 471 uint8_t val;
470 472
471 473 if (csp->ch_handle != NULL && !csp->xio_fault)
472 474 val = ddi_get8(csp->ch_handle,
473 475 csp->ch_regs + reg);
474 476 else
475 477 val = DUMMY_VALUE;
476 478
477 479 return (val);
478 480 }
479 481
480 482 static void
481 483 bscbus_check_fault_status(struct bscbus_channel_state *csp)
482 484 {
483 485 csp->xio_fault =
484 486 ddi_check_acc_handle(csp->ch_handle) != DDI_SUCCESS;
485 487 }
486 488
487 489 static boolean_t
488 490 bscbus_faulty(struct bscbus_channel_state *csp)
489 491 {
490 492 if (!csp->xio_fault)
491 493 bscbus_check_fault_status(csp);
492 494 return (csp->xio_fault);
493 495 }
494 496
495 497 /*
496 498 * Write data into h8 registers
497 499 */
498 500 static void
499 501 bscbus_pat_dog(struct bscbus_channel_state *csp, uint8_t val)
500 502 {
501 503 uint8_t status;
502 504 uint32_t doglimit = BSCBUS_DOG_PAT_POLL_LIMIT;
503 505
504 506 bscbus_trace(csp, 'W', "bscbus_pat_dog:", "");
505 507
506 508 bscbus_cmd_log(csp, BSC_CMD_DOGPAT, 0, val);
507 509 status = bscbus_get_reg(csp, H8_STR);
508 510 while (status & H8_STR_IBF) {
509 511 if (csp->pat_retry_count > BSCBUS_PAT_RETRY_LIMIT) {
510 512 /*
511 513 * Previous attempts to contact BSC have failed.
512 514 * Do not bother waiting for it to eat previous
513 515 * data.
514 516 * Pat anyway just in case the BSC is really alive
515 517 * and the IBF bit is lying.
516 518 */
517 519 bscbus_put_reg(csp, H8_IDRC, val);
518 520 bscbus_trace(csp, 'W', "bscbus_pat_dog:",
519 521 "retry count exceeded");
520 522 return;
521 523 }
522 524 if (--doglimit == 0) {
523 525 /* The BSC is not responding - give up */
524 526 csp->pat_fail_count++;
525 527 csp->pat_retry_count++;
526 528 /* Pat anyway just in case the BSC is really alive */
527 529 bscbus_put_reg(csp, H8_IDRC, val);
528 530 bscbus_trace(csp, 'W', "bscbus_pat_dog:",
529 531 "poll limit exceeded");
530 532 return;
531 533 }
532 534 drv_usecwait(BSCBUS_DOG_PAT_POLL);
533 535 status = bscbus_get_reg(csp, H8_STR);
534 536 }
535 537 bscbus_put_reg(csp, H8_IDRC, val);
536 538 csp->pat_retry_count = 0;
537 539 }
538 540
539 541 /*
540 542 * State diagrams for how bscbus_process works.
541 543 * BSCBUS_CMDSTATE_IDLE No transaction in progress
542 544 * BSCBUS_CMDSTATE_BUSY Setting up command
543 545 * BSCBUS_CMDSTATE_CLEARING Clearing firmware busy status
544 546 * BSCBUS_CMDSTATE_SENDING Waiting to send data to f/w
545 547 * BSCBUS_CMDSTATE_PENDING Waiting for ack from f/w
546 548 * BSCBUS_CMDSTATE_WAITING Waiting for status from f/w
547 549 * BSCBUS_CMDSTATE_READY Status received/command done
548 550 * BSCBUS_CMDSTATE_ERROR Command failed with error
549 551 *
550 552 * +----------+
551 553 * | |
552 554 * | IDLE/BUSY|
553 555 * | (0/1) | abnormal
554 556 * +----------+ state
555 557 * | \ detected
556 558 * | \------>------+ +----<---+
557 559 * bsc | | | |
558 560 * is | V V |
559 561 * ready| +----------+ |
560 562 * | | | ^
561 563 * | | CLEARING | |
562 564 * | | (2) | |
563 565 * | +----------+ |
564 566 * | cleared / | \ | more to clear
565 567 * | / | \-->--+
566 568 * | +-------<-------/ V
567 569 * | | |
568 570 * V V |timeout
569 571 * +----------+ timeout |
570 572 * | |------>---------+--------+
571 573 * | SENDING | |
572 574 * | (3) |------<-------+ |
573 575 * +----------+ | V
574 576 * sent| \ send ^ack |
575 577 * last| \ next |received |
576 578 * | \ +----------+ |
577 579 * | \ | | |
578 580 * | \------>| PENDING |-->-+
579 581 * | | (4) | |
580 582 * | +----------+ |timeout
581 583 * | +---<----+ |
582 584 * | | | |
583 585 * V V | |
584 586 * +----------+ | |
585 587 * | | | |
586 588 * | WAITING | ^ |
587 589 * | (5) | | |
588 590 * +----------+ | |
589 591 * | | |more | |
590 592 * | V |required| |
591 593 * done| | +--->----+ |
592 594 * | +--->--------------+ +---<---+
593 595 * | error/timeout | |
594 596 * V V V
595 597 * +----------+ +----------+
596 598 * | | | |
597 599 * | READY | | ERROR |
598 600 * | (7) | | (6) |
599 601 * +----------+ +----------+
600 602 * | |
601 603 * V V
602 604 * | |
603 605 * +------>---+---<------+
604 606 * |
605 607 * |
606 608 * Back to
607 609 * Idle
608 610 */
609 611
610 612 static void
611 613 bscbus_process_sending(struct bscbus_channel_state *csp, uint8_t status)
612 614 {
613 615 /*
614 616 * When we get here we actually expect H8_STR_IBF to
615 617 * be clear but we check just in case of problems.
616 618 */
617 619 ASSERT(BSCBUS_TX_PENDING(csp));
618 620 if (!(status & H8_STR_IBF)) {
619 621 bscbus_put_reg(csp, H8_IDRD, *--csp->cmdp);
620 622 bscbus_trace(csp, 'P', "bscbus_process_sending",
621 623 "state %d; val $%x",
622 624 csp->cmdstate, *csp->cmdp);
623 625 if (!BSCBUS_TX_PENDING(csp)) {
624 626 bscbus_cmd_log(csp, BSC_CMD_SENT,
625 627 status, *csp->cmdp);
626 628 /* No more pending - move to waiting state */
627 629 bscbus_trace(csp, 'P', "bscbus_process_sending",
628 630 "moving to waiting");
629 631 csp->cmdstate = BSCBUS_CMDSTATE_WAITING;
630 632 /* Extend deadline because time has moved on */
631 633 csp->deadline = ddi_get_lbolt() +
632 634 drv_usectohz(LOMBUS_CMD_TIMEOUT/1000);
633 635 } else {
634 636 /* Wait for ack of this byte */
635 637 bscbus_cmd_log(csp, BSC_CMD_SENDING,
636 638 status, *csp->cmdp);
637 639 csp->cmdstate = BSCBUS_CMDSTATE_PENDING;
638 640 bscbus_trace(csp, 'P', "bscbus_process_sending",
639 641 "moving to pending");
640 642 }
641 643 }
642 644 }
643 645
644 646 static void
645 647 bscbus_process_clearing(struct bscbus_channel_state *csp,
646 648 uint8_t status, uint8_t data)
647 649 {
648 650 /*
649 651 * We only enter this state if H8_STR_BUSY was set when
650 652 * we started the transaction. We just ignore all received
651 653 * data until we see OBF set AND BUSY cleared.
652 654 * It is not good enough to see BUSY clear on its own
653 655 */
654 656 if ((status & H8_STR_OBF) && !(status & H8_STR_BUSY)) {
655 657 bscbus_cmd_log(csp, BSC_CMD_CLEARED, status, data);
656 658 csp->cmdstate = BSCBUS_CMDSTATE_SENDING;
657 659 /* Throw away any data received up until now */
658 660 bscbus_trace(csp, 'P', "bscbus_process_clearing",
659 661 "busy cleared");
660 662 /*
661 663 * Send the next byte immediately.
662 664 * At this stage we should clear the OBF flag because that
663 665 * data has been used. IBF is still valid so do not clear that.
664 666 */
665 667 status &= ~(H8_STR_OBF);
666 668 bscbus_process_sending(csp, status);
667 669 } else {
668 670 if (status & H8_STR_OBF) {
669 671 bscbus_cmd_log(csp, BSC_CMD_CLEARING, status, data);
670 672 }
671 673 }
672 674 }
673 675
674 676 static void
675 677 bscbus_process_pending(struct bscbus_channel_state *csp, uint8_t status)
676 678 {
677 679 /* We are waiting for an acknowledgement of a byte */
678 680 if (status & H8_STR_OBF) {
679 681 bscbus_cmd_log(csp, BSC_CMD_PENDING,
680 682 status, *csp->cmdp);
681 683 bscbus_trace(csp, 'P', "bscbus_process_pending",
682 684 "moving to sending");
683 685 csp->cmdstate = BSCBUS_CMDSTATE_SENDING;
684 686 /*
685 687 * Send the next byte immediately.
686 688 * At this stage we should clear the OBF flag because that
687 689 * data has been used. IBF is still valid so do not clear that.
688 690 */
689 691 status &= ~(H8_STR_OBF);
690 692 bscbus_process_sending(csp, status);
691 693 }
692 694 }
693 695
694 696 static boolean_t
695 697 bscbus_process_waiting(struct bscbus_channel_state *csp,
696 698 uint8_t status, uint8_t data)
697 699 {
698 700 uint8_t rcvd = 0;
699 701 boolean_t ready = B_FALSE;
700 702 uint8_t tmp;
701 703
702 704 if (status & H8_STR_OBF) {
703 705 csp->reply[rcvd = csp->index] = data;
704 706 if (++rcvd < BSCBUS_BUFSIZE)
705 707 csp->index = rcvd;
706 708
707 709 bscbus_trace(csp, 'D', "bscbus_process_waiting",
708 710 "rcvd %d: $%02x $%02x $%02x $%02x $%02x $%02x $%02x $%02x",
709 711 rcvd,
710 712 csp->reply[0], csp->reply[1],
711 713 csp->reply[2], csp->reply[3],
712 714 csp->reply[4], csp->reply[5],
713 715 csp->reply[6], csp->reply[7]);
714 716 }
715 717
716 718 if (rcvd == 0) {
717 719 /*
718 720 * No bytes received this time through (though there
719 721 * might be a partial packet sitting in the buffer).
720 722 */
721 723 /* EMPTY */
722 724 ;
723 725 } else if (rcvd >= BSCBUS_BUFSIZE) {
724 726 /*
725 727 * Buffer overflow; discard the data & treat as an error
726 728 * (even if the last byte read did claim to terminate a
727 729 * packet, it can't be a valid one 'cos it's too long!)
728 730 */
729 731 bscbus_cmd_log(csp, BSC_CMD_ERROR_OFLOW, status, data);
730 732 csp->index = 0;
731 733 csp->cmdstate = BSCBUS_CMDSTATE_ERROR;
732 734 csp->error = LOMBUS_ERR_OFLOW;
733 735 ready = B_TRUE;
734 736 } else if ((data & BSCBUS_LAST) == 0) {
735 737 /*
736 738 * Packet not yet complete; leave the partial packet in
737 739 * the buffer for later ...
738 740 */
739 741 bscbus_cmd_log(csp, BSC_CMD_REPLY, status, data);
740 742 } else if ((data & BSCBUS_MASK) != BSCBUS_STATUS) {
741 743 /* Invalid "status" byte - maybe an echo of the command? */
742 744 bscbus_cmd_log(csp, BSC_CMD_ERROR_STATUS, status, data);
743 745
744 746 csp->cmdstate = BSCBUS_CMDSTATE_ERROR;
745 747 csp->error = LOMBUS_ERR_BADSTATUS;
746 748 ready = B_TRUE;
747 749 } else if ((data & BSCBUS_SEQ) != csp->sequence) {
748 750 /* Wrong sequence number! Flag this as an error */
749 751 bscbus_cmd_log(csp, BSC_CMD_ERROR_SEQ, status, data);
750 752
751 753 csp->cmdstate = BSCBUS_CMDSTATE_ERROR;
752 754 csp->error = LOMBUS_ERR_SEQUENCE;
753 755 ready = B_TRUE;
754 756 } else {
755 757 /*
756 758 * Finally, we know that's it's a valid reply to our
757 759 * last command. Update the ASYNC status, derive the
758 760 * reply parameter (if any), and check the ERROR bit
759 761 * to find out what the parameter means.
760 762 *
761 763 * Note that not all the values read/assigned here
762 764 * are meaningful, but it doesn't matter; the waiting
763 765 * thread will know which one(s) it should check.
764 766 */
765 767 bscbus_cmd_log(csp, BSC_CMD_COMPLETE, status, data);
766 768 csp->async = (data & BSCBUS_STATUS_ASYNC) ? 1 : 0;
767 769
768 770 tmp = ((data & BSCBUS_STATUS_MSB) ? 0x80 : 0) | csp->reply[0];
769 771 if (data & BSCBUS_STATUS_ERR) {
770 772 csp->cmdstate = BSCBUS_CMDSTATE_ERROR;
771 773 csp->error = tmp;
772 774 } else {
773 775 csp->cmdstate = BSCBUS_CMDSTATE_READY;
774 776 csp->result = tmp;
775 777 }
776 778 ready = B_TRUE;
777 779 }
778 780 return (ready);
779 781 }
780 782
781 783 /*
782 784 * Packet receive handler
783 785 *
784 786 * This routine should be called from the low-level softint,
785 787 * or bscbus_cmd() (for polled operation), with the
786 788 * low-level mutex already held.
787 789 */
788 790 static void
789 791 bscbus_process(struct bscbus_channel_state *csp,
790 792 uint8_t status, uint8_t data)
791 793 {
792 794 boolean_t ready = B_FALSE;
793 795
794 796 ASSERT(mutex_owned(csp->lo_mutex));
795 797
796 798 if ((status & H8_STR_OBF) || (status & H8_STR_IBF)) {
797 799 bscbus_trace(csp, 'D', "bscbus_process",
798 800 "state %d; error $%x",
799 801 csp->cmdstate, csp->error);
800 802 }
801 803
802 804 switch (csp->cmdstate) {
803 805 case BSCBUS_CMDSTATE_CLEARING:
804 806 bscbus_process_clearing(csp, status, data);
805 807 break;
806 808 case BSCBUS_CMDSTATE_SENDING:
807 809 bscbus_process_sending(csp, status);
808 810 break;
809 811 case BSCBUS_CMDSTATE_PENDING:
810 812 bscbus_process_pending(csp, status);
811 813 break;
812 814 case BSCBUS_CMDSTATE_WAITING:
813 815 ready = bscbus_process_waiting(csp, status, data);
814 816 break;
815 817 default:
816 818 /* Nothing to do */
817 819 break;
818 820 }
819 821
820 822 /*
821 823 * Check for timeouts - but only if the command has not yet
822 824 * completed (ready is true when command completes in this
823 825 * call to bscbus_process OR cmdstate is READY or ERROR if
824 826 * this is a spurious call to bscbus_process i.e. a spurious
825 827 * interrupt)
826 828 */
827 829 if (!ready &&
828 830 ((ddi_get_lbolt() - csp->deadline) > 0) &&
829 831 csp->cmdstate != BSCBUS_CMDSTATE_READY &&
830 832 csp->cmdstate != BSCBUS_CMDSTATE_ERROR) {
831 833 bscbus_trace(csp, 'P', "bscbus_process",
832 834 "timeout previous state %d; error $%x",
833 835 csp->cmdstate, csp->error);
834 836 bscbus_cmd_log(csp, BSC_CMD_ERROR_TOUT, status, data);
835 837 if (csp->cmdstate == BSCBUS_CMDSTATE_CLEARING) {
836 838 /* Move onto sending because busy might be stuck */
837 839 csp->cmdstate = BSCBUS_CMDSTATE_SENDING;
838 840 /* Extend timeout relative to original start time */
839 841 csp->deadline += drv_usectohz(LOMBUS_CMD_TIMEOUT/1000);
840 842 } else if (csp->cmdstate != BSCBUS_CMDSTATE_IDLE) {
841 843 csp->cmdstate = BSCBUS_CMDSTATE_ERROR;
842 844 csp->error = LOMBUS_ERR_TIMEOUT;
843 845 }
844 846 ready = B_TRUE;
845 847 }
846 848
847 849 if ((status & H8_STR_OBF) || (status & H8_STR_IBF) || ready) {
848 850 bscbus_trace(csp, 'D', "bscbus_process",
849 851 "last $%02x; state %d; error $%x; ready %d",
850 852 data, csp->cmdstate, csp->error, ready);
851 853 }
852 854 if (ready)
853 855 cv_broadcast(csp->lo_cv);
854 856 }
855 857
856 858 static uint_t
857 859 bscbus_hwintr(caddr_t arg)
858 860 {
859 861 struct bscbus_channel_state *csp = (void *)arg;
860 862
861 863 uint8_t status;
862 864 uint8_t data = 0xb0 /* Dummy value */;
863 865
864 866 mutex_enter(csp->lo_mutex);
865 867 /*
866 868 * Read the registers to ensure that the interrupt is cleared.
867 869 * Status must be read first because reading data changes the
868 870 * status.
869 871 * We always read the data because that clears the interrupt down.
870 872 * This is horrible hardware semantics but we have to do it!
871 873 */
872 874 status = bscbus_get_reg(csp, H8_STR);
873 875 data = bscbus_get_reg(csp, H8_ODR);
874 876 if (!(status & H8_STR_OBF)) {
875 877 bscbus_cmd_log(csp, BSC_CMD_V1INTRUNCL, status, data);
876 878 csp->unclaimed_count++;
877 879 } else {
878 880 bscbus_cmd_log(csp, BSC_CMD_V1INTR, status, data);
879 881 }
880 882 if (status & H8_STR_TOKENPROTOCOL) {
881 883 bscbus_process(csp, status, data);
882 884 if (csp->interrupt_failed) {
883 885 bscbus_trace(csp, 'I', "bscbus_hwintr:",
884 886 "interrupt fault cleared channel %d", csp->chno);
885 887 csp->interrupt_failed = B_FALSE;
886 888 csp->poll_hz = drv_usectohz(BSCBUS_CMD_POLL / 1000);
887 889 }
888 890 }
889 891
890 892 mutex_exit(csp->lo_mutex);
891 893 return (DDI_INTR_CLAIMED);
892 894 }
893 895
894 896 void
895 897 bscbus_poll(struct bscbus_channel_state *csp)
896 898 {
897 899 /*
898 900 * This routine is only called if we timeout in userland
899 901 * waiting for an interrupt. This generally means that we have
900 902 * lost interrupt capabilities or that something has gone
901 903 * wrong. In this case we are allowed to access the hardware
902 904 * and read the data register if necessary.
903 905 * If interrupts return then recovery actions should mend us!
904 906 */
905 907 uint8_t status;
906 908 uint8_t data = 0xfa; /* Dummy value */
907 909
908 910 ASSERT(mutex_owned(csp->lo_mutex));
909 911
910 912 /* Should look for data to receive */
911 913 status = bscbus_get_reg(csp, H8_STR);
912 914 if (status & H8_STR_OBF) {
913 915 /* There is data available */
914 916 data = bscbus_get_reg(csp, H8_ODR);
915 917 bscbus_cmd_log(csp, BSC_CMD_PROCESS, status, data);
916 918 }
917 919 bscbus_process(csp, status, data);
918 920 }
919 921
920 922 /*
921 923 * Serial protocol
922 924 *
923 925 * This routine builds a command and sets it in progress.
924 926 */
925 927 static uint8_t
926 928 bscbus_cmd(HANDLE_TYPE *hdlp, ptrdiff_t vreg, uint_t val, uint_t cmd)
927 929 {
928 930 struct bscbus_channel_state *csp;
929 931 clock_t start;
930 932 uint8_t status;
931 933
932 934 /*
933 935 * First of all, wait for the interface to be available.
934 936 *
935 937 * NOTE: we blow through all the mutex/cv/state checking and
936 938 * preempt any command in progress if the system is panicking!
937 939 */
938 940 csp = HANDLE_PRIVATE(hdlp);
939 941 mutex_enter(csp->lo_mutex);
940 942 while (csp->cmdstate != BSCBUS_CMDSTATE_IDLE && !ddi_in_panic())
941 943 cv_wait(csp->lo_cv, csp->lo_mutex);
942 944
943 945 csp->cmdstate = BSCBUS_CMDSTATE_BUSY;
944 946 csp->sequence = (csp->sequence + BSCBUS_SEQ_LSB) & BSCBUS_SEQ;
945 947
946 948 /*
947 949 * We have exclusive ownership, so assemble the command (backwards):
948 950 *
949 951 * [byte 0] Command: modified by XADDR and/or WMSB bits
950 952 * [Optional] Parameter: Value to write (low 7 bits)
951 953 * [Optional] Parameter: Register number (high 7 bits)
952 954 * [Optional] Parameter: Register number (low 7 bits)
953 955 */
954 956 csp->cmdp = &csp->cmdbuf[0];
955 957 *csp->cmdp++ = BSCBUS_CMD | csp->sequence | cmd;
956 958 switch (cmd) {
957 959 case BSCBUS_CMD_WRITE:
958 960 *csp->cmdp++ = val & 0x7f;
959 961 if (val >= 0x80)
960 962 csp->cmdbuf[0] |= BSCBUS_CMD_WMSB;
961 963 /*FALLTHRU*/
962 964 case BSCBUS_CMD_READ:
963 965 if (BSCBUS_VREG_HI(vreg) != 0) {
964 966 *csp->cmdp++ = BSCBUS_VREG_HI(vreg);
965 967 csp->cmdbuf[0] |= BSCBUS_CMD_XADDR;
966 968 }
967 969 *csp->cmdp++ = BSCBUS_VREG_LO(vreg);
968 970 /*FALLTHRU*/
969 971 case BSCBUS_CMD_NOP:
970 972 break;
971 973 }
972 974
973 975 /*
974 976 * Check and update the H8 h/w fault status before accessing
975 977 * the chip registers. If there's a (new or previous) fault,
976 978 * we'll run through the protocol but won't really touch the
977 979 * hardware and all commands will timeout. If a previously
978 980 * discovered fault has now gone away (!), then we can (try to)
979 981 * proceed with the new command (probably a probe).
980 982 */
981 983 bscbus_check_fault_status(csp);
982 984
983 985 /*
984 986 * Prepare for the command (to be processed by the interrupt
985 987 * handler and/or polling loop below), and wait for a response
986 988 * or timeout.
987 989 */
988 990 start = ddi_get_lbolt();
989 991 csp->deadline = start + drv_usectohz(LOMBUS_CMD_TIMEOUT/1000);
990 992 csp->error = 0;
991 993 csp->index = 0;
992 994 csp->result = DUMMY_VALUE;
993 995
994 996 status = bscbus_get_reg(csp, H8_STR);
995 997 if (status & H8_STR_BUSY) {
996 998 bscbus_cmd_log(csp, BSC_CMD_BUSY, status, 0xfd);
997 999 /*
998 1000 * Must ensure that the busy state has cleared before
999 1001 * sending the command
1000 1002 */
1001 1003 csp->cmdstate = BSCBUS_CMDSTATE_CLEARING;
1002 1004 bscbus_trace(csp, 'P', "bscbus_cmd",
1003 1005 "h8 reporting status (%x) busy - clearing", status);
1004 1006 } else {
1005 1007 /* It is clear to send the command immediately */
1006 1008 csp->cmdstate = BSCBUS_CMDSTATE_SENDING;
1007 1009 bscbus_trace(csp, 'P', "bscbus_cmd",
1008 1010 "sending first byte of command, status %x", status);
1009 1011 bscbus_poll(csp);
1010 1012 }
1011 1013
1012 1014 csp->poll_hz = drv_usectohz(
1013 1015 (csp->interrupt_failed ?
1014 1016 BSCBUS_CMD_POLLNOINTS : BSCBUS_CMD_POLL) / 1000);
1015 1017
1016 1018 while ((csp->cmdstate != BSCBUS_CMDSTATE_READY) &&
1017 1019 (csp->cmdstate != BSCBUS_CMDSTATE_ERROR)) {
1018 1020 ASSERT(csp->cmdstate != BSCBUS_CMDSTATE_IDLE);
1019 1021
1020 1022 if ((cv_reltimedwait(csp->lo_cv, csp->lo_mutex,
1021 1023 csp->poll_hz, TR_CLOCK_TICK) == -1) &&
1022 1024 csp->cmdstate != BSCBUS_CMDSTATE_READY &&
1023 1025 csp->cmdstate != BSCBUS_CMDSTATE_ERROR) {
1024 1026 if (!csp->interrupt_failed) {
1025 1027 bscbus_trace(csp, 'I', "bscbus_cmd:",
1026 1028 "interrupt_failed channel %d", csp->chno);
1027 1029 csp->interrupt_failed = B_TRUE;
1028 1030 csp->poll_hz = drv_usectohz(
1029 1031 BSCBUS_CMD_POLLNOINTS / 1000);
1030 1032 }
1031 1033 bscbus_poll(csp);
1032 1034 }
1033 1035 }
1034 1036
1035 1037 /*
1036 1038 * The return value may not be meaningful but retrieve it anyway
1037 1039 */
1038 1040 val = csp->result;
1039 1041 if (bscbus_faulty(csp)) {
1040 1042 val = DUMMY_VALUE;
1041 1043 HANDLE_FAULT(hdlp) = LOMBUS_ERR_SIOHW;
1042 1044 } else if (csp->cmdstate != BSCBUS_CMDSTATE_READY) {
1043 1045 /*
1044 1046 * Some problem here ... transfer the error code from
1045 1047 * the per-instance state to the per-handle fault flag.
1046 1048 * The error code shouldn't be zero!
1047 1049 */
1048 1050 if (csp->error != 0)
1049 1051 HANDLE_FAULT(hdlp) = csp->error;
1050 1052 else
1051 1053 HANDLE_FAULT(hdlp) = LOMBUS_ERR_BADERRCODE;
1052 1054 }
1053 1055
1054 1056 /*
1055 1057 * All done now!
1056 1058 */
1057 1059 csp->index = 0;
1058 1060 csp->cmdstate = BSCBUS_CMDSTATE_IDLE;
1059 1061 cv_broadcast(csp->lo_cv);
1060 1062 mutex_exit(csp->lo_mutex);
1061 1063
1062 1064 return (val);
1063 1065 }
1064 1066
1065 1067 /*
1066 1068 * Space 0 - LOM virtual register access
1067 1069 * Only 8-bit accesses are supported.
1068 1070 */
1069 1071 static uint8_t
1070 1072 bscbus_vreg_get8(HANDLE_TYPE *hdlp, uint8_t *addr)
1071 1073 {
1072 1074 ptrdiff_t offset;
1073 1075
1074 1076 /*
1075 1077 * Check the offset that the caller has added to the base address
1076 1078 * against the length of the mapping originally requested.
1077 1079 */
1078 1080 offset = ADDR_TO_OFFSET(addr, hdlp);
1079 1081 if (offset < 0 || offset >= HANDLE_MAPLEN(hdlp)) {
1080 1082 /*
1081 1083 * Invalid access - flag a fault and return a dummy value
1082 1084 */
1083 1085 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_NUM;
1084 1086 return (DUMMY_VALUE);
1085 1087 }
1086 1088
1087 1089 /*
1088 1090 * Derive the virtual register number and run the command
1089 1091 */
1090 1092 return (bscbus_cmd(hdlp, ADDR_TO_VREG(addr), 0, BSCBUS_CMD_READ));
1091 1093 }
1092 1094
1093 1095 static void
1094 1096 bscbus_vreg_put8(HANDLE_TYPE *hdlp, uint8_t *addr, uint8_t val)
1095 1097 {
1096 1098 ptrdiff_t offset;
1097 1099
1098 1100 /*
1099 1101 * Check the offset that the caller has added to the base address
1100 1102 * against the length of the mapping originally requested.
1101 1103 */
1102 1104 offset = ADDR_TO_OFFSET(addr, hdlp);
1103 1105 if (offset < 0 || offset >= HANDLE_MAPLEN(hdlp)) {
1104 1106 /*
1105 1107 * Invalid access - flag a fault and return
1106 1108 */
1107 1109 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_NUM;
1108 1110 return;
1109 1111 }
1110 1112
1111 1113 /*
1112 1114 * Derive the virtual register number and run the command
1113 1115 */
1114 1116 (void) bscbus_cmd(hdlp, ADDR_TO_VREG(addr), val, BSCBUS_CMD_WRITE);
1115 1117 }
1116 1118
1117 1119 static void
1118 1120 bscbus_vreg_rep_get8(HANDLE_TYPE *hdlp, uint8_t *host_addr,
1119 1121 uint8_t *dev_addr, size_t repcount, uint_t flags)
1120 1122 {
1121 1123 size_t inc;
1122 1124
1123 1125 inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0;
1124 1126 for (; repcount--; dev_addr += inc)
1125 1127 *host_addr++ = bscbus_vreg_get8(hdlp, dev_addr);
1126 1128 }
1127 1129
1128 1130 static void
1129 1131 bscbus_vreg_rep_put8(HANDLE_TYPE *hdlp, uint8_t *host_addr,
1130 1132 uint8_t *dev_addr, size_t repcount, uint_t flags)
1131 1133 {
1132 1134 size_t inc;
1133 1135
1134 1136 inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0;
1135 1137 for (; repcount--; dev_addr += inc)
1136 1138 bscbus_vreg_put8(hdlp, dev_addr, *host_addr++);
1137 1139 }
1138 1140
1139 1141
1140 1142 /*
1141 1143 * Space 1 - LOM watchdog pat register access
1142 1144 * Only 8-bit accesses are supported.
1143 1145 *
1144 1146 * Reads have no effect and return 0.
1145 1147 *
1146 1148 * Multi-byte reads (using ddi_rep_get8(9F)) are a fairly inefficient
1147 1149 * way of zeroing the destination area ;-) and still won't pat the dog.
1148 1150 *
1149 1151 * Multi-byte writes (using ddi_rep_put8(9F)) will almost certainly
1150 1152 * only count as a single pat, no matter how many bytes the caller
1151 1153 * says to write, as the inter-pat time is VERY long compared with
1152 1154 * the time it will take to read the memory source area.
1153 1155 */
1154 1156
1155 1157 static uint8_t
1156 1158 bscbus_pat_get8(HANDLE_TYPE *hdlp, uint8_t *addr)
1157 1159 {
1158 1160 ptrdiff_t offset;
1159 1161
1160 1162 /*
1161 1163 * Check the offset that the caller has added to the base address
1162 1164 * against the length of the mapping originally requested.
1163 1165 */
1164 1166 offset = ADDR_TO_OFFSET(addr, hdlp);
1165 1167 if (offset < 0 || offset >= HANDLE_MAPLEN(hdlp)) {
1166 1168 /*
1167 1169 * Invalid access - flag a fault and return a dummy value
1168 1170 */
1169 1171 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_NUM;
1170 1172 return (DUMMY_VALUE);
1171 1173 }
1172 1174
1173 1175 return (0);
1174 1176 }
1175 1177
1176 1178 static void
1177 1179 bscbus_pat_put8(HANDLE_TYPE *hdlp, uint8_t *addr, uint8_t val)
1178 1180 {
1179 1181 struct bscbus_channel_state *csp;
1180 1182 ptrdiff_t offset;
1181 1183
1182 1184 /*
1183 1185 * Check the offset that the caller has added to the base address
1184 1186 * against the length of the mapping originally requested.
1185 1187 */
1186 1188 offset = ADDR_TO_OFFSET(addr, hdlp);
1187 1189 if (offset < 0 || offset >= HANDLE_MAPLEN(hdlp)) {
1188 1190 /*
1189 1191 * Invalid access - flag a fault and return
1190 1192 */
1191 1193 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_NUM;
1192 1194 return;
1193 1195 }
1194 1196
1195 1197 csp = HANDLE_PRIVATE(hdlp);
1196 1198 mutex_enter(csp->dog_mutex);
1197 1199 bscbus_pat_dog(csp, val);
1198 1200 mutex_exit(csp->dog_mutex);
1199 1201 }
1200 1202
1201 1203 static void
1202 1204 bscbus_pat_rep_get8(HANDLE_TYPE *hdlp, uint8_t *host_addr,
1203 1205 uint8_t *dev_addr, size_t repcount, uint_t flags)
1204 1206 {
1205 1207 size_t inc;
1206 1208
1207 1209 inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0;
1208 1210 for (; repcount--; dev_addr += inc)
1209 1211 *host_addr++ = bscbus_pat_get8(hdlp, dev_addr);
1210 1212 }
1211 1213
1212 1214 static void
1213 1215 bscbus_pat_rep_put8(HANDLE_TYPE *hdlp, uint8_t *host_addr,
1214 1216 uint8_t *dev_addr, size_t repcount, uint_t flags)
1215 1217 {
1216 1218 size_t inc;
1217 1219
1218 1220 inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0;
1219 1221 for (; repcount--; dev_addr += inc)
1220 1222 bscbus_pat_put8(hdlp, dev_addr, *host_addr++);
1221 1223 }
1222 1224
1223 1225
1224 1226 /*
1225 1227 * Space 2 - LOM async event flag register access
1226 1228 * Only 16-bit accesses are supported.
1227 1229 */
1228 1230 static uint16_t
1229 1231 bscbus_event_get16(HANDLE_TYPE *hdlp, uint16_t *addr)
1230 1232 {
1231 1233 struct bscbus_channel_state *csp;
1232 1234 ptrdiff_t offset;
1233 1235
1234 1236 /*
1235 1237 * Check the offset that the caller has added to the base address
1236 1238 * against the length of the mapping orignally requested.
1237 1239 */
1238 1240 offset = ADDR_TO_OFFSET(addr, hdlp);
1239 1241 if (offset < 0 || (offset%2) != 0 || offset >= HANDLE_MAPLEN(hdlp)) {
1240 1242 /*
1241 1243 * Invalid access - flag a fault and return a dummy value
1242 1244 */
1243 1245 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_NUM;
1244 1246 return (DUMMY_VALUE);
1245 1247 }
1246 1248
1247 1249 /*
1248 1250 * Return the value of the asynchronous-event-pending flag
1249 1251 * as passed back by the LOM at the end of the last command.
1250 1252 */
1251 1253 csp = HANDLE_PRIVATE(hdlp);
1252 1254 return (csp->async);
1253 1255 }
1254 1256
1255 1257 static void
1256 1258 bscbus_event_put16(HANDLE_TYPE *hdlp, uint16_t *addr, uint16_t val)
1257 1259 {
1258 1260 ptrdiff_t offset;
1259 1261
1260 1262 _NOTE(ARGUNUSED(val))
1261 1263
1262 1264 /*
1263 1265 * Check the offset that the caller has added to the base address
1264 1266 * against the length of the mapping originally requested.
1265 1267 */
1266 1268 offset = ADDR_TO_OFFSET(addr, hdlp);
1267 1269 if (offset < 0 || (offset%2) != 0 || offset >= HANDLE_MAPLEN(hdlp)) {
1268 1270 /*
1269 1271 * Invalid access - flag a fault and return
1270 1272 */
1271 1273 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_NUM;
1272 1274 return;
1273 1275 }
1274 1276
1275 1277 /*
1276 1278 * The user can't overwrite the asynchronous-event-pending flag!
1277 1279 */
1278 1280 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_RO;
1279 1281 }
1280 1282
1281 1283 static void
1282 1284 bscbus_event_rep_get16(HANDLE_TYPE *hdlp, uint16_t *host_addr,
1283 1285 uint16_t *dev_addr, size_t repcount, uint_t flags)
1284 1286 {
1285 1287 size_t inc;
1286 1288
1287 1289 inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0;
1288 1290 for (; repcount--; dev_addr += inc)
1289 1291 *host_addr++ = bscbus_event_get16(hdlp, dev_addr);
1290 1292 }
1291 1293
1292 1294 static void
1293 1295 bscbus_event_rep_put16(HANDLE_TYPE *hdlp, uint16_t *host_addr,
1294 1296 uint16_t *dev_addr, size_t repcount, uint_t flags)
1295 1297 {
1296 1298 size_t inc;
1297 1299
1298 1300 inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0;
1299 1301 for (; repcount--; dev_addr += inc)
1300 1302 bscbus_event_put16(hdlp, dev_addr, *host_addr++);
1301 1303 }
1302 1304
1303 1305
1304 1306 /*
1305 1307 * All spaces - access handle fault information
1306 1308 * Only 32-bit accesses are supported.
1307 1309 */
1308 1310 static uint32_t
1309 1311 bscbus_meta_get32(HANDLE_TYPE *hdlp, uint32_t *addr)
1310 1312 {
1311 1313 struct bscbus_channel_state *csp;
1312 1314 ptrdiff_t offset;
1313 1315
1314 1316 /*
1315 1317 * Derive the offset that the caller has added to the base
1316 1318 * address originally returned, and use it to determine
1317 1319 * which meta-register is to be accessed ...
1318 1320 */
1319 1321 offset = ADDR_TO_OFFSET(addr, hdlp);
1320 1322 switch (offset) {
1321 1323 case LOMBUS_FAULT_REG:
1322 1324 /*
1323 1325 * This meta-register provides a code for the most
1324 1326 * recent virtual register access fault, if any.
1325 1327 */
1326 1328 return (HANDLE_FAULT(hdlp));
1327 1329
1328 1330 case LOMBUS_PROBE_REG:
1329 1331 /*
1330 1332 * Reading this meta-register clears any existing fault
1331 1333 * (at the virtual, not the hardware access layer), then
1332 1334 * runs a NOP command and returns the fault code from that.
1333 1335 */
1334 1336 HANDLE_FAULT(hdlp) = 0;
1335 1337 (void) bscbus_cmd(hdlp, 0, 0, BSCBUS_CMD_NOP);
1336 1338 return (HANDLE_FAULT(hdlp));
1337 1339
1338 1340 case LOMBUS_ASYNC_REG:
1339 1341 /*
1340 1342 * Obsolescent - but still supported for backwards
1341 1343 * compatibility. This is an alias for the newer
1342 1344 * LOMBUS_EVENT_REG, but doesn't require a separate
1343 1345 * "reg" entry and ddi_regs_map_setup() call.
1344 1346 *
1345 1347 * It returns the value of the asynchronous-event-pending
1346 1348 * flag as passed back by the BSC at the end of the last
1347 1349 * completed command.
1348 1350 */
1349 1351 csp = HANDLE_PRIVATE(hdlp);
1350 1352 return (csp->async);
1351 1353
1352 1354 default:
1353 1355 /*
1354 1356 * Invalid access - flag a fault and return a dummy value
1355 1357 */
1356 1358 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
1357 1359 return (DUMMY_VALUE);
1358 1360 }
1359 1361 }
1360 1362
1361 1363 static void
1362 1364 bscbus_meta_put32(HANDLE_TYPE *hdlp, uint32_t *addr, uint32_t val)
1363 1365 {
1364 1366 ptrdiff_t offset;
1365 1367
1366 1368 /*
1367 1369 * Derive the offset that the caller has added to the base
1368 1370 * address originally returned, and use it to determine
1369 1371 * which meta-register is to be accessed ...
1370 1372 */
1371 1373 offset = ADDR_TO_OFFSET(addr, hdlp);
1372 1374 switch (offset) {
1373 1375 case LOMBUS_FAULT_REG:
1374 1376 /*
1375 1377 * This meta-register contains a code for the most
1376 1378 * recent virtual register access fault, if any.
1377 1379 * It can be cleared simply by writing 0 to it.
1378 1380 */
1379 1381 HANDLE_FAULT(hdlp) = val;
1380 1382 return;
1381 1383
1382 1384 case LOMBUS_PROBE_REG:
1383 1385 /*
1384 1386 * Writing this meta-register clears any existing fault
1385 1387 * (at the virtual, not the hardware acess layer), then
1386 1388 * runs a NOP command. The caller can check the fault
1387 1389 * code later if required.
1388 1390 */
1389 1391 HANDLE_FAULT(hdlp) = 0;
1390 1392 (void) bscbus_cmd(hdlp, 0, 0, BSCBUS_CMD_NOP);
1391 1393 return;
1392 1394
1393 1395 default:
1394 1396 /*
1395 1397 * Invalid access - flag a fault
1396 1398 */
1397 1399 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
1398 1400 return;
1399 1401 }
1400 1402 }
1401 1403
1402 1404 static void
1403 1405 bscbus_meta_rep_get32(HANDLE_TYPE *hdlp, uint32_t *host_addr,
1404 1406 uint32_t *dev_addr, size_t repcount, uint_t flags)
1405 1407 {
1406 1408 size_t inc;
1407 1409
1408 1410 inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0;
1409 1411 for (; repcount--; dev_addr += inc)
1410 1412 *host_addr++ = bscbus_meta_get32(hdlp, dev_addr);
1411 1413 }
1412 1414
1413 1415 static void
1414 1416 bscbus_meta_rep_put32(HANDLE_TYPE *hdlp, uint32_t *host_addr,
1415 1417 uint32_t *dev_addr, size_t repcount, uint_t flags)
1416 1418 {
1417 1419 size_t inc;
1418 1420
1419 1421 inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0;
1420 1422 for (; repcount--; dev_addr += inc)
1421 1423 bscbus_meta_put32(hdlp, dev_addr, *host_addr++);
1422 1424 }
1423 1425
1424 1426
1425 1427 /*
1426 1428 * Finally, some dummy functions for all unsupported access
1427 1429 * space/size/mode combinations ...
1428 1430 */
1429 1431 static uint8_t
1430 1432 bscbus_no_get8(HANDLE_TYPE *hdlp, uint8_t *addr)
1431 1433 {
1432 1434 _NOTE(ARGUNUSED(addr))
1433 1435
1434 1436 /*
1435 1437 * Invalid access - flag a fault and return a dummy value
1436 1438 */
1437 1439 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
1438 1440 return (DUMMY_VALUE);
1439 1441 }
1440 1442
1441 1443 static void
1442 1444 bscbus_no_put8(HANDLE_TYPE *hdlp, uint8_t *addr, uint8_t val)
1443 1445 {
1444 1446 _NOTE(ARGUNUSED(addr, val))
1445 1447
1446 1448 /*
1447 1449 * Invalid access - flag a fault
1448 1450 */
1449 1451 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
1450 1452 }
1451 1453
1452 1454 static void
1453 1455 bscbus_no_rep_get8(HANDLE_TYPE *hdlp, uint8_t *host_addr,
1454 1456 uint8_t *dev_addr, size_t repcount, uint_t flags)
1455 1457 {
1456 1458 _NOTE(ARGUNUSED(host_addr, dev_addr, repcount, flags))
1457 1459
1458 1460 /*
1459 1461 * Invalid access - flag a fault
1460 1462 */
1461 1463 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
1462 1464 }
1463 1465
1464 1466 static void
1465 1467 bscbus_no_rep_put8(HANDLE_TYPE *hdlp, uint8_t *host_addr,
1466 1468 uint8_t *dev_addr, size_t repcount, uint_t flags)
1467 1469 {
1468 1470 _NOTE(ARGUNUSED(host_addr, dev_addr, repcount, flags))
1469 1471
1470 1472 /*
1471 1473 * Invalid access - flag a fault
1472 1474 */
1473 1475 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
1474 1476 }
1475 1477
1476 1478 static uint16_t
1477 1479 bscbus_no_get16(HANDLE_TYPE *hdlp, uint16_t *addr)
1478 1480 {
1479 1481 _NOTE(ARGUNUSED(addr))
1480 1482
1481 1483 /*
1482 1484 * Invalid access - flag a fault and return a dummy value
1483 1485 */
1484 1486 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
1485 1487 return (DUMMY_VALUE);
1486 1488 }
1487 1489
1488 1490 static void
1489 1491 bscbus_no_put16(HANDLE_TYPE *hdlp, uint16_t *addr, uint16_t val)
1490 1492 {
1491 1493 _NOTE(ARGUNUSED(addr, val))
1492 1494
1493 1495 /*
1494 1496 * Invalid access - flag a fault
1495 1497 */
1496 1498 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
1497 1499 }
1498 1500
1499 1501 static void
1500 1502 bscbus_no_rep_get16(HANDLE_TYPE *hdlp, uint16_t *host_addr,
1501 1503 uint16_t *dev_addr, size_t repcount, uint_t flags)
1502 1504 {
1503 1505 _NOTE(ARGUNUSED(host_addr, dev_addr, repcount, flags))
1504 1506
1505 1507 /*
1506 1508 * Invalid access - flag a fault
1507 1509 */
1508 1510 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
1509 1511 }
1510 1512
1511 1513 static void
1512 1514 bscbus_no_rep_put16(HANDLE_TYPE *hdlp, uint16_t *host_addr,
1513 1515 uint16_t *dev_addr, size_t repcount, uint_t flags)
1514 1516 {
1515 1517 _NOTE(ARGUNUSED(host_addr, dev_addr, repcount, flags))
1516 1518
1517 1519 /*
1518 1520 * Invalid access - flag a fault
1519 1521 */
1520 1522 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
1521 1523 }
1522 1524
1523 1525 static uint64_t
1524 1526 bscbus_no_get64(HANDLE_TYPE *hdlp, uint64_t *addr)
1525 1527 {
1526 1528 _NOTE(ARGUNUSED(addr))
1527 1529
1528 1530 /*
1529 1531 * Invalid access - flag a fault and return a dummy value
1530 1532 */
1531 1533 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
1532 1534 return (DUMMY_VALUE);
1533 1535 }
1534 1536
1535 1537 static void
1536 1538 bscbus_no_put64(HANDLE_TYPE *hdlp, uint64_t *addr, uint64_t val)
1537 1539 {
1538 1540 _NOTE(ARGUNUSED(addr, val))
1539 1541
1540 1542 /*
1541 1543 * Invalid access - flag a fault
1542 1544 */
1543 1545 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
1544 1546 }
1545 1547
1546 1548 static void
1547 1549 bscbus_no_rep_get64(HANDLE_TYPE *hdlp, uint64_t *host_addr,
1548 1550 uint64_t *dev_addr, size_t repcount, uint_t flags)
1549 1551 {
1550 1552 _NOTE(ARGUNUSED(host_addr, dev_addr, repcount, flags))
1551 1553
1552 1554 /*
1553 1555 * Invalid access - flag a fault
1554 1556 */
1555 1557 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
1556 1558 }
1557 1559
1558 1560 static void
1559 1561 bscbus_no_rep_put64(HANDLE_TYPE *hdlp, uint64_t *host_addr,
1560 1562 uint64_t *dev_addr, size_t repcount, uint_t flags)
1561 1563 {
1562 1564 _NOTE(ARGUNUSED(host_addr, dev_addr, repcount, flags))
1563 1565
1564 1566 /*
1565 1567 * Invalid access - flag a fault
1566 1568 */
1567 1569 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
1568 1570 }
1569 1571
1570 1572 static int
1571 1573 bscbus_acc_fault_check(HANDLE_TYPE *hdlp)
1572 1574 {
1573 1575 return (HANDLE_FAULT(hdlp) != 0);
1574 1576 }
1575 1577
1576 1578 /*
1577 1579 * Hardware setup - ensure that there are no pending transactions and
1578 1580 * hence no pending interrupts. We do this be ensuring that the BSC is
1579 1581 * not reporting a busy condition and that it does not have any data
1580 1582 * pending in its output buffer.
1581 1583 * This is important because if we have pending interrupts at attach
1582 1584 * time Solaris will hang due to bugs in ddi_get_iblock_cookie.
1583 1585 */
1584 1586 static void
1585 1587 bscbus_hw_reset(struct bscbus_channel_state *csp)
1586 1588 {
1587 1589 int64_t timeout;
1588 1590 uint8_t status;
1589 1591
1590 1592 if (csp->map_count == 0) {
1591 1593 /* No-one using this instance - no need to reset hardware */
1592 1594 return;
1593 1595 }
1594 1596
1595 1597 bscbus_trace(csp, 'R', "bscbus_hw_reset",
1596 1598 "resetting channel %d", csp->chno);
1597 1599
1598 1600 status = bscbus_get_reg(csp, H8_STR);
1599 1601 if (status & H8_STR_BUSY) {
1600 1602 /*
1601 1603 * Give the h8 time to complete a reply.
1602 1604 * In practice we should never worry about this
1603 1605 * because whenever we get here it will have been
1604 1606 * long enough for the h8 to complete a reply
1605 1607 */
1606 1608 bscbus_cmd_log(csp, BSC_CMD_BUSY, status, 0);
1607 1609 bscbus_trace(csp, 'R', "bscbus_hw_reset",
1608 1610 "h8 reporting status (%x) busy - waiting", status);
1609 1611 if (ddi_in_panic()) {
1610 1612 drv_usecwait(BSCBUS_HWRESET_POLL/1000);
1611 1613 } else {
1612 1614 delay(drv_usectohz(BSCBUS_HWRESET_POLL/1000));
1613 1615 }
1614 1616 }
1615 1617 /* Reply should be completed by now. Try to clear busy status */
1616 1618 status = bscbus_get_reg(csp, H8_STR);
1617 1619 if (status & (H8_STR_BUSY | H8_STR_OBF)) {
1618 1620 bscbus_trace(csp, 'R', "bscbus_hw_reset",
1619 1621 "clearing busy status for channel %d", csp->chno);
1620 1622
1621 1623 for (timeout = BSCBUS_HWRESET_TIMEOUT;
1622 1624 (timeout > 0);
1623 1625 timeout -= BSCBUS_HWRESET_POLL) {
1624 1626 if (status & H8_STR_OBF) {
1625 1627 (void) bscbus_get_reg(csp, H8_ODR);
1626 1628 if (!(status & H8_STR_BUSY)) {
1627 1629 /* We are done */
1628 1630 break;
1629 1631 }
1630 1632 }
1631 1633 if (ddi_in_panic()) {
1632 1634 drv_usecwait(BSCBUS_HWRESET_POLL/1000);
1633 1635 } else {
1634 1636 delay(drv_usectohz(BSCBUS_HWRESET_POLL/1000));
1635 1637 }
1636 1638 status = bscbus_get_reg(csp, H8_STR);
1637 1639 }
1638 1640 if (timeout <= 0) {
1639 1641 cmn_err(CE_WARN, "bscbus_hw_reset: timed out "
1640 1642 "clearing busy status");
1641 1643 }
1642 1644 }
1643 1645 /*
1644 1646 * We read ODR just in case there is a pending interrupt with
1645 1647 * no data. This is potentially dangerous because we could get
1646 1648 * out of sync due to race conditions BUT at this point the
1647 1649 * channel should be idle so it is safe.
1648 1650 */
1649 1651 (void) bscbus_get_reg(csp, H8_ODR);
1650 1652 }
1651 1653
1652 1654 /*
1653 1655 * Higher-level setup & teardown
1654 1656 */
1655 1657
1656 1658 static void
1657 1659 bscbus_offline(struct bscbus_state *ssp)
1658 1660 {
1659 1661 if (ssp->h8_handle != NULL)
1660 1662 ddi_regs_map_free(&ssp->h8_handle);
1661 1663 ssp->h8_handle = NULL;
1662 1664 ssp->h8_regs = NULL;
1663 1665 }
1664 1666
1665 1667 static int
1666 1668 bscbus_online(struct bscbus_state *ssp)
1667 1669 {
1668 1670 ddi_acc_handle_t h;
1669 1671 caddr_t p;
1670 1672 int nregs;
1671 1673 int err;
1672 1674
1673 1675 ssp->h8_handle = NULL;
1674 1676 ssp->h8_regs = (void *)NULL;
1675 1677 ssp->per_channel_regs = B_FALSE;
1676 1678
1677 1679 if (ddi_dev_nregs(ssp->dip, &nregs) != DDI_SUCCESS)
1678 1680 nregs = 0;
1679 1681
1680 1682 switch (nregs) {
1681 1683 case 1:
1682 1684 /*
1683 1685 * regset 0 represents the H8 interface registers
1684 1686 */
1685 1687 err = ddi_regs_map_setup(ssp->dip, 0, &p, 0, 0,
1686 1688 bscbus_dev_acc_attr, &h);
1687 1689 if (err != DDI_SUCCESS)
1688 1690 return (EIO);
1689 1691
1690 1692 ssp->h8_handle = h;
1691 1693 ssp->h8_regs = (void *)p;
1692 1694 break;
1693 1695
1694 1696 case 0:
1695 1697 /*
1696 1698 * If no registers are defined, succeed vacuously;
1697 1699 * commands will be accepted, but we fake the accesses.
1698 1700 */
1699 1701 break;
1700 1702
1701 1703 default:
1702 1704 /*
1703 1705 * Remember that we are using the new register scheme.
1704 1706 * reg set 0 is chan 0
1705 1707 * reg set 1 is chan 1 ...
1706 1708 * Interrupts are specified in that order but later
1707 1709 * channels may not have interrupts.
1708 1710 * We map the regs later on a per channel basis.
1709 1711 */
1710 1712 ssp->per_channel_regs = B_TRUE;
1711 1713 break;
1712 1714 }
1713 1715 return (0);
1714 1716 }
1715 1717
1716 1718 static int
1717 1719 bscbus_claim_channel(struct bscbus_channel_state *csp, boolean_t map_dog)
1718 1720 {
1719 1721 int err;
1720 1722
1721 1723 mutex_enter(csp->ssp->ch_mutex);
1722 1724 csp->map_count++;
1723 1725 bscbus_trace(csp, 'C', "bscbus_claim_channel",
1724 1726 "claim channel for channel %d, count %d",
1725 1727 csp->chno, csp->map_count);
1726 1728
1727 1729 if (csp->map_count == 1) {
1728 1730 /* No-one is using this channel - initialise it */
1729 1731 bscbus_trace(csp, 'C', "bscbus_claim_channel",
1730 1732 "initialise channel %d, count %d",
1731 1733 csp->chno, csp->map_count);
1732 1734
1733 1735 mutex_init(csp->dog_mutex, NULL, MUTEX_DRIVER,
1734 1736 (void *)(uintptr_t)__ipltospl(SPL7 - 1));
1735 1737 csp->map_dog = map_dog;
1736 1738 csp->interrupt_failed = B_FALSE;
1737 1739 csp->cmdstate = BSCBUS_CMDSTATE_IDLE;
1738 1740 csp->pat_retry_count = 0;
1739 1741 csp->pat_fail_count = 0;
1740 1742
1741 1743 /* Map appropriate register set for this channel */
1742 1744 if (csp->ssp->per_channel_regs == B_TRUE) {
1743 1745 ddi_acc_handle_t h;
1744 1746 caddr_t p;
1745 1747
1746 1748 err = ddi_regs_map_setup(csp->ssp->dip, csp->chno,
1747 1749 &p, 0, 0, bscbus_dev_acc_attr, &h);
1748 1750
1749 1751 if (err != DDI_SUCCESS) {
1750 1752 goto failed1;
1751 1753 }
1752 1754
1753 1755 csp->ch_handle = h;
1754 1756 csp->ch_regs = (void *)p;
1755 1757
1756 1758 bscbus_trace(csp, 'C', "bscbus_claim_channel",
1757 1759 "mapped chno=%d ch_handle=%d ch_regs=%p",
1758 1760 csp->chno, h, p);
1759 1761 } else {
1760 1762 /*
1761 1763 * if using the old reg property scheme use the
1762 1764 * common mapping.
1763 1765 */
1764 1766 csp->ch_handle = csp->ssp->h8_handle;
1765 1767 csp->ch_regs =
1766 1768 csp->ssp->h8_regs +
1767 1769 BSCBUS_CHANNEL_TO_OFFSET(csp->chno);
1768 1770 }
1769 1771
1770 1772 /* Ensure no interrupts pending prior to getting iblk cookie */
1771 1773 bscbus_hw_reset(csp);
1772 1774
1773 1775 if (csp->map_dog == 1) {
1774 1776 /*
1775 1777 * we don't want lo_mutex to be initialised
1776 1778 * with an iblock cookie if we are the wdog,
1777 1779 * because we don't use interrupts.
1778 1780 */
1779 1781 mutex_init(csp->lo_mutex, NULL,
1780 1782 MUTEX_DRIVER, NULL);
1781 1783 cv_init(csp->lo_cv, NULL,
1782 1784 CV_DRIVER, NULL);
1783 1785 csp->unclaimed_count = 0;
1784 1786 } else {
1785 1787 int ninterrupts;
1786 1788
1787 1789 /*
1788 1790 * check that there is an interrupt for this
1789 1791 * this channel. If we fail to setup interrupts we
1790 1792 * must unmap the registers and fail.
1791 1793 */
1792 1794 err = ddi_dev_nintrs(csp->ssp->dip, &ninterrupts);
1793 1795
1794 1796 if (err != DDI_SUCCESS) {
1795 1797 ninterrupts = 0;
1796 1798 }
1797 1799
1798 1800 if (ninterrupts <= csp->chno) {
1799 1801 cmn_err(CE_WARN,
1800 1802 "no interrupt available for "
1801 1803 "bscbus channel %d", csp->chno);
1802 1804 goto failed2;
1803 1805 }
1804 1806
1805 1807 if (ddi_intr_hilevel(csp->ssp->dip, csp->chno) != 0) {
1806 1808 cmn_err(CE_WARN,
1807 1809 "bscbus interrupts are high "
1808 1810 "level - channel not usable.");
1809 1811 goto failed2;
1810 1812 } else {
1811 1813 err = ddi_get_iblock_cookie(csp->ssp->dip,
1812 1814 csp->chno, &csp->lo_iblk);
1813 1815 if (err != DDI_SUCCESS) {
1814 1816 goto failed2;
1815 1817 }
1816 1818
1817 1819 mutex_init(csp->lo_mutex, NULL,
1818 1820 MUTEX_DRIVER, csp->lo_iblk);
1819 1821 cv_init(csp->lo_cv, NULL,
1820 1822 CV_DRIVER, NULL);
1821 1823 csp->unclaimed_count = 0;
1822 1824
1823 1825 err = ddi_add_intr(csp->ssp->dip, csp->chno,
1824 1826 &csp->lo_iblk, NULL,
1825 1827 bscbus_hwintr, (caddr_t)csp);
1826 1828 if (err != DDI_SUCCESS) {
1827 1829 cv_destroy(csp->lo_cv);
1828 1830 mutex_destroy(csp->lo_mutex);
1829 1831 goto failed2;
1830 1832 }
1831 1833 }
1832 1834 }
1833 1835 /*
1834 1836 * The channel is now live and may
1835 1837 * receive interrupts
1836 1838 */
1837 1839 } else if (csp->map_dog != map_dog) {
1838 1840 bscbus_trace(csp, 'C', "bscbus_claim_channel",
1839 1841 "request conflicts with previous mapping. old %x, new %x.",
1840 1842 csp->map_dog, map_dog);
1841 1843 goto failed1;
1842 1844 }
1843 1845 mutex_exit(csp->ssp->ch_mutex);
1844 1846 return (1);
1845 1847
1846 1848 failed2:
1847 1849 /* unmap regs for failed channel */
1848 1850 if (csp->ssp->per_channel_regs == B_TRUE) {
1849 1851 ddi_regs_map_free(&csp->ch_handle);
1850 1852 }
1851 1853 csp->ch_handle = NULL;
1852 1854 csp->ch_regs = (void *)NULL;
1853 1855 failed1:
1854 1856 csp->map_count--;
1855 1857 mutex_exit(csp->ssp->ch_mutex);
1856 1858 return (0);
1857 1859 }
1858 1860
1859 1861 static void
1860 1862 bscbus_release_channel(struct bscbus_channel_state *csp)
1861 1863 {
1862 1864 mutex_enter(csp->ssp->ch_mutex);
1863 1865 if (csp->map_count == 1) {
1864 1866 /* No-one is now using this channel - shutdown channel */
1865 1867 bscbus_trace(csp, 'C', "bscbus_release_channel",
1866 1868 "shutdown channel %d, count %d",
1867 1869 csp->chno, csp->map_count);
1868 1870
1869 1871 if (csp->map_dog == 0) {
1870 1872 ASSERT(!ddi_intr_hilevel(csp->ssp->dip, csp->chno));
1871 1873 ddi_remove_intr(csp->ssp->dip, csp->chno, csp->lo_iblk);
1872 1874 }
1873 1875 cv_destroy(csp->lo_cv);
1874 1876 mutex_destroy(csp->lo_mutex);
1875 1877 mutex_destroy(csp->dog_mutex);
1876 1878 bscbus_hw_reset(csp);
1877 1879
1878 1880 /* unmap registers if using the new register scheme */
1879 1881 if (csp->ssp->per_channel_regs == B_TRUE) {
1880 1882 ddi_regs_map_free(&csp->ch_handle);
1881 1883 }
1882 1884 csp->ch_handle = NULL;
1883 1885 csp->ch_regs = (void *)NULL;
1884 1886 }
1885 1887 csp->map_count--;
1886 1888 bscbus_trace(csp, 'C', "bscbus_release_channel",
1887 1889 "release channel %d, count %d",
1888 1890 csp->chno, csp->map_count);
1889 1891 mutex_exit(csp->ssp->ch_mutex);
1890 1892 }
1891 1893
1892 1894
1893 1895 /*
1894 1896 * Nexus routines
1895 1897 */
1896 1898
1897 1899 #if defined(NDI_ACC_HDL_V2)
1898 1900
1899 1901 static const ndi_acc_fns_t bscbus_vreg_acc_fns = {
1900 1902 NDI_ACC_FNS_CURRENT,
1901 1903 NDI_ACC_FNS_V1,
1902 1904
1903 1905 bscbus_vreg_get8,
1904 1906 bscbus_vreg_put8,
1905 1907 bscbus_vreg_rep_get8,
1906 1908 bscbus_vreg_rep_put8,
1907 1909
1908 1910 bscbus_no_get16,
1909 1911 bscbus_no_put16,
1910 1912 bscbus_no_rep_get16,
1911 1913 bscbus_no_rep_put16,
1912 1914
1913 1915 bscbus_meta_get32,
1914 1916 bscbus_meta_put32,
1915 1917 bscbus_meta_rep_get32,
1916 1918 bscbus_meta_rep_put32,
1917 1919
1918 1920 bscbus_no_get64,
1919 1921 bscbus_no_put64,
1920 1922 bscbus_no_rep_get64,
1921 1923 bscbus_no_rep_put64,
1922 1924
1923 1925 bscbus_acc_fault_check
1924 1926 };
1925 1927
1926 1928 static const ndi_acc_fns_t bscbus_pat_acc_fns = {
1927 1929 NDI_ACC_FNS_CURRENT,
1928 1930 NDI_ACC_FNS_V1,
1929 1931
1930 1932 bscbus_pat_get8,
1931 1933 bscbus_pat_put8,
1932 1934 bscbus_pat_rep_get8,
1933 1935 bscbus_pat_rep_put8,
1934 1936
1935 1937 bscbus_no_get16,
1936 1938 bscbus_no_put16,
1937 1939 bscbus_no_rep_get16,
1938 1940 bscbus_no_rep_put16,
1939 1941
1940 1942 bscbus_meta_get32,
1941 1943 bscbus_meta_put32,
1942 1944 bscbus_meta_rep_get32,
1943 1945 bscbus_meta_rep_put32,
1944 1946
1945 1947 bscbus_no_get64,
1946 1948 bscbus_no_put64,
1947 1949 bscbus_no_rep_get64,
1948 1950 bscbus_no_rep_put64,
1949 1951
1950 1952 bscbus_acc_fault_check
1951 1953 };
1952 1954
1953 1955 static const ndi_acc_fns_t bscbus_event_acc_fns = {
1954 1956 NDI_ACC_FNS_CURRENT,
1955 1957 NDI_ACC_FNS_V1,
1956 1958
1957 1959 bscbus_no_get8,
1958 1960 bscbus_no_put8,
1959 1961 bscbus_no_rep_get8,
1960 1962 bscbus_no_rep_put8,
1961 1963
1962 1964 bscbus_event_get16,
1963 1965 bscbus_event_put16,
1964 1966 bscbus_event_rep_get16,
1965 1967 bscbus_event_rep_put16,
1966 1968
1967 1969 bscbus_meta_get32,
1968 1970 bscbus_meta_put32,
1969 1971 bscbus_meta_rep_get32,
1970 1972 bscbus_meta_rep_put32,
1971 1973
1972 1974 bscbus_no_get64,
1973 1975 bscbus_no_put64,
1974 1976 bscbus_no_rep_get64,
1975 1977 bscbus_no_rep_put64,
1976 1978
1977 1979 bscbus_acc_fault_check
1978 1980 };
1979 1981
1980 1982 static int
1981 1983 bscbus_map_handle(struct bscbus_channel_state *csp, ddi_map_op_t op,
1982 1984 int space, caddr_t vaddr, off_t len,
1983 1985 ndi_acc_handle_t *hdlp, caddr_t *addrp)
1984 1986 {
1985 1987 switch (op) {
1986 1988 default:
1987 1989 return (DDI_ME_UNIMPLEMENTED);
1988 1990
1989 1991 case DDI_MO_MAP_LOCKED:
1990 1992 if (bscbus_claim_channel(csp,
1991 1993 (space == LOMBUS_PAT_SPACE)) == 0) {
1992 1994 return (DDI_ME_GENERIC);
1993 1995 }
1994 1996
1995 1997 switch (space) {
1996 1998 default:
1997 1999 return (DDI_ME_REGSPEC_RANGE);
1998 2000
1999 2001 case LOMBUS_VREG_SPACE:
2000 2002 ndi_set_acc_fns(hdlp, &bscbus_vreg_acc_fns);
2001 2003 break;
2002 2004
2003 2005 case LOMBUS_PAT_SPACE:
2004 2006 ndi_set_acc_fns(hdlp, &bscbus_pat_acc_fns);
2005 2007 break;
2006 2008
2007 2009 case LOMBUS_EVENT_SPACE:
2008 2010 ndi_set_acc_fns(hdlp, &bscbus_event_acc_fns);
2009 2011 break;
2010 2012 }
2011 2013 hdlp->ah_addr = *addrp = vaddr;
2012 2014 hdlp->ah_len = len;
2013 2015 hdlp->ah_bus_private = csp;
2014 2016 return (DDI_SUCCESS);
2015 2017
2016 2018 case DDI_MO_UNMAP:
2017 2019 *addrp = NULL;
2018 2020 hdlp->ah_bus_private = NULL;
2019 2021 bscbus_release_channel(csp);
2020 2022 return (DDI_SUCCESS);
2021 2023 }
2022 2024 }
2023 2025
2024 2026 #else
2025 2027
2026 2028 static int
2027 2029 bscbus_map_handle(struct bscbus_channel_state *csp, ddi_map_op_t op,
2028 2030 int space, caddr_t vaddr, off_t len,
2029 2031 ddi_acc_hdl_t *hdlp, caddr_t *addrp)
2030 2032 {
2031 2033 ddi_acc_impl_t *aip = hdlp->ah_platform_private;
2032 2034
2033 2035 switch (op) {
2034 2036 default:
2035 2037 return (DDI_ME_UNIMPLEMENTED);
2036 2038
2037 2039 case DDI_MO_MAP_LOCKED:
2038 2040 if (bscbus_claim_channel(csp,
2039 2041 (space == LOMBUS_PAT_SPACE)) == 0) {
2040 2042 return (DDI_ME_GENERIC);
2041 2043 }
2042 2044
2043 2045 switch (space) {
2044 2046 default:
2045 2047 return (DDI_ME_REGSPEC_RANGE);
2046 2048
2047 2049 case LOMBUS_VREG_SPACE:
2048 2050 aip->ahi_get8 = bscbus_vreg_get8;
2049 2051 aip->ahi_put8 = bscbus_vreg_put8;
2050 2052 aip->ahi_rep_get8 = bscbus_vreg_rep_get8;
2051 2053 aip->ahi_rep_put8 = bscbus_vreg_rep_put8;
2052 2054
2053 2055 aip->ahi_get16 = bscbus_no_get16;
2054 2056 aip->ahi_put16 = bscbus_no_put16;
2055 2057 aip->ahi_rep_get16 = bscbus_no_rep_get16;
2056 2058 aip->ahi_rep_put16 = bscbus_no_rep_put16;
2057 2059
2058 2060 aip->ahi_get32 = bscbus_meta_get32;
2059 2061 aip->ahi_put32 = bscbus_meta_put32;
2060 2062 aip->ahi_rep_get32 = bscbus_meta_rep_get32;
2061 2063 aip->ahi_rep_put32 = bscbus_meta_rep_put32;
2062 2064
2063 2065 aip->ahi_get64 = bscbus_no_get64;
2064 2066 aip->ahi_put64 = bscbus_no_put64;
2065 2067 aip->ahi_rep_get64 = bscbus_no_rep_get64;
2066 2068 aip->ahi_rep_put64 = bscbus_no_rep_put64;
2067 2069
2068 2070 aip->ahi_fault_check = bscbus_acc_fault_check;
2069 2071 break;
2070 2072
2071 2073 case LOMBUS_PAT_SPACE:
2072 2074 aip->ahi_get8 = bscbus_pat_get8;
2073 2075 aip->ahi_put8 = bscbus_pat_put8;
2074 2076 aip->ahi_rep_get8 = bscbus_pat_rep_get8;
2075 2077 aip->ahi_rep_put8 = bscbus_pat_rep_put8;
2076 2078
2077 2079 aip->ahi_get16 = bscbus_no_get16;
2078 2080 aip->ahi_put16 = bscbus_no_put16;
2079 2081 aip->ahi_rep_get16 = bscbus_no_rep_get16;
2080 2082 aip->ahi_rep_put16 = bscbus_no_rep_put16;
2081 2083
2082 2084 aip->ahi_get32 = bscbus_meta_get32;
2083 2085 aip->ahi_put32 = bscbus_meta_put32;
2084 2086 aip->ahi_rep_get32 = bscbus_meta_rep_get32;
2085 2087 aip->ahi_rep_put32 = bscbus_meta_rep_put32;
2086 2088
2087 2089 aip->ahi_get64 = bscbus_no_get64;
2088 2090 aip->ahi_put64 = bscbus_no_put64;
2089 2091 aip->ahi_rep_get64 = bscbus_no_rep_get64;
2090 2092 aip->ahi_rep_put64 = bscbus_no_rep_put64;
2091 2093
2092 2094 aip->ahi_fault_check = bscbus_acc_fault_check;
2093 2095 break;
2094 2096
2095 2097 case LOMBUS_EVENT_SPACE:
2096 2098 aip->ahi_get8 = bscbus_no_get8;
2097 2099 aip->ahi_put8 = bscbus_no_put8;
2098 2100 aip->ahi_rep_get8 = bscbus_no_rep_get8;
2099 2101 aip->ahi_rep_put8 = bscbus_no_rep_put8;
2100 2102
2101 2103 aip->ahi_get16 = bscbus_event_get16;
2102 2104 aip->ahi_put16 = bscbus_event_put16;
2103 2105 aip->ahi_rep_get16 = bscbus_event_rep_get16;
2104 2106 aip->ahi_rep_put16 = bscbus_event_rep_put16;
2105 2107
2106 2108 aip->ahi_get32 = bscbus_meta_get32;
2107 2109 aip->ahi_put32 = bscbus_meta_put32;
2108 2110 aip->ahi_rep_get32 = bscbus_meta_rep_get32;
2109 2111 aip->ahi_rep_put32 = bscbus_meta_rep_put32;
2110 2112
2111 2113 aip->ahi_get64 = bscbus_no_get64;
2112 2114 aip->ahi_put64 = bscbus_no_put64;
2113 2115 aip->ahi_rep_get64 = bscbus_no_rep_get64;
2114 2116 aip->ahi_rep_put64 = bscbus_no_rep_put64;
2115 2117
2116 2118 aip->ahi_fault_check = bscbus_acc_fault_check;
2117 2119 break;
2118 2120 }
2119 2121 hdlp->ah_addr = *addrp = vaddr;
2120 2122 hdlp->ah_len = len;
2121 2123 hdlp->ah_bus_private = csp;
2122 2124 return (DDI_SUCCESS);
2123 2125
2124 2126 case DDI_MO_UNMAP:
2125 2127 *addrp = NULL;
2126 2128 hdlp->ah_bus_private = NULL;
2127 2129 bscbus_release_channel(csp);
2128 2130 return (DDI_SUCCESS);
2129 2131 }
2130 2132 }
2131 2133
2132 2134 #endif /* NDI_ACC_HDL_V2 */
2133 2135
2134 2136 static int
2135 2137 bscbus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
2136 2138 off_t off, off_t len, caddr_t *addrp)
2137 2139 {
2138 2140 struct bscbus_child_info *lcip;
2139 2141 struct bscbus_state *ssp;
2140 2142 lombus_regspec_t *rsp;
2141 2143
2142 2144 if ((ssp = bscbus_getstate(dip, -1, "bscbus_map")) == NULL)
2143 2145 return (DDI_FAILURE); /* this "can't happen" */
2144 2146
2145 2147 /*
2146 2148 * Validate mapping request ...
2147 2149 */
2148 2150
2149 2151 if (mp->map_flags != DDI_MF_KERNEL_MAPPING)
2150 2152 return (DDI_ME_UNSUPPORTED);
2151 2153 if (mp->map_handlep == NULL)
2152 2154 return (DDI_ME_UNSUPPORTED);
2153 2155 if (mp->map_type != DDI_MT_RNUMBER)
2154 2156 return (DDI_ME_UNIMPLEMENTED);
2155 2157 if ((lcip = ddi_get_parent_data(rdip)) == NULL)
2156 2158 return (DDI_ME_INVAL);
2157 2159 if ((rsp = lcip->rsp) == NULL)
2158 2160 return (DDI_ME_INVAL);
2159 2161 if (mp->map_obj.rnumber >= lcip->nregs)
2160 2162 return (DDI_ME_RNUMBER_RANGE);
2161 2163 rsp += mp->map_obj.rnumber;
2162 2164 if (off < 0 || off >= rsp->lombus_size)
2163 2165 return (DDI_ME_INVAL);
2164 2166 if (len == 0)
2165 2167 len = rsp->lombus_size-off;
2166 2168 if (len < 0)
2167 2169 return (DDI_ME_INVAL);
2168 2170 if (off+len < 0 || off+len > rsp->lombus_size)
2169 2171 return (DDI_ME_INVAL);
2170 2172
2171 2173 return (bscbus_map_handle(
2172 2174 &ssp->channel[LOMBUS_SPACE_TO_CHANNEL(rsp->lombus_space)],
2173 2175 mp->map_op, LOMBUS_SPACE_TO_REGSET(rsp->lombus_space),
2174 2176 VREG_TO_ADDR(rsp->lombus_base+off), len, mp->map_handlep, addrp));
2175 2177 }
2176 2178
2177 2179
2178 2180 static int
2179 2181 bscbus_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t op,
2180 2182 void *arg, void *result)
2181 2183 {
2182 2184 struct bscbus_child_info *lcip;
2183 2185 lombus_regspec_t *rsp;
2184 2186 dev_info_t *cdip;
2185 2187 char addr[32];
2186 2188 uint_t nregs;
2187 2189 uint_t rnum;
2188 2190 int *regs;
2189 2191 int limit;
2190 2192 int err;
2191 2193 int i;
2192 2194
2193 2195 if (bscbus_getstate(dip, -1, "bscbus_ctlops") == NULL)
2194 2196 return (DDI_FAILURE); /* this "can't happen" */
2195 2197
2196 2198 switch (op) {
2197 2199 default:
2198 2200 break;
2199 2201
2200 2202 case DDI_CTLOPS_INITCHILD:
2201 2203 /*
2202 2204 * First, look up and validate the "reg" property.
2203 2205 *
2204 2206 * It must be a non-empty integer array containing a set
2205 2207 * of triples. Once we've verified that, we can treat it
2206 2208 * as an array of type lombus_regspec_t[], which defines
2207 2209 * the meaning of the elements of each triple:
2208 2210 * + the first element of each triple must be a valid space
2209 2211 * + the second and third elements (base, size) of each
2210 2212 * triple must define a valid subrange of that space
2211 2213 * If it passes all the tests, we save it away for future
2212 2214 * reference in the child's parent-private-data field.
2213 2215 */
2214 2216 cdip = arg;
2215 2217 err = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, cdip,
2216 2218 DDI_PROP_DONTPASS, "reg", ®s, &nregs);
2217 2219 if (err != DDI_PROP_SUCCESS)
2218 2220 return (DDI_FAILURE);
2219 2221
2220 2222 err = (nregs <= 0 || (nregs % LOMBUS_REGSPEC_SIZE) != 0);
2221 2223 nregs /= LOMBUS_REGSPEC_SIZE;
2222 2224 rsp = (lombus_regspec_t *)regs;
2223 2225 for (i = 0; i < nregs && !err; ++i) {
2224 2226 switch (LOMBUS_SPACE_TO_REGSET(rsp[i].lombus_space)) {
2225 2227 default:
2226 2228 limit = 0;
2227 2229 err = 1;
2228 2230 cmn_err(CE_WARN,
2229 2231 "child(%p): unknown reg space %d",
2230 2232 (void *)cdip, rsp[i].lombus_space);
2231 2233 break;
2232 2234
2233 2235 case LOMBUS_VREG_SPACE:
2234 2236 limit = LOMBUS_MAX_REG+1;
2235 2237 break;
2236 2238
2237 2239 case LOMBUS_PAT_SPACE:
2238 2240 limit = LOMBUS_PAT_REG+1;
2239 2241 break;
2240 2242
2241 2243 case LOMBUS_EVENT_SPACE:
2242 2244 limit = LOMBUS_EVENT_REG+1;
2243 2245 break;
2244 2246 }
2245 2247
2246 2248 err |= (rsp[i].lombus_base < 0);
2247 2249 err |= (rsp[i].lombus_base >= limit);
2248 2250
2249 2251 if (rsp[i].lombus_size == 0)
2250 2252 rsp[i].lombus_size = limit-rsp[i].lombus_base;
2251 2253
2252 2254 err |= (rsp[i].lombus_size < 0);
2253 2255 err |= (rsp[i].lombus_base+rsp[i].lombus_size < 0);
2254 2256 err |= (rsp[i].lombus_base+rsp[i].lombus_size > limit);
2255 2257
2256 2258 err |= (rsp[i].lombus_base+rsp[i].lombus_size > limit);
2257 2259
2258 2260 }
2259 2261
2260 2262 if (err) {
2261 2263 ddi_prop_free(regs);
2262 2264 return (DDI_FAILURE);
2263 2265 }
2264 2266
2265 2267 lcip = kmem_zalloc(sizeof (*lcip), KM_SLEEP);
2266 2268 lcip->nregs = nregs;
2267 2269 lcip->rsp = rsp;
2268 2270 ddi_set_parent_data(cdip, lcip);
2269 2271
2270 2272 (void) snprintf(addr, sizeof (addr),
2271 2273 "%x,%x", rsp[0].lombus_space, rsp[0].lombus_base);
2272 2274 ddi_set_name_addr(cdip, addr);
2273 2275
2274 2276 return (DDI_SUCCESS);
2275 2277
2276 2278 case DDI_CTLOPS_UNINITCHILD:
2277 2279 cdip = arg;
2278 2280 ddi_set_name_addr(cdip, NULL);
2279 2281 lcip = ddi_get_parent_data(cdip);
2280 2282 ddi_set_parent_data(cdip, NULL);
2281 2283 ddi_prop_free(lcip->rsp);
2282 2284 kmem_free(lcip, sizeof (*lcip));
2283 2285 return (DDI_SUCCESS);
2284 2286
2285 2287 case DDI_CTLOPS_REPORTDEV:
2286 2288 if (rdip == NULL)
2287 2289 return (DDI_FAILURE);
2288 2290
2289 2291 cmn_err(CE_CONT, "?BSC device: %s@%s, %s#%d\n",
2290 2292 ddi_node_name(rdip), ddi_get_name_addr(rdip),
2291 2293 ddi_driver_name(dip), ddi_get_instance(dip));
2292 2294
2293 2295 return (DDI_SUCCESS);
2294 2296
2295 2297 case DDI_CTLOPS_REGSIZE:
2296 2298 if ((lcip = ddi_get_parent_data(rdip)) == NULL)
2297 2299 return (DDI_FAILURE);
2298 2300 if ((rnum = *(uint_t *)arg) >= lcip->nregs)
2299 2301 return (DDI_FAILURE);
2300 2302 *(off_t *)result = lcip->rsp[rnum].lombus_size;
2301 2303 return (DDI_SUCCESS);
2302 2304
2303 2305 case DDI_CTLOPS_NREGS:
2304 2306 if ((lcip = ddi_get_parent_data(rdip)) == NULL)
2305 2307 return (DDI_FAILURE);
2306 2308 *(int *)result = lcip->nregs;
2307 2309 return (DDI_SUCCESS);
2308 2310 }
2309 2311
2310 2312 return (ddi_ctlops(dip, rdip, op, arg, result));
2311 2313 }
2312 2314
2313 2315
2314 2316 /*
2315 2317 * This nexus does not support passing interrupts to leaf drivers, so
2316 2318 * all the intrspec-related operations just fail as cleanly as possible.
2317 2319 */
2318 2320
2319 2321 /*ARGSUSED*/
2320 2322 static int
2321 2323 bscbus_intr_op(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t op,
2322 2324 ddi_intr_handle_impl_t *hdlp, void *result)
2323 2325 {
2324 2326 #if defined(__sparc)
2325 2327 return (i_ddi_intr_ops(dip, rdip, op, hdlp, result));
2326 2328 #else
2327 2329 _NOTE(ARGUNUSED(dip, rdip, op, hdlp, result))
2328 2330 return (DDI_FAILURE);
2329 2331 #endif
2330 2332 }
2331 2333
2332 2334 /*
2333 2335 * Clean up on detach or failure of attach
2334 2336 */
2335 2337 static int
2336 2338 bscbus_unattach(struct bscbus_state *ssp, int instance)
2337 2339 {
2338 2340 int chno;
2339 2341
2340 2342 if (ssp != NULL) {
2341 2343 for (chno = 0; chno < BSCBUS_MAX_CHANNELS; chno++) {
2342 2344 ASSERT(ssp->channel[chno].map_count == 0);
2343 2345 }
2344 2346 bscbus_offline(ssp);
2345 2347 ddi_set_driver_private(ssp->dip, NULL);
2346 2348 mutex_destroy(ssp->ch_mutex);
2347 2349 }
2348 2350 #ifdef BSCBUS_LOGSTATUS
2349 2351 if (ssp->cmd_log_size != 0) {
2350 2352 kmem_free(ssp->cmd_log,
2351 2353 ssp->cmd_log_size * sizeof (bsc_cmd_log_t));
2352 2354 }
2353 2355 #endif /* BSCBUS_LOGSTATUS */
2354 2356
2355 2357
2356 2358 ddi_soft_state_free(bscbus_statep, instance);
2357 2359 return (DDI_FAILURE);
2358 2360 }
2359 2361
2360 2362 /*
2361 2363 * Autoconfiguration routines
2362 2364 */
2363 2365
2364 2366 static int
2365 2367 bscbus_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2366 2368 {
2367 2369 struct bscbus_state *ssp = NULL;
2368 2370 int chno;
2369 2371 int instance;
2370 2372 int err;
2371 2373
2372 2374 switch (cmd) {
2373 2375 default:
2374 2376 return (DDI_FAILURE);
2375 2377
2376 2378 case DDI_ATTACH:
2377 2379 break;
2378 2380 }
2379 2381
2380 2382 /*
2381 2383 * Allocate the soft-state structure
2382 2384 */
2383 2385 instance = ddi_get_instance(dip);
2384 2386 if (ddi_soft_state_zalloc(bscbus_statep, instance) != DDI_SUCCESS)
2385 2387 return (DDI_FAILURE);
2386 2388 if ((ssp = bscbus_getstate(dip, instance, "bscbus_attach")) == NULL)
2387 2389 return (bscbus_unattach(ssp, instance));
2388 2390 ddi_set_driver_private(dip, ssp);
2389 2391
2390 2392 /*
2391 2393 * Initialise devinfo-related fields
2392 2394 */
2393 2395 ssp->dip = dip;
2394 2396 ssp->majornum = ddi_driver_major(dip);
2395 2397 ssp->instance = instance;
2396 2398
2397 2399 /*
2398 2400 * Set various options from .conf properties
2399 2401 */
2400 2402 ssp->debug = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
2401 2403 DDI_PROP_DONTPASS, "debug", 0);
2402 2404
2403 2405 mutex_init(ssp->ch_mutex, NULL, MUTEX_DRIVER, NULL);
2404 2406
2405 2407 #ifdef BSCBUS_LOGSTATUS
2406 2408 ssp->cmd_log_size = bscbus_cmd_log_size;
2407 2409 if (ssp->cmd_log_size != 0) {
2408 2410 ssp->cmd_log_idx = 0;
2409 2411 ssp->cmd_log = kmem_zalloc(ssp->cmd_log_size *
2410 2412 sizeof (bsc_cmd_log_t), KM_SLEEP);
2411 2413 }
2412 2414 #endif /* BSCBUS_LOGSTATUS */
2413 2415
2414 2416 /*
2415 2417 * Online the hardware ...
2416 2418 */
2417 2419 err = bscbus_online(ssp);
2418 2420 if (err != 0)
2419 2421 return (bscbus_unattach(ssp, instance));
2420 2422
2421 2423 for (chno = 0; chno < BSCBUS_MAX_CHANNELS; chno++) {
2422 2424 struct bscbus_channel_state *csp = &ssp->channel[chno];
2423 2425
2424 2426 /*
2425 2427 * Initialise state
2426 2428 * The hardware/interrupts are setup at map time to
2427 2429 * avoid claiming hardware that OBP is using
2428 2430 */
2429 2431 csp->ssp = ssp;
2430 2432 csp->chno = chno;
2431 2433 csp->map_count = 0;
2432 2434 csp->map_dog = B_FALSE;
2433 2435 }
2434 2436
2435 2437 /*
2436 2438 * All done, report success
2437 2439 */
2438 2440 ddi_report_dev(dip);
2439 2441 return (DDI_SUCCESS);
2440 2442 }
2441 2443
2442 2444 static int
2443 2445 bscbus_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2444 2446 {
2445 2447 struct bscbus_state *ssp;
2446 2448 int instance;
2447 2449
2448 2450 switch (cmd) {
2449 2451 default:
2450 2452 return (DDI_FAILURE);
2451 2453
2452 2454 case DDI_DETACH:
2453 2455 break;
2454 2456 }
2455 2457
2456 2458 instance = ddi_get_instance(dip);
2457 2459 if ((ssp = bscbus_getstate(dip, instance, "bscbus_detach")) == NULL)
2458 2460 return (DDI_FAILURE); /* this "can't happen" */
2459 2461
2460 2462 (void) bscbus_unattach(ssp, instance);
2461 2463 return (DDI_SUCCESS);
2462 2464 }
2463 2465
2464 2466 static int
2465 2467 bscbus_reset(dev_info_t *dip, ddi_reset_cmd_t cmd)
2466 2468 {
2467 2469 struct bscbus_state *ssp;
2468 2470 int chno;
2469 2471
2470 2472 _NOTE(ARGUNUSED(cmd))
2471 2473
2472 2474 if ((ssp = bscbus_getstate(dip, -1, "bscbus_reset")) == NULL)
2473 2475 return (DDI_FAILURE);
2474 2476
2475 2477 for (chno = 0; chno < BSCBUS_MAX_CHANNELS; chno++) {
2476 2478 bscbus_hw_reset(&ssp->channel[chno]);
2477 2479 }
2478 2480 return (DDI_SUCCESS);
2479 2481 }
2480 2482
2481 2483
2482 2484 /*
2483 2485 * System interface structures
2484 2486 */
2485 2487
2486 2488 static struct cb_ops bscbus_cb_ops =
2487 2489 {
2488 2490 nodev, /* b/c open */
2489 2491 nodev, /* b/c close */
2490 2492 nodev, /* b strategy */
2491 2493 nodev, /* b print */
2492 2494 nodev, /* b dump */
2493 2495 nodev, /* c read */
2494 2496 nodev, /* c write */
2495 2497 nodev, /* c ioctl */
2496 2498 nodev, /* c devmap */
2497 2499 nodev, /* c mmap */
2498 2500 nodev, /* c segmap */
2499 2501 nochpoll, /* c poll */
2500 2502 ddi_prop_op, /* b/c prop_op */
2501 2503 NULL, /* c streamtab */
2502 2504 D_MP | D_NEW /* b/c flags */
2503 2505 };
2504 2506
2505 2507 static struct bus_ops bscbus_bus_ops =
2506 2508 {
2507 2509 BUSO_REV, /* revision */
2508 2510 bscbus_map, /* bus_map */
2509 2511 0, /* get_intrspec */
2510 2512 0, /* add_intrspec */
2511 2513 0, /* remove_intrspec */
2512 2514 i_ddi_map_fault, /* map_fault */
2513 2515 ddi_no_dma_map, /* dma_map */
2514 2516 ddi_no_dma_allochdl, /* allocate DMA handle */
2515 2517 ddi_no_dma_freehdl, /* free DMA handle */
2516 2518 ddi_no_dma_bindhdl, /* bind DMA handle */
2517 2519 ddi_no_dma_unbindhdl, /* unbind DMA handle */
2518 2520 ddi_no_dma_flush, /* flush DMA */
2519 2521 ddi_no_dma_win, /* move DMA window */
2520 2522 ddi_no_dma_mctl, /* generic DMA control */
2521 2523 bscbus_ctlops, /* generic control */
2522 2524 ddi_bus_prop_op, /* prop_op */
2523 2525 ndi_busop_get_eventcookie, /* get_eventcookie */
2524 2526 ndi_busop_add_eventcall, /* add_eventcall */
2525 2527 ndi_busop_remove_eventcall, /* remove_eventcall */
2526 2528 ndi_post_event, /* post_event */
2527 2529 0, /* interrupt control */
2528 2530 0, /* bus_config */
2529 2531 0, /* bus_unconfig */
2530 2532 0, /* bus_fm_init */
2531 2533 0, /* bus_fm_fini */
2532 2534 0, /* bus_fm_access_enter */
2533 2535 0, /* bus_fm_access_exit */
2534 2536 0, /* bus_power */
2535 2537 bscbus_intr_op /* bus_intr_op */
2536 2538 };
2537 2539
2538 2540 static struct dev_ops bscbus_dev_ops =
2539 2541 {
2540 2542 DEVO_REV,
2541 2543 0, /* refcount */
2542 2544 ddi_no_info, /* getinfo */
2543 2545 nulldev, /* identify */
2544 2546 nulldev, /* probe */
2545 2547 bscbus_attach, /* attach */
2546 2548 bscbus_detach, /* detach */
2547 2549 bscbus_reset, /* reset */
2548 2550 &bscbus_cb_ops, /* driver operations */
2549 2551 &bscbus_bus_ops, /* bus operations */
2550 2552 NULL, /* power */
2551 2553 ddi_quiesce_not_needed, /* quiesce */
2552 2554 };
2553 2555
2554 2556 static struct modldrv modldrv =
2555 2557 {
2556 2558 &mod_driverops,
2557 2559 "bscbus driver",
2558 2560 &bscbus_dev_ops
2559 2561 };
2560 2562
2561 2563 static struct modlinkage modlinkage =
2562 2564 {
2563 2565 MODREV_1,
2564 2566 {
2565 2567 &modldrv,
2566 2568 NULL
2567 2569 }
2568 2570 };
2569 2571
2570 2572
2571 2573 /*
2572 2574 * Dynamic loader interface code
2573 2575 */
2574 2576
2575 2577 int
2576 2578 _init(void)
2577 2579 {
2578 2580 int err;
2579 2581
2580 2582 err = ddi_soft_state_init(&bscbus_statep,
2581 2583 sizeof (struct bscbus_state), 0);
2582 2584 if (err == DDI_SUCCESS)
2583 2585 if ((err = mod_install(&modlinkage)) != DDI_SUCCESS) {
2584 2586 ddi_soft_state_fini(&bscbus_statep);
2585 2587 }
2586 2588
2587 2589 return (err);
2588 2590 }
2589 2591
2590 2592 int
2591 2593 _info(struct modinfo *mip)
2592 2594 {
2593 2595 return (mod_info(&modlinkage, mip));
2594 2596 }
2595 2597
2596 2598 int
2597 2599 _fini(void)
2598 2600 {
2599 2601 int err;
2600 2602
2601 2603 if ((err = mod_remove(&modlinkage)) == DDI_SUCCESS) {
2602 2604 ddi_soft_state_fini(&bscbus_statep);
2603 2605 bscbus_major = NOMAJOR;
2604 2606 }
2605 2607
2606 2608 return (err);
2607 2609 }
2608 2610
2609 2611 #ifdef BSCBUS_LOGSTATUS
2610 2612 void bscbus_cmd_log(struct bscbus_channel_state *csp, bsc_cmd_stamp_t cat,
2611 2613 uint8_t status, uint8_t data)
2612 2614 {
2613 2615 int idx;
2614 2616 bsc_cmd_log_t *logp;
2615 2617 struct bscbus_state *ssp;
2616 2618
2617 2619 if ((csp) == NULL)
2618 2620 return;
2619 2621 if ((ssp = (csp)->ssp) == NULL)
2620 2622 return;
2621 2623 if (ssp->cmd_log_size == 0)
2622 2624 return;
2623 2625 if ((bscbus_cmd_log_flags & (1 << cat)) == 0)
2624 2626 return;
2625 2627 idx = atomic_inc_32_nv(&ssp->cmd_log_idx);
2626 2628 logp = &ssp->cmd_log[idx % ssp->cmd_log_size];
2627 2629 logp->bcl_seq = idx;
2628 2630 logp->bcl_cat = cat;
2629 2631 logp->bcl_now = gethrtime();
2630 2632 logp->bcl_chno = csp->chno;
2631 2633 logp->bcl_cmdstate = csp->cmdstate;
2632 2634 logp->bcl_status = status;
2633 2635 logp->bcl_data = data;
2634 2636 }
2635 2637 #endif /* BSCBUS_LOGSTATUS */
↓ open down ↓ |
2218 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX