1 diff -urN linux-2.6.1/drivers/Kconfig linux-2.6.1-ibmasm/drivers/Kconfig
2 --- linux-2.6.1/drivers/Kconfig 2004-01-08 23:00:03.000000000 -0800
3 +++ linux-2.6.1-ibmasm/drivers/Kconfig 2004-01-14 13:21:36.000000000 -0800
6 source "drivers/char/Kconfig"
8 -# source "drivers/misc/Kconfig"
9 +source "drivers/misc/Kconfig"
11 source "drivers/media/Kconfig"
13 diff -urN linux-2.6.1/drivers/misc/ibmasm/command.c linux-2.6.1-ibmasm/drivers/misc/ibmasm/command.c
14 --- linux-2.6.1/drivers/misc/ibmasm/command.c 1969-12-31 16:00:00.000000000 -0800
15 +++ linux-2.6.1-ibmasm/drivers/misc/ibmasm/command.c 2004-01-22 11:57:28.000000000 -0800
19 + * IBM ASM Service Processor Device Driver
21 + * This program is free software; you can redistribute it and/or modify
22 + * it under the terms of the GNU General Public License as published by
23 + * the Free Software Foundation; either version 2 of the License, or
24 + * (at your option) any later version.
26 + * This program is distributed in the hope that it will be useful,
27 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 + * GNU General Public License for more details.
31 + * You should have received a copy of the GNU General Public License
32 + * along with this program; if not, write to the Free Software
33 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
35 + * Copyright (C) IBM Corporation, 2004
37 + * Author: Max Asböck <amax@us.ibm.com>
43 +static void exec_next_command(struct service_processor *sp);
44 +static void free_command(struct kobject *kobj);
46 +static struct kobj_type ibmasm_cmd_kobj_type = {
47 + .release = free_command,
51 +struct command *ibmasm_new_command(size_t buffer_size)
53 + struct command *cmd;
55 + if (buffer_size > IBMASM_CMD_MAX_BUFFER_SIZE)
58 + cmd = kmalloc(sizeof(struct command), GFP_KERNEL);
62 + memset(cmd, 0, sizeof(*cmd));
64 + cmd->buffer = kmalloc(buffer_size, GFP_KERNEL);
65 + if (cmd->buffer == NULL) {
69 + memset(cmd->buffer, 0, buffer_size);
70 + cmd->buffer_size = buffer_size;
72 + kobject_init(&cmd->kobj);
73 + cmd->kobj.ktype = &ibmasm_cmd_kobj_type;
75 + cmd->status = IBMASM_CMD_PENDING;
76 + init_waitqueue_head(&cmd->wait);
77 + INIT_LIST_HEAD(&cmd->queue_node);
82 +static void free_command(struct kobject *kobj)
84 + struct command *cmd = to_command(kobj);
86 + list_del(&cmd->queue_node);
91 +static void enqueue_command(struct service_processor *sp, struct command *cmd)
93 + list_add_tail(&cmd->queue_node, &sp->command_queue);
96 +static struct command *dequeue_command(struct service_processor *sp)
98 + struct command *cmd;
99 + struct list_head *next;
101 + if ( list_empty(&sp->command_queue) )
104 + next = sp->command_queue.next;
105 + list_del_init(next);
106 + cmd = list_entry(next, struct command, queue_node);
111 +static inline void do_exec_command(struct service_processor *sp)
113 + if ( ibmasm_send_i2o_message(sp) ) {
114 + sp->current_command->status = IBMASM_CMD_FAILED;
115 + exec_next_command(sp);
121 + * send a command to a service processor
122 + * Commands are executed sequentially. One command (sp->current_command)
123 + * is sent to the service processor. Once the interrupt handler gets a
124 + * message of type command_response, the message is copied into
125 + * the current commands buffer,
127 +void ibmasm_exec_command(struct service_processor *sp, struct command *cmd)
129 + unsigned long flags;
131 + spin_lock_irqsave(&sp->lock, flags);
133 + if ( !sp->current_command ) {
135 + sp->current_command = cmd;
136 + spin_unlock_irqrestore(&sp->lock, flags);
138 + do_exec_command(sp);
140 + enqueue_command(sp, cmd);
141 + spin_unlock_irqrestore(&sp->lock, flags);
145 +static void exec_next_command(struct service_processor *sp)
147 + unsigned long flags;
149 + wake_up(&sp->current_command->wait);
150 + command_put(sp->current_command);
152 + spin_lock_irqsave(&sp->lock, flags);
153 + sp->current_command = dequeue_command(sp);
154 + if ( sp->current_command ) {
155 + command_get(sp->current_command);
156 + spin_unlock_irqrestore(&sp->lock, flags);
157 + do_exec_command(sp);
159 + spin_unlock_irqrestore(&sp->lock, flags);
164 + * Sleep until a command has failed or a response has been received
165 + * and the command status been updated by the interrupt handler.
166 + * (see receive_response).
168 +void ibmasm_wait_for_response(struct command *cmd, int timeout)
170 + wait_event_interruptible_timeout(cmd->wait,
171 + cmd->status == IBMASM_CMD_COMPLETE ||
172 + cmd->status == IBMASM_CMD_FAILED,
177 + * receive_command_response
178 + * called by the interrupt handler when a dot command of type command_response
181 +void ibmasm_receive_command_response(struct service_processor *sp, void *response, size_t size)
183 + struct command *cmd = sp->current_command;
185 + if (!sp->current_command)
188 + memcpy(cmd->buffer, response, min(size, cmd->buffer_size));
189 + cmd->status = IBMASM_CMD_COMPLETE;
190 + exec_next_command(sp);
192 diff -urN linux-2.6.1/drivers/misc/ibmasm/dot_command.c linux-2.6.1-ibmasm/drivers/misc/ibmasm/dot_command.c
193 --- linux-2.6.1/drivers/misc/ibmasm/dot_command.c 1969-12-31 16:00:00.000000000 -0800
194 +++ linux-2.6.1-ibmasm/drivers/misc/ibmasm/dot_command.c 2004-01-22 11:10:20.000000000 -0800
197 + * IBM ASM Service Processor Device Driver
199 + * This program is free software; you can redistribute it and/or modify
200 + * it under the terms of the GNU General Public License as published by
201 + * the Free Software Foundation; either version 2 of the License, or
202 + * (at your option) any later version.
204 + * This program is distributed in the hope that it will be useful,
205 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
206 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
207 + * GNU General Public License for more details.
209 + * You should have received a copy of the GNU General Public License
210 + * along with this program; if not, write to the Free Software
211 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
213 + * Copyright (C) IBM Corporation, 2004
215 + * Author: Max Asböck <amax@us.ibm.com>
220 +#include "dot_command.h"
223 + * Dispatch an incoming message to the specific handler for the message.
224 + * Called from interrupt context.
226 +void ibmasm_receive_message(struct service_processor *sp, void *message, int message_size)
229 + struct dot_command_header *header = (struct dot_command_header *)message;
231 + size = get_dot_command_size(message);
232 + if (size > message_size)
233 + size = message_size;
235 + switch (header->type) {
237 + ibmasm_receive_event(sp, message, size);
239 + case sp_command_response:
240 + ibmasm_receive_command_response(sp, message, size);
243 + ibmasm_receive_heartbeat(sp, message, size);
246 + dev_err(sp->dev, "Received unknown message from service processor\n");
251 +#define INIT_BUFFER_SIZE 32
255 + * send the 4.3.5.10 dot command (driver VPD) to the service processor
257 +int ibmasm_send_driver_vpd(struct service_processor *sp)
259 + struct command *command;
260 + struct dot_command_header *header;
265 + command = ibmasm_new_command(INIT_BUFFER_SIZE);
266 + if (command == NULL)
269 + header = (struct dot_command_header *)command->buffer;
270 + header->type = sp_write;
271 + header->command_size = 4;
272 + header->data_size = 16;
273 + header->status = 0;
274 + header->reserved = 0;
276 + vpd_command = command->buffer + sizeof(struct dot_command_header);
277 + vpd_command[0] = 0x4;
278 + vpd_command[1] = 0x3;
279 + vpd_command[2] = 0x5;
280 + vpd_command[3] = 0xa;
282 + vpd_data = vpd_command + header->command_size;
284 + strcat(vpd_data, IBMASM_DRIVER_VPD);
288 + ibmasm_exec_command(sp, command);
289 + ibmasm_wait_for_response(command, IBMASM_CMD_TIMEOUT_NORMAL);
291 + if (command->status != IBMASM_CMD_COMPLETE)
294 + command_put(command);
299 +struct os_state_command {
300 + struct dot_command_header header;
301 + unsigned char command[3];
302 + unsigned char data;
306 + * send the 4.3.6 dot command (os state) to the service processor
307 + * During driver init this function is called with os state "up".
308 + * This causes the service processor to start sending heartbeats the
310 + * During driver exit the function is called with os state "down",
311 + * causing the service processor to stop the heartbeats.
313 +int ibmasm_send_os_state(struct service_processor *sp, int os_state)
315 + struct command *cmd;
316 + struct os_state_command *os_state_cmd;
319 + cmd = ibmasm_new_command(sizeof(struct os_state_command));
323 + os_state_cmd = (struct os_state_command *)cmd->buffer;
324 + os_state_cmd->header.type = sp_write;
325 + os_state_cmd->header.command_size = 3;
326 + os_state_cmd->header.data_size = 1;
327 + os_state_cmd->header.status = 0;
328 + os_state_cmd->command[0] = 4;
329 + os_state_cmd->command[1] = 3;
330 + os_state_cmd->command[2] = 6;
331 + os_state_cmd->data = os_state;
333 + ibmasm_exec_command(sp, cmd);
334 + ibmasm_wait_for_response(cmd, IBMASM_CMD_TIMEOUT_NORMAL);
336 + if (cmd->status != IBMASM_CMD_COMPLETE)
342 diff -urN linux-2.6.1/drivers/misc/ibmasm/dot_command.h linux-2.6.1-ibmasm/drivers/misc/ibmasm/dot_command.h
343 --- linux-2.6.1/drivers/misc/ibmasm/dot_command.h 1969-12-31 16:00:00.000000000 -0800
344 +++ linux-2.6.1-ibmasm/drivers/misc/ibmasm/dot_command.h 2004-01-23 15:40:55.000000000 -0800
347 + * IBM ASM Service Processor Device Driver
349 + * This program is free software; you can redistribute it and/or modify
350 + * it under the terms of the GNU General Public License as published by
351 + * the Free Software Foundation; either version 2 of the License, or
352 + * (at your option) any later version.
354 + * This program is distributed in the hope that it will be useful,
355 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
356 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
357 + * GNU General Public License for more details.
359 + * You should have received a copy of the GNU General Public License
360 + * along with this program; if not, write to the Free Software
361 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
363 + * Copyright (C) IBM Corporation, 2004
365 + * Author: Max Asböck <amax@us.ibm.com>
369 +#ifndef __DOT_COMMAND_H__
370 +#define __DOT_COMMAND_H__
373 + * dot commands are the protocol used to communicate with the service
375 + * They consist of header, a command of variable length and data of
379 +/* dot command types */
381 +#define sp_write_next 1
383 +#define sp_read_next 3
384 +#define sp_command_response 4
386 +#define sp_heartbeat 6
389 +struct dot_command_header {
398 +static inline size_t get_dot_command_size(void *buffer)
400 + struct dot_command_header *cmd = (struct dot_command_header *)buffer;
401 + return sizeof(struct dot_command_header) + cmd->command_size + cmd->data_size;
404 +static inline unsigned int get_dot_command_timeout(void *buffer)
406 + struct dot_command_header *header = (struct dot_command_header *)buffer;
407 + unsigned char *cmd = buffer + sizeof(struct dot_command_header);
409 + /* dot commands 6.3.1, 7.1 and 8.x need a longer timeout */
411 + if (header->command_size == 3) {
412 + if ( (cmd[0] == 6) && (cmd[1] == 3) && (cmd[2] == 1) )
413 + return IBMASM_CMD_TIMEOUT_EXTRA;
414 + } else if (header->command_size == 2) {
415 + if ( (cmd[0] == 7) && (cmd[1] == 1) )
416 + return IBMASM_CMD_TIMEOUT_EXTRA;
418 + return IBMASM_CMD_TIMEOUT_EXTRA;
420 + return IBMASM_CMD_TIMEOUT_NORMAL;
423 +#endif /* __DOT_COMMAND_H__ */
424 diff -urN linux-2.6.1/drivers/misc/ibmasm/event.c linux-2.6.1-ibmasm/drivers/misc/ibmasm/event.c
425 --- linux-2.6.1/drivers/misc/ibmasm/event.c 1969-12-31 16:00:00.000000000 -0800
426 +++ linux-2.6.1-ibmasm/drivers/misc/ibmasm/event.c 2004-01-20 11:16:29.000000000 -0800
430 + * IBM ASM Service Processor Device Driver
432 + * This program is free software; you can redistribute it and/or modify
433 + * it under the terms of the GNU General Public License as published by
434 + * the Free Software Foundation; either version 2 of the License, or
435 + * (at your option) any later version.
437 + * This program is distributed in the hope that it will be useful,
438 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
439 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
440 + * GNU General Public License for more details.
442 + * You should have received a copy of the GNU General Public License
443 + * along with this program; if not, write to the Free Software
444 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
446 + * Copyright (C) IBM Corporation, 2004
448 + * Author: Max Asböck <amax@us.ibm.com>
455 + * ASM service processor event handling routines.
457 + * Events are signalled to the device drivers through interrupts.
458 + * They have the format of dot commands, with the type field set to
460 + * The driver does not interpret the events, it simply stores them in a
465 +static void wake_up_event_readers(struct service_processor *sp)
467 + struct event_reader *reader;
468 + struct list_head *entry;
470 + list_for_each(entry, &sp->event_buffer->readers) {
471 + reader = list_entry(entry, struct event_reader, node);
472 + wake_up_interruptible(&reader->wait);
478 + * Called by the interrupt handler when a dot command of type sp_event is
480 + * Store the event in the circular event buffer, wake up any sleeping
482 + * There is no reader marker in the buffer, therefore readers are
483 + * responsible for keeping up with the writer, or they will loose events.
485 +void ibmasm_receive_event(struct service_processor *sp, void *data, size_t data_size)
487 + struct event_buffer *buffer = sp->event_buffer;
488 + struct ibmasm_event *event;
489 + unsigned long flags;
491 + data_size = min(data_size, IBMASM_EVENT_MAX_SIZE);
493 + spin_lock_irqsave(&sp->lock, flags);
494 + /* copy the event into the next slot in the circular buffer */
495 + event = &buffer->events[buffer->next_index];
496 + memcpy(event->data, data, data_size);
497 + event->data_size = data_size;
498 + event->serial_number = buffer->next_serial_number;
500 + /* advance indices in the buffer */
501 + buffer->next_index = ++(buffer->next_index) % IBMASM_NUM_EVENTS;
502 + buffer->next_serial_number++;
503 + spin_unlock_irqrestore(&sp->lock, flags);
505 + wake_up_event_readers(sp);
508 +static inline int event_available(struct event_buffer *b, struct event_reader *r)
510 + return (r->next_serial_number < b->next_serial_number);
515 + * Called by event readers (initiated from user space through the file
517 + * Sleeps until a new event is available.
519 +int ibmasm_get_next_event(struct service_processor *sp, struct event_reader *reader)
521 + struct event_buffer *buffer = sp->event_buffer;
522 + struct ibmasm_event *event;
523 + unsigned int index;
524 + unsigned long flags;
526 + if ( wait_event_interruptible(reader->wait, event_available(buffer, reader)) )
527 + return -ERESTARTSYS;
529 + if (!event_available(buffer, reader))
532 + spin_lock_irqsave(&sp->lock, flags);
534 + index = buffer->next_index;
535 + event = &buffer->events[index];
536 + while (event->serial_number < reader->next_serial_number) {
537 + index = (index + 1) % IBMASM_NUM_EVENTS;
538 + event = &buffer->events[index];
540 + memcpy(reader->data, event->data, event->data_size);
541 + reader->data_size = event->data_size;
542 + reader->next_serial_number = event->serial_number + 1;
544 + spin_unlock_irqrestore(&sp->lock, flags);
546 + return event->data_size;
549 +void ibmasm_event_reader_register(struct service_processor *sp, struct event_reader *reader)
551 + unsigned long flags;
553 + reader->next_serial_number = sp->event_buffer->next_serial_number;
554 + init_waitqueue_head(&reader->wait);
555 + spin_lock_irqsave(&sp->lock, flags);
556 + list_add(&reader->node, &sp->event_buffer->readers);
557 + spin_unlock_irqrestore(&sp->lock, flags);
560 +void ibmasm_event_reader_unregister(struct service_processor *sp, struct event_reader *reader)
562 + unsigned long flags;
564 + wake_up_interruptible(&reader->wait);
566 + spin_lock_irqsave(&sp->lock, flags);
567 + list_del(&reader->node);
568 + spin_unlock_irqrestore(&sp->lock, flags);
571 +int ibmasm_event_buffer_init(struct service_processor *sp)
573 + struct event_buffer *buffer;
574 + struct ibmasm_event *event;
577 + buffer = kmalloc(sizeof(struct event_buffer), GFP_KERNEL);
581 + buffer->next_index = 0;
582 + buffer->next_serial_number = 1;
584 + event = buffer->events;
585 + for (i=0; i<IBMASM_NUM_EVENTS; i++, event++)
586 + event->serial_number = 0;
588 + INIT_LIST_HEAD(&buffer->readers);
590 + sp->event_buffer = buffer;
595 +void ibmasm_event_buffer_exit(struct service_processor *sp)
597 + wake_up_event_readers(sp);
598 + kfree(sp->event_buffer);
600 diff -urN linux-2.6.1/drivers/misc/ibmasm/heartbeat.c linux-2.6.1-ibmasm/drivers/misc/ibmasm/heartbeat.c
601 --- linux-2.6.1/drivers/misc/ibmasm/heartbeat.c 1969-12-31 16:00:00.000000000 -0800
602 +++ linux-2.6.1-ibmasm/drivers/misc/ibmasm/heartbeat.c 2004-01-22 11:09:09.000000000 -0800
606 + * IBM ASM Service Processor Device Driver
608 + * This program is free software; you can redistribute it and/or modify
609 + * it under the terms of the GNU General Public License as published by
610 + * the Free Software Foundation; either version 2 of the License, or
611 + * (at your option) any later version.
613 + * This program is distributed in the hope that it will be useful,
614 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
615 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
616 + * GNU General Public License for more details.
618 + * You should have received a copy of the GNU General Public License
619 + * along with this program; if not, write to the Free Software
620 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
622 + * Copyright (C) IBM Corporation, 2004
624 + * Author: Max Asböck <amax@us.ibm.com>
628 +#include <linux/notifier.h>
630 +#include "dot_command.h"
632 +static int suspend_heartbeats = 0;
635 + * Once the driver indicates to the service processor that it is running
636 + * - see send_os_state() - the service processor sends periodic heartbeats
637 + * to the driver. The driver must respond to the heartbeats or else the OS
638 + * will be rebooted.
639 + * In the case of a panic the interrupt handler continues to work and thus
640 + * continues to respond to heartbeats, making the service processor believe
641 + * the OS is still running and thus preventing a reboot.
642 + * To prevent this from happening a callback is added the panic_notifier_list.
643 + * Before responding to a heartbeat the driver checks if a panic has happened,
644 + * if yes it suspends heartbeat, causing the service processor to reboot as
647 +static int panic_happened(struct notifier_block *n, unsigned long val, void *v)
649 + suspend_heartbeats = 1;
653 +static struct notifier_block panic_notifier = { panic_happened, NULL, 1 };
655 +void ibmasm_register_panic_notifier(void)
657 + notifier_chain_register(&panic_notifier_list, &panic_notifier);
660 +void ibmasm_unregister_panic_notifier(void)
662 + notifier_chain_unregister(&panic_notifier_list, &panic_notifier);
666 +int ibmasm_heartbeat_init(struct service_processor *sp)
668 + sp->heartbeat = ibmasm_new_command(HEARTBEAT_BUFFER_SIZE);
669 + if (sp->heartbeat == NULL)
675 +void ibmasm_heartbeat_exit(struct service_processor *sp)
677 + command_put(sp->heartbeat);
680 +void ibmasm_receive_heartbeat(struct service_processor *sp, void *message, size_t size)
682 + struct command *cmd = sp->heartbeat;
683 + struct dot_command_header *header = (struct dot_command_header *)cmd->buffer;
685 + if (suspend_heartbeats)
688 + /* return the received dot command to sender */
689 + cmd->status = IBMASM_CMD_PENDING;
690 + size = min(size, cmd->buffer_size);
691 + memcpy(cmd->buffer, message, size);
692 + header->type = sp_write;
693 + ibmasm_exec_command(sp, cmd);
695 diff -urN linux-2.6.1/drivers/misc/ibmasm/i2o.h linux-2.6.1-ibmasm/drivers/misc/ibmasm/i2o.h
696 --- linux-2.6.1/drivers/misc/ibmasm/i2o.h 1969-12-31 16:00:00.000000000 -0800
697 +++ linux-2.6.1-ibmasm/drivers/misc/ibmasm/i2o.h 2004-01-23 15:41:15.000000000 -0800
700 + * IBM ASM Service Processor Device Driver
702 + * This program is free software; you can redistribute it and/or modify
703 + * it under the terms of the GNU General Public License as published by
704 + * the Free Software Foundation; either version 2 of the License, or
705 + * (at your option) any later version.
707 + * This program is distributed in the hope that it will be useful,
708 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
709 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
710 + * GNU General Public License for more details.
712 + * You should have received a copy of the GNU General Public License
713 + * along with this program; if not, write to the Free Software
714 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
716 + * Copyright (C) IBM Corporation, 2004
718 + * Author: Max Asböck <amax@us.ibm.com>
728 + u8 initiator_and_target;
731 + u32 initiator_context;
735 +#define I2O_HEADER_TEMPLATE \
736 + { .version = 0x01, \
737 + .message_flags = 0x00, \
738 + .function = 0xFF, \
739 + .initiator = 0x00, \
740 + .initiator_and_target = 0x40, \
742 + .initiator_context = 0x0 }
744 +#define I2O_MESSAGE_SIZE 0x1000
745 +#define I2O_COMMAND_SIZE (I2O_MESSAGE_SIZE - sizeof(struct i2o_header))
748 +struct i2o_message {
749 + struct i2o_header header;
754 +static inline unsigned short outgoing_message_size(unsigned int data_size)
757 + unsigned short i2o_size;
759 + if (data_size > I2O_COMMAND_SIZE)
760 + data_size = I2O_COMMAND_SIZE;
762 + size = sizeof(struct i2o_header) + data_size;
764 + i2o_size = size / sizeof(u32);
766 + if (size % sizeof(u32))
772 +static inline u32 incoming_data_size(struct i2o_message *i2o_message)
774 + return (sizeof(u32) * i2o_message->header.message_size);
776 diff -urN linux-2.6.1/drivers/misc/ibmasm/ibmasm.h linux-2.6.1-ibmasm/drivers/misc/ibmasm/ibmasm.h
777 --- linux-2.6.1/drivers/misc/ibmasm/ibmasm.h 1969-12-31 16:00:00.000000000 -0800
778 +++ linux-2.6.1-ibmasm/drivers/misc/ibmasm/ibmasm.h 2004-01-26 10:05:25.000000000 -0800
782 + * IBM ASM Service Processor Device Driver
784 + * This program is free software; you can redistribute it and/or modify
785 + * it under the terms of the GNU General Public License as published by
786 + * the Free Software Foundation; either version 2 of the License, or
787 + * (at your option) any later version.
789 + * This program is distributed in the hope that it will be useful,
790 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
791 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
792 + * GNU General Public License for more details.
794 + * You should have received a copy of the GNU General Public License
795 + * along with this program; if not, write to the Free Software
796 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
798 + * Copyright (C) IBM Corporation, 2004
800 + * Author: Max Asböck <amax@us.ibm.com>
804 +#include <linux/kernel.h>
805 +#include <linux/types.h>
806 +#include <linux/errno.h>
807 +#include <linux/list.h>
808 +#include <linux/wait.h>
809 +#include <linux/spinlock.h>
810 +#include <linux/slab.h>
811 +#include <linux/config.h>
812 +#include <linux/module.h>
813 +#include <linux/version.h>
814 +#include <linux/interrupt.h>
815 +#include <linux/device.h>
817 +/* Driver identification */
818 +#define DRIVER_NAME "ibmasm"
819 +#define DRIVER_VERSION "0.3"
820 +#define DRIVER_AUTHOR "Max Asbock"
821 +#define DRIVER_DESC "IBM ASM Service Processor Driver"
823 +#define err(msg) printk(KERN_ERR "%s: " msg "\n", DRIVER_NAME)
824 +#define info(msg) printk(KERN_INFO "%s: " msg "\n", DRIVER_NAME)
827 +#define IBMASM_CMD_PENDING 0
828 +#define IBMASM_CMD_COMPLETE 1
829 +#define IBMASM_CMD_FAILED 2
831 +#define IBMASM_CMD_TIMEOUT_NORMAL 45
832 +#define IBMASM_CMD_TIMEOUT_EXTRA 240
834 +#define IBMASM_CMD_MAX_BUFFER_SIZE 0x4000
836 +#define REVERSE_HEARTBEAT_TIMEOUT 120
838 +#define HEARTBEAT_BUFFER_SIZE 0x400
841 +#define IBMASM_DRIVER_VPD "Lin64 6.08 "
843 +#define IBMASM_DRIVER_VPD "Lin32 6.08 "
846 +#define SYSTEM_STATE_OS_UP 5
847 +#define SYSTEM_STATE_OS_DOWN 4
849 +#define IBMASM_IOCTL_MAGIC 'f'
850 +#define IBMASM_IO_CANCEL _IO(IBMASM_IOCTL_MAGIC, 0)
852 +#define IBMASM_NAME_SIZE 16
854 +#define IBMASM_NUM_EVENTS 10
855 +#define IBMASM_EVENT_MAX_SIZE 2048u
859 + struct list_head queue_node;
860 + wait_queue_head_t wait;
861 + unsigned char *buffer;
862 + size_t buffer_size;
864 + struct kobject kobj;
866 +#define to_command(c) container_of(c, struct command, kobj)
868 +static inline void command_put(struct command *cmd)
870 + kobject_put(&cmd->kobj);
873 +static inline void command_get(struct command *cmd)
875 + kobject_get(&cmd->kobj);
879 +struct ibmasm_event {
880 + unsigned int serial_number;
881 + unsigned int data_size;
882 + unsigned char data[IBMASM_EVENT_MAX_SIZE];
885 +struct event_buffer {
886 + struct ibmasm_event events[IBMASM_NUM_EVENTS];
887 + unsigned int next_serial_number;
888 + unsigned int next_index;
889 + struct list_head readers;
892 +struct event_reader {
893 + unsigned int next_serial_number;
894 + wait_queue_head_t wait;
895 + struct list_head node;
896 + unsigned int data_size;
897 + unsigned char data[IBMASM_EVENT_MAX_SIZE];
900 +struct reverse_heartbeat {
901 + wait_queue_head_t wait;
902 + unsigned int stopped;
906 +/* remote console events */
907 +struct mouse_event {
910 + unsigned char buttons;
911 + unsigned char transitions;
914 +struct keyboard_event {
915 + unsigned long key_code;
916 + unsigned char key_down;
919 +struct remote_event {
920 + unsigned long type;
922 + struct mouse_event mouse;
923 + struct keyboard_event keyboard;
927 +#define DRIVER_REMOTE_QUEUE_SIZE 240
929 +struct remote_queue {
930 + struct remote_event *start;
931 + struct remote_event *end;
932 + struct remote_event *reader;
933 + struct remote_event *writer;
936 + wait_queue_head_t wait;
940 +struct service_processor {
941 + struct list_head node;
943 + void *base_address;
945 + struct command *current_command;
946 + struct command *heartbeat;
947 + struct list_head command_queue;
948 + struct event_buffer *event_buffer;
949 + char dirname[IBMASM_NAME_SIZE];
950 + char devname[IBMASM_NAME_SIZE];
951 + unsigned int number;
952 + struct remote_queue remote_queue;
954 + struct device *dev;
957 +/* command processing */
958 +extern struct command *ibmasm_new_command(size_t buffer_size);
959 +extern void ibmasm_exec_command(struct service_processor *sp, struct command *cmd);
960 +extern void ibmasm_wait_for_response(struct command *cmd, int timeout);
961 +extern void ibmasm_receive_command_response(struct service_processor *sp, void *response, size_t size);
963 +/* event processing */
964 +extern int ibmasm_event_buffer_init(struct service_processor *sp);
965 +extern void ibmasm_event_buffer_exit(struct service_processor *sp);
966 +extern void ibmasm_receive_event(struct service_processor *sp, void *data, size_t data_size);
967 +extern void ibmasm_event_reader_register(struct service_processor *sp, struct event_reader *reader);
968 +extern void ibmasm_event_reader_unregister(struct service_processor *sp, struct event_reader *reader);
969 +extern int ibmasm_get_next_event(struct service_processor *sp, struct event_reader *reader);
971 +/* heartbeat - from SP to OS */
972 +extern void ibmasm_register_panic_notifier(void);
973 +extern void ibmasm_unregister_panic_notifier(void);
974 +extern int ibmasm_heartbeat_init(struct service_processor *sp);
975 +extern void ibmasm_heartbeat_exit(struct service_processor *sp);
976 +extern void ibmasm_receive_heartbeat(struct service_processor *sp, void *message, size_t size);
978 +/* reverse heartbeat - from OS to SP */
979 +extern void ibmasm_init_reverse_heartbeat(struct service_processor *sp, struct reverse_heartbeat *rhb);
980 +extern int ibmasm_start_reverse_heartbeat(struct service_processor *sp, struct reverse_heartbeat *rhb);
981 +extern void ibmasm_stop_reverse_heartbeat(struct reverse_heartbeat *rhb);
984 +extern void ibmasm_receive_message(struct service_processor *sp, void *data, int data_size);
985 +extern int ibmasm_send_driver_vpd(struct service_processor *sp);
986 +extern int ibmasm_send_os_state(struct service_processor *sp, int os_state);
988 +/* low level message processing */
989 +extern int ibmasm_send_i2o_message(struct service_processor *sp);
990 +extern irqreturn_t ibmasm_interrupt_handler(int irq, void * dev_id, struct pt_regs *regs);
992 +/* remote console */
993 +extern void ibmasm_handle_mouse_interrupt(struct service_processor *sp);
994 +extern int ibmasm_init_remote_queue(struct service_processor *sp);
995 +extern void ibmasm_free_remote_queue(struct service_processor *sp);
996 +extern void ibmasm_advance_reader(struct remote_queue *q, unsigned int n);
997 +extern size_t ibmasm_events_available(struct remote_queue *q);
1000 +extern int ibmasmfs_register(void);
1001 +extern void ibmasmfs_unregister(void);
1002 +extern void ibmasmfs_add_sp(struct service_processor *sp);
1005 +extern void ibmasm_register_uart(struct service_processor *sp);
1006 +extern void ibmasm_unregister_uart(struct service_processor *sp);
1007 diff -urN linux-2.6.1/drivers/misc/ibmasm/lowlevel.c linux-2.6.1-ibmasm/drivers/misc/ibmasm/lowlevel.c
1008 --- linux-2.6.1/drivers/misc/ibmasm/lowlevel.c 1969-12-31 16:00:00.000000000 -0800
1009 +++ linux-2.6.1-ibmasm/drivers/misc/ibmasm/lowlevel.c 2004-01-14 16:41:31.000000000 -0800
1012 + * IBM ASM Service Processor Device Driver
1014 + * This program is free software; you can redistribute it and/or modify
1015 + * it under the terms of the GNU General Public License as published by
1016 + * the Free Software Foundation; either version 2 of the License, or
1017 + * (at your option) any later version.
1019 + * This program is distributed in the hope that it will be useful,
1020 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1021 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1022 + * GNU General Public License for more details.
1024 + * You should have received a copy of the GNU General Public License
1025 + * along with this program; if not, write to the Free Software
1026 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1028 + * Copyright (C) IBM Corporation, 2004
1030 + * Author: Max Asböck <amax@us.ibm.com>
1034 +#include "ibmasm.h"
1035 +#include "lowlevel.h"
1037 +#include "dot_command.h"
1038 +#include "remote.h"
1040 +static struct i2o_header header = I2O_HEADER_TEMPLATE;
1043 +int ibmasm_send_i2o_message(struct service_processor *sp)
1046 + unsigned int command_size;
1047 + struct i2o_message *message;
1048 + struct command *command = sp->current_command;
1050 + mfa = get_mfa_inbound(sp->base_address);
1054 + command_size = get_dot_command_size(command->buffer);
1055 + header.message_size = outgoing_message_size(command_size);
1057 + message = get_i2o_message(sp->base_address, mfa);
1059 + memcpy(&message->header, &header, sizeof(struct i2o_header));
1060 + memcpy(&message->data, command->buffer, command_size);
1062 + set_mfa_inbound(sp->base_address, mfa);
1067 +irqreturn_t ibmasm_interrupt_handler(int irq, void * dev_id, struct pt_regs *regs)
1070 + struct service_processor *sp = (struct service_processor *)dev_id;
1071 + void *base_address = sp->base_address;
1073 + if (!sp_interrupt_pending(base_address))
1076 + if ( mouse_interrupt_pending(sp) ) {
1077 + ibmasm_handle_mouse_interrupt(sp);
1078 + mfa = get_mfa_outbound(base_address);
1079 + clear_mouse_interrupt(sp);
1080 + set_mfa_outbound(base_address, mfa);
1081 + return IRQ_HANDLED;
1084 + mfa = get_mfa_outbound(base_address);
1085 + if ( valid_mfa(mfa) ) {
1086 + struct i2o_message *msg = get_i2o_message(base_address, mfa);
1087 + ibmasm_receive_message(sp, &msg->data, incoming_data_size(msg));
1089 + set_mfa_outbound(base_address, mfa);
1090 + return IRQ_HANDLED;
1092 diff -urN linux-2.6.1/drivers/misc/ibmasm/lowlevel.h linux-2.6.1-ibmasm/drivers/misc/ibmasm/lowlevel.h
1093 --- linux-2.6.1/drivers/misc/ibmasm/lowlevel.h 1969-12-31 16:00:00.000000000 -0800
1094 +++ linux-2.6.1-ibmasm/drivers/misc/ibmasm/lowlevel.h 2004-01-14 16:41:42.000000000 -0800
1097 + * IBM ASM Service Processor Device Driver
1099 + * This program is free software; you can redistribute it and/or modify
1100 + * it under the terms of the GNU General Public License as published by
1101 + * the Free Software Foundation; either version 2 of the License, or
1102 + * (at your option) any later version.
1104 + * This program is distributed in the hope that it will be useful,
1105 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1106 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1107 + * GNU General Public License for more details.
1109 + * You should have received a copy of the GNU General Public License
1110 + * along with this program; if not, write to the Free Software
1111 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1113 + * Copyright (C) IBM Corporation, 2004
1115 + * Author: Max Asböck <amax@us.ibm.com>
1119 +/* Condor service processor specific hardware definitions */
1121 +#ifndef __IBMASM_CONDOR_H__
1122 +#define __IBMASM_CONDOR_H__
1124 +#include <asm/io.h>
1126 +#define VENDORID_IBM 0x1014
1127 +#define DEVICEID_RSA 0x010F
1129 +#define GET_MFA_ADDR(x) (x & 0xFFFFFF00)
1131 +#define MAILBOX_FULL(x) (x & 0x00000001)
1133 +#define NO_MFAS_AVAILABLE 0xFFFFFFFF
1136 +#define INBOUND_QUEUE_PORT 0x40 /* contains address of next free MFA */
1137 +#define OUTBOUND_QUEUE_PORT 0x44 /* contains address of posted MFA */
1139 +#define SP_INTR_MASK 0x00000008
1140 +#define UART_INTR_MASK 0x00000010
1142 +#define INTR_STATUS_REGISTER 0x13A0
1143 +#define INTR_CONTROL_REGISTER 0x13A4
1145 +#define SCOUT_COM_A_BASE 0x0000
1146 +#define SCOUT_COM_B_BASE 0x0100
1147 +#define SCOUT_COM_C_BASE 0x0200
1148 +#define SCOUT_COM_D_BASE 0x0300
1150 +static inline int sp_interrupt_pending(void *base_address)
1152 + return SP_INTR_MASK & readl(base_address + INTR_STATUS_REGISTER);
1155 +static inline int uart_interrupt_pending(void *base_address)
1157 + return UART_INTR_MASK & readl(base_address + INTR_STATUS_REGISTER);
1160 +static inline void ibmasm_enable_interrupts(void *base_address, int mask)
1162 + void *ctrl_reg = base_address + INTR_CONTROL_REGISTER;
1163 + writel( readl(ctrl_reg) & ~mask, ctrl_reg);
1166 +static inline void ibmasm_disable_interrupts(void *base_address, int mask)
1168 + void *ctrl_reg = base_address + INTR_CONTROL_REGISTER;
1169 + writel( readl(ctrl_reg) | mask, ctrl_reg);
1172 +static inline void enable_sp_interrupts(void *base_address)
1174 + ibmasm_enable_interrupts(base_address, SP_INTR_MASK);
1177 +static inline void disable_sp_interrupts(void *base_address)
1179 + ibmasm_disable_interrupts(base_address, SP_INTR_MASK);
1182 +static inline void enable_uart_interrupts(void *base_address)
1184 + ibmasm_enable_interrupts(base_address, UART_INTR_MASK);
1187 +static inline void disable_uart_interrupts(void *base_address)
1189 + ibmasm_disable_interrupts(base_address, UART_INTR_MASK);
1192 +#define valid_mfa(mfa) ( (mfa) != NO_MFAS_AVAILABLE )
1194 +static inline u32 get_mfa_outbound(void *base_address)
1199 + for (retry=0; retry<=10; retry++) {
1200 + mfa = readl(base_address + OUTBOUND_QUEUE_PORT);
1201 + if ( valid_mfa(mfa) )
1207 +static inline void set_mfa_outbound(void *base_address, u32 mfa)
1209 + writel(mfa, base_address + OUTBOUND_QUEUE_PORT);
1212 +static inline u32 get_mfa_inbound(void *base_address)
1214 + u32 mfa = readl(base_address + INBOUND_QUEUE_PORT);
1216 + if ( MAILBOX_FULL(mfa) )
1222 +static inline void set_mfa_inbound(void *base_address, u32 mfa)
1224 + writel(mfa, base_address + INBOUND_QUEUE_PORT);
1227 +static inline struct i2o_message *get_i2o_message(void *base_address, u32 mfa)
1229 + return (struct i2o_message *)(GET_MFA_ADDR(mfa) + base_address);
1232 +#endif /* __IBMASM_CONDOR_H__ */
1233 diff -urN linux-2.6.1/drivers/misc/ibmasm/Makefile linux-2.6.1-ibmasm/drivers/misc/ibmasm/Makefile
1234 --- linux-2.6.1/drivers/misc/ibmasm/Makefile 1969-12-31 16:00:00.000000000 -0800
1235 +++ linux-2.6.1-ibmasm/drivers/misc/ibmasm/Makefile 2004-01-14 14:50:21.000000000 -0800
1238 +obj-$(CONFIG_IBM_ASM) := ibmasm.o
1240 +ibmasm-objs := module.o \
1250 diff -urN linux-2.6.1/drivers/misc/ibmasm/module.c linux-2.6.1-ibmasm/drivers/misc/ibmasm/module.c
1251 --- linux-2.6.1/drivers/misc/ibmasm/module.c 1969-12-31 16:00:00.000000000 -0800
1252 +++ linux-2.6.1-ibmasm/drivers/misc/ibmasm/module.c 2004-01-20 13:05:38.000000000 -0800
1256 + * IBM ASM Service Processor Device Driver
1258 + * This program is free software; you can redistribute it and/or modify
1259 + * it under the terms of the GNU General Public License as published by
1260 + * the Free Software Foundation; either version 2 of the License, or
1261 + * (at your option) any later version.
1263 + * This program is distributed in the hope that it will be useful,
1264 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1265 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1266 + * GNU General Public License for more details.
1268 + * You should have received a copy of the GNU General Public License
1269 + * along with this program; if not, write to the Free Software
1270 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1272 + * Copyright (C) IBM Corporation, 2004
1274 + * Author: Max Asböck <amax@us.ibm.com>
1276 + * This driver is based on code originally written by Pete Reynolds
1282 + * The ASM device driver does the following things:
1284 + * 1) When loaded it sends a message to the service processor,
1285 + * indicating that an OS is * running. This causes the service processor
1286 + * to send periodic heartbeats to the OS.
1288 + * 2) Answers the periodic heartbeats sent by the service processor.
1289 + * Failure to do so would result in system reboot.
1291 + * 3) Acts as a pass through for dot commands sent from user applications.
1292 + * The interface for this is the ibmasmfs file system.
1294 + * 4) Allows user applications to register for event notification. Events
1295 + * are sent to the driver through interrupts. They can be read from user
1296 + * space through the ibmasmfs file system.
1298 + * 5) Allows user space applications to send heartbeats to the service
1299 + * processor (aka reverse heartbeats). Again this happens through ibmasmfs.
1301 + * 6) Handles remote mouse and keyboard event interrupts and makes them
1302 + * available to user applications through ibmasmfs.
1306 +#include <linux/pci.h>
1307 +#include <linux/init.h>
1308 +#include "ibmasm.h"
1309 +#include "lowlevel.h"
1310 +#include "remote.h"
1313 +static int __init ibmasm_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
1316 + struct service_processor *sp;
1318 + sp = kmalloc(sizeof(struct service_processor), GFP_KERNEL);
1320 + dev_err(&pdev->dev, "Failed to allocate memory\n");
1323 + memset(sp, 0, sizeof(struct service_processor));
1325 + pci_set_drvdata(pdev, (void *)sp);
1326 + sp->dev = &pdev->dev;
1327 + sp->number = pdev->bus->number;
1328 + snprintf(sp->dirname, IBMASM_NAME_SIZE, "%d", sp->number);
1329 + snprintf(sp->devname, IBMASM_NAME_SIZE, "%s%d", DRIVER_NAME, sp->number);
1331 + if (ibmasm_event_buffer_init(sp)) {
1332 + dev_err(sp->dev, "Failed to allocate event buffer\n");
1334 + goto error_eventbuffer;
1337 + if (ibmasm_heartbeat_init(sp)) {
1338 + dev_err(sp->dev, "Failed to allocate heartbeat command\n");
1340 + goto error_heartbeat;
1343 + sp->irq = pdev->irq;
1344 + sp->base_address = ioremap(pci_resource_start(pdev, 0),
1345 + pci_resource_len(pdev, 0));
1346 + if (sp->base_address == 0) {
1347 + dev_err(sp->dev, "Failed to ioremap pci memory\n");
1349 + goto error_ioremap;
1352 + result = ibmasm_init_remote_queue(sp);
1354 + dev_err(sp->dev, "Failed to initialize remote queue\n");
1355 + goto error_remote_queue;
1358 + sp->lock = SPIN_LOCK_UNLOCKED;
1359 + INIT_LIST_HEAD(&sp->command_queue);
1361 + result = request_irq(sp->irq, ibmasm_interrupt_handler, SA_SHIRQ, sp->devname, (void*)sp);
1363 + dev_err(sp->dev, "Failed to register interrupt handler\n");
1364 + goto error_request_irq;
1367 + enable_sp_interrupts(sp->base_address);
1368 + disable_mouse_interrupts(sp);
1370 + result = ibmasm_send_driver_vpd(sp);
1372 + dev_err(sp->dev, "Failed to send driver VPD to service processor\n");
1373 + goto error_send_message;
1375 + result = ibmasm_send_os_state(sp, SYSTEM_STATE_OS_UP);
1377 + dev_err(sp->dev, "Failed to send OS state to service processor\n");
1378 + goto error_send_message;
1380 + ibmasmfs_add_sp(sp);
1382 + ibmasm_register_uart(sp);
1386 +error_send_message:
1387 + disable_sp_interrupts(sp->base_address);
1388 + free_irq(sp->irq, (void *)sp);
1390 + ibmasm_free_remote_queue(sp);
1391 +error_remote_queue:
1392 + iounmap(sp->base_address);
1394 + ibmasm_heartbeat_exit(sp);
1396 + ibmasm_event_buffer_exit(sp);
1403 +static void __exit ibmasm_remove_one(struct pci_dev *pdev)
1405 + struct service_processor *sp = (struct service_processor *)pci_get_drvdata(pdev);
1407 + ibmasm_unregister_uart(sp);
1408 + ibmasm_send_os_state(sp, SYSTEM_STATE_OS_DOWN);
1409 + disable_sp_interrupts(sp->base_address);
1410 + disable_mouse_interrupts(sp);
1411 + free_irq(sp->irq, (void *)sp);
1412 + ibmasm_heartbeat_exit(sp);
1413 + ibmasm_free_remote_queue(sp);
1414 + iounmap(sp->base_address);
1415 + ibmasm_event_buffer_exit(sp);
1419 +static struct pci_device_id ibmasm_pci_table[] =
1421 + { PCI_DEVICE(VENDORID_IBM, DEVICEID_RSA) },
1425 +static struct pci_driver ibmasm_driver = {
1426 + .name = DRIVER_NAME,
1427 + .id_table = ibmasm_pci_table,
1428 + .probe = ibmasm_init_one,
1429 + .remove = __devexit_p(ibmasm_remove_one),
1432 +static void __exit ibmasm_exit (void)
1434 + ibmasm_unregister_panic_notifier();
1435 + ibmasmfs_unregister();
1436 + pci_unregister_driver(&ibmasm_driver);
1437 + info(DRIVER_DESC " version " DRIVER_VERSION " unloaded");
1440 +static int __init ibmasm_init(void)
1444 + result = ibmasmfs_register();
1446 + err("Failed to register ibmasmfs file system");
1449 + result = pci_register_driver(&ibmasm_driver);
1450 + if (result <= 0) {
1451 + pci_unregister_driver(&ibmasm_driver);
1452 + ibmasmfs_unregister();
1455 + ibmasm_register_panic_notifier();
1456 + info(DRIVER_DESC " version " DRIVER_VERSION " loaded");
1460 +module_init(ibmasm_init);
1461 +module_exit(ibmasm_exit);
1463 +MODULE_AUTHOR(DRIVER_AUTHOR);
1464 +MODULE_DESCRIPTION(DRIVER_DESC);
1465 +MODULE_LICENSE("GPL");
1466 diff -urN linux-2.6.1/drivers/misc/ibmasm/remote.c linux-2.6.1-ibmasm/drivers/misc/ibmasm/remote.c
1467 --- linux-2.6.1/drivers/misc/ibmasm/remote.c 1969-12-31 16:00:00.000000000 -0800
1468 +++ linux-2.6.1-ibmasm/drivers/misc/ibmasm/remote.c 2004-01-14 16:42:01.000000000 -0800
1472 + * IBM ASM Service Processor Device Driver
1474 + * This program is free software; you can redistribute it and/or modify
1475 + * it under the terms of the GNU General Public License as published by
1476 + * the Free Software Foundation; either version 2 of the License, or
1477 + * (at your option) any later version.
1479 + * This program is distributed in the hope that it will be useful,
1480 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1481 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1482 + * GNU General Public License for more details.
1484 + * You should have received a copy of the GNU General Public License
1485 + * along with this program; if not, write to the Free Software
1486 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1488 + * Copyright (C) IBM Corporation, 2004
1490 + * Author: Max Asböck <amax@us.ibm.com>
1494 +/* Remote mouse and keyboard event handling functions */
1496 +#include "ibmasm.h"
1497 +#include "remote.h"
1499 +int ibmasm_init_remote_queue(struct service_processor *sp)
1501 + struct remote_queue *q = &sp->remote_queue;
1503 + disable_mouse_interrupts(sp);
1508 + q->start = kmalloc(DRIVER_REMOTE_QUEUE_SIZE * sizeof(struct remote_event), GFP_KERNEL);
1509 + if (q->start == 0)
1512 + q->end = q->start + DRIVER_REMOTE_QUEUE_SIZE;
1513 + q->reader = q->start;
1514 + q->writer = q->start;
1515 + q->size = DRIVER_REMOTE_QUEUE_SIZE;
1516 + init_waitqueue_head(&q->wait);
1521 +void ibmasm_free_remote_queue(struct service_processor *sp)
1523 + if (sp->remote_queue.start)
1524 + kfree(sp->remote_queue.start);
1527 +void ibmasm_advance_reader(struct remote_queue *q, unsigned int n)
1530 + if (q->reader >= q->end)
1531 + q->reader -= q->size;
1534 +size_t ibmasm_events_available(struct remote_queue *q)
1536 + ssize_t diff = q->writer - q->reader;
1541 + return (q->end - q->reader);
1545 +static int space_free(struct remote_queue *q)
1547 + if (q->reader == q->writer)
1548 + return q->size - 1;
1550 + return ( (q->reader + q->size - q->writer) % q->size ) - 1;
1553 +static void set_mouse_event(struct remote_input *input, struct mouse_event *mouse)
1555 + static char last_buttons = 0;
1557 + mouse->x = input->data.mouse.x;
1558 + mouse->y = input->data.mouse.y;
1560 + if (input->mouse_buttons == REMOTE_MOUSE_DOUBLE_CLICK) {
1561 + mouse->buttons = REMOTE_MOUSE_DOUBLE_CLICK;
1565 + mouse->transitions = last_buttons ^ input->mouse_buttons;
1566 + mouse->buttons = input->mouse_buttons;
1568 + last_buttons = input->mouse_buttons;
1571 +static void set_keyboard_event(struct remote_input *input, struct keyboard_event *keyboard)
1573 + keyboard->key_code = input->data.keyboard.key_code;
1574 + keyboard->key_down = input->data.keyboard.key_down;
1577 +static int add_to_driver_queue(struct remote_queue *q, struct remote_input *input)
1579 + struct remote_event *event = q->writer;
1581 + if ( space_free(q) < 1 ) {
1585 + switch(input->type) {
1586 + case (INPUT_TYPE_MOUSE):
1587 + event->type = INPUT_TYPE_MOUSE;
1588 + set_mouse_event(input, &event->data.mouse);
1590 + case (INPUT_TYPE_KEYBOARD):
1591 + event->type = INPUT_TYPE_KEYBOARD;
1592 + set_keyboard_event(input, &event->data.keyboard);
1597 + event->type = input->type;
1600 + if (q->writer == q->end)
1601 + q->writer = q->start;
1607 +void ibmasm_handle_mouse_interrupt(struct service_processor *sp)
1609 + unsigned long reader;
1610 + unsigned long writer;
1611 + struct remote_input input;
1613 + reader = get_queue_reader(sp);
1614 + writer = get_queue_writer(sp);
1616 + while (reader != writer) {
1617 + memcpy(&input, (void *)get_queue_entry(sp, reader), sizeof(struct remote_input));
1619 + if ( add_to_driver_queue(&sp->remote_queue, &input) )
1622 + reader = advance_queue_reader(sp, reader);
1624 + wake_up_interruptible(&sp->remote_queue.wait);
1626 diff -urN linux-2.6.1/drivers/misc/ibmasm/remote.h linux-2.6.1-ibmasm/drivers/misc/ibmasm/remote.h
1627 --- linux-2.6.1/drivers/misc/ibmasm/remote.h 1969-12-31 16:00:00.000000000 -0800
1628 +++ linux-2.6.1-ibmasm/drivers/misc/ibmasm/remote.h 2004-01-14 16:42:14.000000000 -0800
1632 + * IBM ASM Service Processor Device Driver
1634 + * This program is free software; you can redistribute it and/or modify
1635 + * it under the terms of the GNU General Public License as published by
1636 + * the Free Software Foundation; either version 2 of the License, or
1637 + * (at your option) any later version.
1639 + * This program is distributed in the hope that it will be useful,
1640 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1641 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1642 + * GNU General Public License for more details.
1644 + * You should have received a copy of the GNU General Public License
1645 + * along with this program; if not, write to the Free Software
1646 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1648 + * Copyright (C) IBM Corporation, 2004
1650 + * Author: Max Asböck <amax@us.ibm.com>
1652 + * Orignally written by Pete Reynolds
1655 +#ifndef _IBMASM_REMOTE_H_
1656 +#define _IBMASM_REMOTE_H_
1658 +#include <asm/io.h>
1661 +#define CONDOR_MOUSE_DATA 0x000AC000
1662 +#define CONDOR_MOUSE_ISR_CONTROL 0x00
1663 +#define CONDOR_MOUSE_ISR_STATUS 0x04
1664 +#define CONDOR_MOUSE_Q_READER 0x08
1665 +#define CONDOR_MOUSE_Q_WRITER 0x0C
1666 +#define CONDOR_MOUSE_Q_BEGIN 0x10
1667 +#define CONDOR_MOUSE_MAX_X 0x14
1668 +#define CONDOR_MOUSE_MAX_Y 0x18
1670 +#define CONDOR_INPUT_DESKTOP_INFO 0x1F0
1671 +#define CONDOR_INPUT_DISPLAY_RESX 0x1F4
1672 +#define CONDOR_INPUT_DISPLAY_RESY 0x1F8
1673 +#define CONDOR_INPUT_DISPLAY_BITS 0x1FC
1674 +#define CONDOR_OUTPUT_VNC_STATUS 0x200
1676 +#define CONDOR_MOUSE_INTR_STATUS_MASK 0x00000001
1678 +#define INPUT_TYPE_MOUSE 0x1
1679 +#define INPUT_TYPE_KEYBOARD 0x2
1682 +/* mouse button states received from SP */
1683 +#define REMOTE_MOUSE_DOUBLE_CLICK 0xF0
1684 +#define REMOTE_MOUSE_BUTTON_LEFT 0x01
1685 +#define REMOTE_MOUSE_BUTTON_MIDDLE 0x02
1686 +#define REMOTE_MOUSE_BUTTON_RIGHT 0x04
1689 +struct mouse_input {
1695 +struct keyboard_input {
1696 + unsigned short key_code;
1697 + unsigned char key_flag;
1698 + unsigned char key_down;
1703 +struct remote_input {
1705 + struct mouse_input mouse;
1706 + struct keyboard_input keyboard;
1709 + unsigned char type;
1710 + unsigned char pad1;
1711 + unsigned char mouse_buttons;
1712 + unsigned char pad3;
1715 +#define mouse_addr(sp) sp->base_address + CONDOR_MOUSE_DATA
1716 +#define display_width(sp) mouse_addr(sp) + CONDOR_INPUT_DISPLAY_RESX
1717 +#define display_height(sp) mouse_addr(sp) + CONDOR_INPUT_DISPLAY_RESY
1718 +#define display_depth(sp) mouse_addr(sp) + CONDOR_INPUT_DISPLAY_BITS
1719 +#define vnc_status(sp) mouse_addr(sp) + CONDOR_OUTPUT_VNC_STATUS
1721 +#define mouse_interrupt_pending(sp) readl(mouse_addr(sp) + CONDOR_MOUSE_ISR_STATUS)
1722 +#define clear_mouse_interrupt(sp) writel(0, mouse_addr(sp) + CONDOR_MOUSE_ISR_STATUS)
1723 +#define enable_mouse_interrupts(sp) writel(1, mouse_addr(sp) + CONDOR_MOUSE_ISR_CONTROL)
1724 +#define disable_mouse_interrupts(sp) writel(0, mouse_addr(sp) + CONDOR_MOUSE_ISR_CONTROL)
1726 +/* remote input queue operations */
1727 +#define REMOTE_QUEUE_SIZE 60
1729 +#define get_queue_writer(sp) readl(mouse_addr(sp) + CONDOR_MOUSE_Q_WRITER)
1730 +#define get_queue_reader(sp) readl(mouse_addr(sp) + CONDOR_MOUSE_Q_READER)
1731 +#define set_queue_reader(sp, reader) writel(reader, mouse_addr(sp) + CONDOR_MOUSE_Q_READER)
1733 +#define queue_begin mouse_addr(sp) + CONDOR_MOUSE_Q_BEGIN
1735 +#define get_queue_entry(sp, read_index) \
1736 + queue_begin + read_index * sizeof(struct remote_input)
1738 +static inline int advance_queue_reader(struct service_processor *sp, unsigned long reader)
1741 + if (reader == REMOTE_QUEUE_SIZE)
1744 + set_queue_reader(sp, reader);
1748 +#endif /* _IBMASM_REMOTE_H_ */
1749 diff -urN linux-2.6.1/drivers/misc/ibmasm/r_heartbeat.c linux-2.6.1-ibmasm/drivers/misc/ibmasm/r_heartbeat.c
1750 --- linux-2.6.1/drivers/misc/ibmasm/r_heartbeat.c 1969-12-31 16:00:00.000000000 -0800
1751 +++ linux-2.6.1-ibmasm/drivers/misc/ibmasm/r_heartbeat.c 2004-01-22 11:08:48.000000000 -0800
1755 + * This program is free software; you can redistribute it and/or modify
1756 + * it under the terms of the GNU General Public License as published by
1757 + * the Free Software Foundation; either version 2 of the License, or
1758 + * (at your option) any later version.
1760 + * This program is distributed in the hope that it will be useful,
1761 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1762 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1763 + * GNU General Public License for more details.
1765 + * You should have received a copy of the GNU General Public License
1766 + * along with this program; if not, write to the Free Software
1767 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1769 + * Copyright (C) IBM Corporation, 2004
1771 + * Author: Max Asböck <amax@us.ibm.com>
1775 +#include "ibmasm.h"
1776 +#include "dot_command.h"
1779 + * Reverse Heartbeat, i.e. heartbeats sent from the driver to the
1780 + * service processor.
1781 + * These heartbeats are initiated by user level programs.
1784 +/* the reverse heartbeat dot command */
1786 + struct dot_command_header header;
1787 + unsigned char command[3];
1791 + .command_size = 3,
1795 + .command = { 4, 3, 6 }
1798 +void ibmasm_init_reverse_heartbeat(struct service_processor *sp, struct reverse_heartbeat *rhb)
1800 + init_waitqueue_head(&rhb->wait);
1805 + * start_reverse_heartbeat
1806 + * Loop forever, sending a reverse heartbeat dot command to the service
1807 + * processor, then sleeping. The loop comes to an end if the service
1808 + * processor fails to respond 3 times or we were interrupted.
1810 +int ibmasm_start_reverse_heartbeat(struct service_processor *sp, struct reverse_heartbeat *rhb)
1812 + struct command *cmd;
1813 + int times_failed = 0;
1815 + cmd = ibmasm_new_command(sizeof rhb_dot_cmd);
1819 + while ( times_failed < 3 && !rhb->stopped ) {
1820 + memcpy(cmd->buffer, (void *)&rhb_dot_cmd, sizeof rhb_dot_cmd);
1821 + cmd->status = IBMASM_CMD_PENDING;
1822 + ibmasm_exec_command(sp, cmd);
1823 + ibmasm_wait_for_response(cmd, IBMASM_CMD_TIMEOUT_NORMAL);
1825 + if (cmd->status != IBMASM_CMD_COMPLETE)
1828 + wait_event_interruptible_timeout(rhb->wait,
1830 + REVERSE_HEARTBEAT_TIMEOUT * HZ);
1831 + if (signal_pending(current)) {
1843 +void ibmasm_stop_reverse_heartbeat(struct reverse_heartbeat *rhb)
1846 + wake_up_interruptible(&rhb->wait);
1848 diff -urN linux-2.6.1/drivers/misc/ibmasm/uart.c linux-2.6.1-ibmasm/drivers/misc/ibmasm/uart.c
1849 --- linux-2.6.1/drivers/misc/ibmasm/uart.c 1969-12-31 16:00:00.000000000 -0800
1850 +++ linux-2.6.1-ibmasm/drivers/misc/ibmasm/uart.c 2004-01-19 14:02:56.000000000 -0800
1854 + * IBM ASM Service Processor Device Driver
1856 + * This program is free software; you can redistribute it and/or modify
1857 + * it under the terms of the GNU General Public License as published by
1858 + * the Free Software Foundation; either version 2 of the License, or
1859 + * (at your option) any later version.
1861 + * This program is distributed in the hope that it will be useful,
1862 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1863 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1864 + * GNU General Public License for more details.
1866 + * You should have received a copy of the GNU General Public License
1867 + * along with this program; if not, write to the Free Software
1868 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1870 + * Copyright (C) IBM Corporation, 2004
1872 + * Author: Max Asböck <amax@us.ibm.com>
1876 +#include <linux/termios.h>
1877 +#include <linux/tty.h>
1878 +#include <linux/serial_core.h>
1879 +#include <linux/serial.h>
1880 +#include <linux/serial_reg.h>
1881 +#include "ibmasm.h"
1882 +#include "lowlevel.h"
1885 +void ibmasm_register_uart(struct service_processor *sp)
1887 + struct serial_struct serial;
1888 + unsigned char *iomem_base;
1890 + iomem_base = sp->base_address + SCOUT_COM_B_BASE;
1892 + /* read the uart scratch register to determine if the UART
1893 + * is dedicated to the service processor or if the OS can use it
1895 + if ( 0 == readl(iomem_base + UART_SCR) ) {
1896 + dev_info(sp->dev, "IBM SP UART not registered, owned by service processor\n");
1897 + sp->serial_line = -1;
1901 + memset(&serial, 0, sizeof(serial));
1902 + serial.irq = sp->irq;
1903 + serial.baud_base = 3686400 / 16;
1904 + serial.flags = UPF_AUTOPROBE | UPF_SHARE_IRQ;
1905 + serial.io_type = UPIO_MEM;
1906 + serial.iomem_base = iomem_base;
1908 + sp->serial_line = register_serial(&serial);
1909 + if (sp->serial_line < 0) {
1910 + dev_err(sp->dev, "Failed to register serial port\n");
1913 + enable_uart_interrupts(sp->base_address);
1916 +void ibmasm_unregister_uart(struct service_processor *sp)
1918 + if (sp->serial_line < 0)
1921 + disable_uart_interrupts(sp->base_address);
1922 + unregister_serial(sp->serial_line);
1924 diff -urN linux-2.6.1/drivers/misc/Kconfig linux-2.6.1-ibmasm/drivers/misc/Kconfig
1925 --- linux-2.6.1/drivers/misc/Kconfig 2004-01-08 22:59:18.000000000 -0800
1926 +++ linux-2.6.1-ibmasm/drivers/misc/Kconfig 2004-01-15 10:00:13.000000000 -0800
1932 + tristate "Device driver for IBM RSA service processor"
1935 + This option enables device driver support for in-band access to the
1936 + IBM RSA (Condor) service processor in eServer xSeries systems.
1937 + The ibmasm device driver allows user space application to access
1938 + ASM (Advanced Systems Management) functions on the service
1939 + processor. The driver is meant to be used in conjunction with
1941 + The ibmasm driver also enables the OS to use the UART on the
1942 + service processor board as a regular serial port.
1949 diff -urN linux-2.6.1/drivers/misc/Makefile linux-2.6.1-ibmasm/drivers/misc/Makefile
1950 --- linux-2.6.1/drivers/misc/Makefile 2004-01-08 23:00:03.000000000 -0800
1951 +++ linux-2.6.1-ibmasm/drivers/misc/Makefile 2004-01-14 17:15:39.000000000 -0800
1954 # Makefile for misc devices that really don't fit anywhere else.
1956 -obj- := misc.o # Dummy rule to force built-in.o to be made
1957 +obj- := misc.o # Dummy rule to force built-in.o to be made
1959 +obj-$(CONFIG_IBM_ASM) += ibmasm/