1 /* 2 * I/O Processor (IOP) management 3 * Written and (C) 1999 by Joshua M. Thompson (funaho@jurai.org) 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice and this list of conditions. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice and this list of conditions in the documentation and/or other 12 * materials provided with the distribution. 13 */ 14 15 /* 16 * The IOP chips are used in the IIfx and some Quadras (900, 950) to manage 17 * serial and ADB. They are actually a 6502 processor and some glue logic. 18 * 19 * 990429 (jmt) - Initial implementation, just enough to knock the SCC IOP 20 * into compatible mode so nobody has to fiddle with the 21 * Serial Switch control panel anymore. 22 * 990603 (jmt) - Added code to grab the correct ISM IOP interrupt for OSS 23 * and non-OSS machines (at least I hope it's correct on a 24 * non-OSS machine -- someone with a Q900 or Q950 needs to 25 * check this.) 26 * 990605 (jmt) - Rearranged things a bit wrt IOP detection; iop_present is 27 * gone, IOP base addresses are now in an array and the 28 * globally-visible functions take an IOP number instead of 29 * an actual base address. 30 * 990610 (jmt) - Finished the message passing framework and it seems to work. 31 * Sending _definitely_ works; my adb-bus.c mods can send 32 * messages and receive the MSG_COMPLETED status back from the 33 * IOP. The trick now is figuring out the message formats. 34 * 990611 (jmt) - More cleanups. Fixed problem where unclaimed messages on a 35 * receive channel were never properly acknowledged. Bracketed 36 * the remaining debug printk's with #ifdef's and disabled 37 * debugging. I can now type on the console. 38 * 990612 (jmt) - Copyright notice added. Reworked the way replies are handled. 39 * It turns out that replies are placed back in the send buffer 40 * for that channel; messages on the receive channels are always 41 * unsolicited messages from the IOP (and our replies to them 42 * should go back in the receive channel.) Also added tracking 43 * of device names to the listener functions ala the interrupt 44 * handlers. 45 * 990729 (jmt) - Added passing of pt_regs structure to IOP handlers. This is 46 * used by the new unified ADB driver. 47 * 48 * TODO: 49 * 50 * o The SCC IOP has to be placed in bypass mode before the serial console 51 * gets initialized. iop_init() would be one place to do that. Or the 52 * bootloader could do that. For now, the Serial Switch control panel 53 * is needed for that -- contrary to the changelog above. 54 * o Something should be periodically checking iop_alive() to make sure the 55 * IOP hasn't died. 56 * o Some of the IOP manager routines need better error checking and 57 * return codes. Nothing major, just prettying up. 58 */ 59 60 /* 61 * ----------------------- 62 * IOP Message Passing 101 63 * ----------------------- 64 * 65 * The host talks to the IOPs using a rather simple message-passing scheme via 66 * a shared memory area in the IOP RAM. Each IOP has seven "channels"; each 67 * channel is connected to a specific software driver on the IOP. For example 68 * on the SCC IOP there is one channel for each serial port. Each channel has 69 * an incoming and an outgoing message queue with a depth of one. 70 * 71 * A message is 32 bytes plus a state byte for the channel (MSG_IDLE, MSG_NEW, 72 * MSG_RCVD, MSG_COMPLETE). To send a message you copy the message into the 73 * buffer, set the state to MSG_NEW and signal the IOP by setting the IRQ flag 74 * in the IOP control to 1. The IOP will move the state to MSG_RCVD when it 75 * receives the message and then to MSG_COMPLETE when the message processing 76 * has completed. It is the host's responsibility at that point to read the 77 * reply back out of the send channel buffer and reset the channel state back 78 * to MSG_IDLE. 79 * 80 * To receive message from the IOP the same procedure is used except the roles 81 * are reversed. That is, the IOP puts message in the channel with a state of 82 * MSG_NEW, and the host receives the message and move its state to MSG_RCVD 83 * and then to MSG_COMPLETE when processing is completed and the reply (if any) 84 * has been placed back in the receive channel. The IOP will then reset the 85 * channel state to MSG_IDLE. 86 * 87 * Two sets of host interrupts are provided, INT0 and INT1. Both appear on one 88 * interrupt level; they are distinguished by a pair of bits in the IOP status 89 * register. The IOP will raise INT0 when one or more messages in the send 90 * channels have gone to the MSG_COMPLETE state and it will raise INT1 when one 91 * or more messages on the receive channels have gone to the MSG_NEW state. 92 * 93 * Since each channel handles only one message we have to implement a small 94 * interrupt-driven queue on our end. Messages to be sent are placed on the 95 * queue for sending and contain a pointer to an optional callback function. 96 * The handler for a message is called when the message state goes to 97 * MSG_COMPLETE. 98 * 99 * For receiving message we maintain a list of handler functions to call when 100 * a message is received on that IOP/channel combination. The handlers are 101 * called much like an interrupt handler and are passed a copy of the message 102 * from the IOP. The message state will be in MSG_RCVD while the handler runs; 103 * it is the handler's responsibility to call iop_complete_message() when 104 * finished; this function moves the message state to MSG_COMPLETE and signals 105 * the IOP. This two-step process is provided to allow the handler to defer 106 * message processing to a bottom-half handler if the processing will take 107 * a significant amount of time (handlers are called at interrupt time so they 108 * should execute quickly.) 109 */ 110 111 #include <linux/types.h> 112 #include <linux/kernel.h> 113 #include <linux/mm.h> 114 #include <linux/delay.h> 115 #include <linux/init.h> 116 #include <linux/interrupt.h> 117 118 #include <asm/macintosh.h> 119 #include <asm/macints.h> 120 #include <asm/mac_iop.h> 121 122 #include "mac.h" 123 124 #ifdef DEBUG 125 #define iop_pr_debug(fmt, ...) \ 126 printk(KERN_DEBUG "%s: " fmt, __func__, ##__VA_ARGS__) 127 #define iop_pr_cont(fmt, ...) \ 128 printk(KERN_CONT fmt, ##__VA_ARGS__) 129 #else 130 #define iop_pr_debug(fmt, ...) \ 131 no_printk(KERN_DEBUG "%s: " fmt, __func__, ##__VA_ARGS__) 132 #define iop_pr_cont(fmt, ...) \ 133 no_printk(KERN_CONT fmt, ##__VA_ARGS__) 134 #endif 135 136 /* Non-zero if the IOPs are present */ 137 138 int iop_scc_present, iop_ism_present; 139 140 /* structure for tracking channel listeners */ 141 142 struct listener { 143 const char *devname; 144 void (*handler)(struct iop_msg *); 145 }; 146 147 /* 148 * IOP structures for the two IOPs 149 * 150 * The SCC IOP controls both serial ports (A and B) as its two functions. 151 * The ISM IOP controls the SWIM (floppy drive) and ADB. 152 */ 153 154 static volatile struct mac_iop *iop_base[NUM_IOPS]; 155 156 /* 157 * IOP message queues 158 */ 159 160 static struct iop_msg iop_msg_pool[NUM_IOP_MSGS]; 161 static struct iop_msg *iop_send_queue[NUM_IOPS][NUM_IOP_CHAN]; 162 static struct listener iop_listeners[NUM_IOPS][NUM_IOP_CHAN]; 163 164 irqreturn_t iop_ism_irq(int, void *); 165 166 /* 167 * Private access functions 168 */ 169 170 static __inline__ void iop_loadaddr(volatile struct mac_iop *iop, __u16 addr) 171 { 172 iop->ram_addr_lo = addr; 173 iop->ram_addr_hi = addr >> 8; 174 } 175 176 static __inline__ __u8 iop_readb(volatile struct mac_iop *iop, __u16 addr) 177 { 178 iop->ram_addr_lo = addr; 179 iop->ram_addr_hi = addr >> 8; 180 return iop->ram_data; 181 } 182 183 static __inline__ void iop_writeb(volatile struct mac_iop *iop, __u16 addr, __u8 data) 184 { 185 iop->ram_addr_lo = addr; 186 iop->ram_addr_hi = addr >> 8; 187 iop->ram_data = data; 188 } 189 190 static __inline__ void iop_stop(volatile struct mac_iop *iop) 191 { 192 iop->status_ctrl = IOP_AUTOINC; 193 } 194 195 static __inline__ void iop_start(volatile struct mac_iop *iop) 196 { 197 iop->status_ctrl = IOP_RUN | IOP_AUTOINC; 198 } 199 200 static __inline__ void iop_interrupt(volatile struct mac_iop *iop) 201 { 202 iop->status_ctrl = IOP_IRQ | IOP_RUN | IOP_AUTOINC; 203 } 204 205 static int iop_alive(volatile struct mac_iop *iop) 206 { 207 int retval; 208 209 retval = (iop_readb(iop, IOP_ADDR_ALIVE) == 0xFF); 210 iop_writeb(iop, IOP_ADDR_ALIVE, 0); 211 return retval; 212 } 213 214 static struct iop_msg *iop_get_unused_msg(void) 215 { 216 int i; 217 unsigned long flags; 218 219 local_irq_save(flags); 220 221 for (i = 0 ; i < NUM_IOP_MSGS ; i++) { 222 if (iop_msg_pool[i].status == IOP_MSGSTATUS_UNUSED) { 223 iop_msg_pool[i].status = IOP_MSGSTATUS_WAITING; 224 local_irq_restore(flags); 225 return &iop_msg_pool[i]; 226 } 227 } 228 229 local_irq_restore(flags); 230 return NULL; 231 } 232 233 /* 234 * Initialize the IOPs, if present. 235 */ 236 237 void __init iop_init(void) 238 { 239 int i; 240 241 if (macintosh_config->scc_type == MAC_SCC_IOP) { 242 if (macintosh_config->ident == MAC_MODEL_IIFX) 243 iop_base[IOP_NUM_SCC] = (struct mac_iop *)SCC_IOP_BASE_IIFX; 244 else 245 iop_base[IOP_NUM_SCC] = (struct mac_iop *)SCC_IOP_BASE_QUADRA; 246 iop_scc_present = 1; 247 pr_debug("SCC IOP detected at %p\n", iop_base[IOP_NUM_SCC]); 248 } 249 if (macintosh_config->adb_type == MAC_ADB_IOP) { 250 if (macintosh_config->ident == MAC_MODEL_IIFX) 251 iop_base[IOP_NUM_ISM] = (struct mac_iop *)ISM_IOP_BASE_IIFX; 252 else 253 iop_base[IOP_NUM_ISM] = (struct mac_iop *)ISM_IOP_BASE_QUADRA; 254 iop_ism_present = 1; 255 pr_debug("ISM IOP detected at %p\n", iop_base[IOP_NUM_ISM]); 256 257 iop_stop(iop_base[IOP_NUM_ISM]); 258 iop_start(iop_base[IOP_NUM_ISM]); 259 iop_alive(iop_base[IOP_NUM_ISM]); /* clears the alive flag */ 260 } 261 262 /* Make the whole pool available and empty the queues */ 263 264 for (i = 0 ; i < NUM_IOP_MSGS ; i++) { 265 iop_msg_pool[i].status = IOP_MSGSTATUS_UNUSED; 266 } 267 268 for (i = 0 ; i < NUM_IOP_CHAN ; i++) { 269 iop_send_queue[IOP_NUM_SCC][i] = NULL; 270 iop_send_queue[IOP_NUM_ISM][i] = NULL; 271 iop_listeners[IOP_NUM_SCC][i].devname = NULL; 272 iop_listeners[IOP_NUM_SCC][i].handler = NULL; 273 iop_listeners[IOP_NUM_ISM][i].devname = NULL; 274 iop_listeners[IOP_NUM_ISM][i].handler = NULL; 275 } 276 } 277 278 /* 279 * Register the interrupt handler for the IOPs. 280 */ 281 282 void __init iop_register_interrupts(void) 283 { 284 if (iop_ism_present) { 285 if (macintosh_config->ident == MAC_MODEL_IIFX) { 286 if (request_irq(IRQ_MAC_ADB, iop_ism_irq, 0, 287 "ISM IOP", (void *)IOP_NUM_ISM)) 288 pr_err("Couldn't register ISM IOP interrupt\n"); 289 } else { 290 if (request_irq(IRQ_VIA2_0, iop_ism_irq, 0, "ISM IOP", 291 (void *)IOP_NUM_ISM)) 292 pr_err("Couldn't register ISM IOP interrupt\n"); 293 } 294 if (!iop_alive(iop_base[IOP_NUM_ISM])) { 295 pr_warn("IOP: oh my god, they killed the ISM IOP!\n"); 296 } else { 297 pr_warn("IOP: the ISM IOP seems to be alive.\n"); 298 } 299 } 300 } 301 302 /* 303 * Register or unregister a listener for a specific IOP and channel 304 * 305 * If the handler pointer is NULL the current listener (if any) is 306 * unregistered. Otherwise the new listener is registered provided 307 * there is no existing listener registered. 308 */ 309 310 int iop_listen(uint iop_num, uint chan, 311 void (*handler)(struct iop_msg *), 312 const char *devname) 313 { 314 if ((iop_num >= NUM_IOPS) || !iop_base[iop_num]) return -EINVAL; 315 if (chan >= NUM_IOP_CHAN) return -EINVAL; 316 if (iop_listeners[iop_num][chan].handler && handler) return -EINVAL; 317 iop_listeners[iop_num][chan].devname = devname; 318 iop_listeners[iop_num][chan].handler = handler; 319 return 0; 320 } 321 322 /* 323 * Complete reception of a message, which just means copying the reply 324 * into the buffer, setting the channel state to MSG_COMPLETE and 325 * notifying the IOP. 326 */ 327 328 void iop_complete_message(struct iop_msg *msg) 329 { 330 int iop_num = msg->iop_num; 331 int chan = msg->channel; 332 int i,offset; 333 334 iop_pr_debug("iop_num %d chan %d reply %*ph\n", 335 msg->iop_num, msg->channel, IOP_MSG_LEN, msg->reply); 336 337 offset = IOP_ADDR_RECV_MSG + (msg->channel * IOP_MSG_LEN); 338 339 for (i = 0 ; i < IOP_MSG_LEN ; i++, offset++) { 340 iop_writeb(iop_base[iop_num], offset, msg->reply[i]); 341 } 342 343 iop_writeb(iop_base[iop_num], 344 IOP_ADDR_RECV_STATE + chan, IOP_MSG_COMPLETE); 345 iop_interrupt(iop_base[msg->iop_num]); 346 347 msg->status = IOP_MSGSTATUS_UNUSED; 348 } 349 350 /* 351 * Actually put a message into a send channel buffer 352 */ 353 354 static void iop_do_send(struct iop_msg *msg) 355 { 356 volatile struct mac_iop *iop = iop_base[msg->iop_num]; 357 int i,offset; 358 359 iop_pr_debug("iop_num %d chan %d message %*ph\n", 360 msg->iop_num, msg->channel, IOP_MSG_LEN, msg->message); 361 362 offset = IOP_ADDR_SEND_MSG + (msg->channel * IOP_MSG_LEN); 363 364 for (i = 0 ; i < IOP_MSG_LEN ; i++, offset++) { 365 iop_writeb(iop, offset, msg->message[i]); 366 } 367 368 iop_writeb(iop, IOP_ADDR_SEND_STATE + msg->channel, IOP_MSG_NEW); 369 370 iop_interrupt(iop); 371 } 372 373 /* 374 * Handle sending a message on a channel that 375 * has gone into the IOP_MSG_COMPLETE state. 376 */ 377 378 static void iop_handle_send(uint iop_num, uint chan) 379 { 380 volatile struct mac_iop *iop = iop_base[iop_num]; 381 struct iop_msg *msg; 382 int i,offset; 383 384 iop_writeb(iop, IOP_ADDR_SEND_STATE + chan, IOP_MSG_IDLE); 385 386 if (!(msg = iop_send_queue[iop_num][chan])) return; 387 388 msg->status = IOP_MSGSTATUS_COMPLETE; 389 offset = IOP_ADDR_SEND_MSG + (chan * IOP_MSG_LEN); 390 for (i = 0 ; i < IOP_MSG_LEN ; i++, offset++) { 391 msg->reply[i] = iop_readb(iop, offset); 392 } 393 iop_pr_debug("iop_num %d chan %d reply %*ph\n", 394 iop_num, chan, IOP_MSG_LEN, msg->reply); 395 396 if (msg->handler) (*msg->handler)(msg); 397 msg->status = IOP_MSGSTATUS_UNUSED; 398 msg = msg->next; 399 iop_send_queue[iop_num][chan] = msg; 400 if (msg && iop_readb(iop, IOP_ADDR_SEND_STATE + chan) == IOP_MSG_IDLE) 401 iop_do_send(msg); 402 } 403 404 /* 405 * Handle reception of a message on a channel that has 406 * gone into the IOP_MSG_NEW state. 407 */ 408 409 static void iop_handle_recv(uint iop_num, uint chan) 410 { 411 volatile struct mac_iop *iop = iop_base[iop_num]; 412 int i,offset; 413 struct iop_msg *msg; 414 415 msg = iop_get_unused_msg(); 416 msg->iop_num = iop_num; 417 msg->channel = chan; 418 msg->status = IOP_MSGSTATUS_UNSOL; 419 msg->handler = iop_listeners[iop_num][chan].handler; 420 421 offset = IOP_ADDR_RECV_MSG + (chan * IOP_MSG_LEN); 422 423 for (i = 0 ; i < IOP_MSG_LEN ; i++, offset++) { 424 msg->message[i] = iop_readb(iop, offset); 425 } 426 iop_pr_debug("iop_num %d chan %d message %*ph\n", 427 iop_num, chan, IOP_MSG_LEN, msg->message); 428 429 iop_writeb(iop, IOP_ADDR_RECV_STATE + chan, IOP_MSG_RCVD); 430 431 /* If there is a listener, call it now. Otherwise complete */ 432 /* the message ourselves to avoid possible stalls. */ 433 434 if (msg->handler) { 435 (*msg->handler)(msg); 436 } else { 437 memset(msg->reply, 0, IOP_MSG_LEN); 438 iop_complete_message(msg); 439 } 440 } 441 442 /* 443 * Send a message 444 * 445 * The message is placed at the end of the send queue. Afterwards if the 446 * channel is idle we force an immediate send of the next message in the 447 * queue. 448 */ 449 450 int iop_send_message(uint iop_num, uint chan, void *privdata, 451 uint msg_len, __u8 *msg_data, 452 void (*handler)(struct iop_msg *)) 453 { 454 struct iop_msg *msg, *q; 455 456 if ((iop_num >= NUM_IOPS) || !iop_base[iop_num]) return -EINVAL; 457 if (chan >= NUM_IOP_CHAN) return -EINVAL; 458 if (msg_len > IOP_MSG_LEN) return -EINVAL; 459 460 msg = iop_get_unused_msg(); 461 if (!msg) return -ENOMEM; 462 463 msg->next = NULL; 464 msg->status = IOP_MSGSTATUS_WAITING; 465 msg->iop_num = iop_num; 466 msg->channel = chan; 467 msg->caller_priv = privdata; 468 memcpy(msg->message, msg_data, msg_len); 469 msg->handler = handler; 470 471 if (!(q = iop_send_queue[iop_num][chan])) { 472 iop_send_queue[iop_num][chan] = msg; 473 iop_do_send(msg); 474 } else { 475 while (q->next) q = q->next; 476 q->next = msg; 477 } 478 479 return 0; 480 } 481 482 /* 483 * Upload code to the shared RAM of an IOP. 484 */ 485 486 void iop_upload_code(uint iop_num, __u8 *code_start, 487 uint code_len, __u16 shared_ram_start) 488 { 489 if ((iop_num >= NUM_IOPS) || !iop_base[iop_num]) return; 490 491 iop_loadaddr(iop_base[iop_num], shared_ram_start); 492 493 while (code_len--) { 494 iop_base[iop_num]->ram_data = *code_start++; 495 } 496 } 497 498 /* 499 * Download code from the shared RAM of an IOP. 500 */ 501 502 void iop_download_code(uint iop_num, __u8 *code_start, 503 uint code_len, __u16 shared_ram_start) 504 { 505 if ((iop_num >= NUM_IOPS) || !iop_base[iop_num]) return; 506 507 iop_loadaddr(iop_base[iop_num], shared_ram_start); 508 509 while (code_len--) { 510 *code_start++ = iop_base[iop_num]->ram_data; 511 } 512 } 513 514 /* 515 * Compare the code in the shared RAM of an IOP with a copy in system memory 516 * and return 0 on match or the first nonmatching system memory address on 517 * failure. 518 */ 519 520 __u8 *iop_compare_code(uint iop_num, __u8 *code_start, 521 uint code_len, __u16 shared_ram_start) 522 { 523 if ((iop_num >= NUM_IOPS) || !iop_base[iop_num]) return code_start; 524 525 iop_loadaddr(iop_base[iop_num], shared_ram_start); 526 527 while (code_len--) { 528 if (*code_start != iop_base[iop_num]->ram_data) { 529 return code_start; 530 } 531 code_start++; 532 } 533 return (__u8 *) 0; 534 } 535 536 /* 537 * Handle an ISM IOP interrupt 538 */ 539 540 irqreturn_t iop_ism_irq(int irq, void *dev_id) 541 { 542 uint iop_num = (uint) dev_id; 543 volatile struct mac_iop *iop = iop_base[iop_num]; 544 int i,state; 545 u8 events = iop->status_ctrl & (IOP_INT0 | IOP_INT1); 546 547 do { 548 iop_pr_debug("iop_num %d status %02X\n", iop_num, 549 iop->status_ctrl); 550 551 /* INT0 indicates state change on an outgoing message channel */ 552 if (events & IOP_INT0) { 553 iop->status_ctrl = IOP_INT0 | IOP_RUN | IOP_AUTOINC; 554 for (i = 0; i < NUM_IOP_CHAN; i++) { 555 state = iop_readb(iop, IOP_ADDR_SEND_STATE + i); 556 if (state == IOP_MSG_COMPLETE) 557 iop_handle_send(iop_num, i); 558 else if (state != IOP_MSG_IDLE) 559 iop_pr_debug("chan %d send state %02X\n", 560 i, state); 561 } 562 } 563 564 /* INT1 for incoming messages */ 565 if (events & IOP_INT1) { 566 iop->status_ctrl = IOP_INT1 | IOP_RUN | IOP_AUTOINC; 567 for (i = 0; i < NUM_IOP_CHAN; i++) { 568 state = iop_readb(iop, IOP_ADDR_RECV_STATE + i); 569 if (state == IOP_MSG_NEW) 570 iop_handle_recv(iop_num, i); 571 else if (state != IOP_MSG_IDLE) 572 iop_pr_debug("chan %d recv state %02X\n", 573 i, state); 574 } 575 } 576 577 events = iop->status_ctrl & (IOP_INT0 | IOP_INT1); 578 } while (events); 579 580 return IRQ_HANDLED; 581 } 582 583 void iop_ism_irq_poll(uint iop_num) 584 { 585 unsigned long flags; 586 587 local_irq_save(flags); 588 iop_ism_irq(0, (void *)iop_num); 589 local_irq_restore(flags); 590 } 591
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.