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