Subject: [patch 04/16] axon driver, simple callback implementation Description: This patch provides a mechanism for modules such as APNET to recieve interrupt notification. Signed-off-by: H Brett Bolen (hbbolen@us.ibm.com) Signed-off-by: Murali Iyer (mniyer@us.ibm.com) Signed-off-by: Tim Schimke (tschimke@us.ibm.com) Signed-off-by: Jesse Arroyo (arroyoj@us.ibm.com) Index: linux-2.6.23.1/drivers/misc/triblade/axon_callback.c =================================================================== --- /dev/null +++ linux-2.6.23.1/drivers/misc/triblade/axon_callback.c @@ -0,0 +1,337 @@ +/** + * axon_callbacks - provides user and driver callbacks + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (C) IBM Corporation, 2008 + * + * Authors: H Brett Bolen , + * Tim Schimke , + * Jesse Arroyo , + * Murali N Iyer + * + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "axon.h" +#include "axon_callback.h" + +extern int num_axons_found; + +/** + * get_priv + */ +static struct axon *get_axon_priv( int msg_type, int dev_num, int *error) +{ + struct axon *axon_priv = NULL; + *error = 0; + + /* check for valid instance & type */ + if (( dev_num < 0 ) || (dev_num >= num_axons_found)) { + printk(KERN_ERR "axon: invalid dev_num %d\n", dev_num); + *error = -1; + return axon_priv; + } + if (( msg_type < 0 ) || (msg_type >= AXON_NUM_CALLBACKS)) { + printk(KERN_ERR "axon: invalid msg_type %d\n", msg_type); + *error = -2; + return axon_priv; + } + + /* make sure it is valid */ + axon_priv = &(axon_device_table[dev_num]); + if ( axon_priv == NULL) { + printk(KERN_ERR "axon: invalid instance struct\n"); + *error = -3; + return axon_priv; + } + + return axon_priv; +} + +/** + * axon_send_remote_enable - notify remote driver that message type + * has been enabled + * @axon_priv - instance structure + * @msg_type - type of msg interrupt + */ +void axon_send_remote_enable(struct axon *axon_priv, int msg_type) +{ + unsigned mask; + + /* adjust scratchpad to enable interrupt */ + mask = SPREG_RD( axon_priv->scratchpad, local_sp.int_disable); + mask &= ~(1<scratchpad, mask, local_sp.int_disable); + +} + +/** + * axon_send_remote_disable + * notify remote driver that message type has been disabled + * @axon_priv - instance structure + * @msg_type - type of msg interrupt + */ +void axon_send_remote_disable(struct axon *axon_priv, int msg_type) +{ + unsigned int mask; + + /* adjust scratchpad to disable interrupt */ + mask = SPREG_RD( axon_priv->scratchpad, local_sp.int_disable); + mask |= (1<scratchpad, mask, local_sp.int_disable); + + +} +/** + * axon_register_notify_callback - register callback for msg type + * @type - type of callback ( enum message_type) + * @dev_num - device number + * @cb_data - data for callback + * @cb_func - function to call + * + */ +int axon_register_notify_callback( enum message_type type, + int dev_num, + void *cb_data, + axon_callback cb_func) +{ + int msg_type = (int) type; + struct axon *axon_priv; + int error; + + axon_priv = get_axon_priv( msg_type, dev_num, &error); + if ( axon_priv == NULL) { + printk(KERN_ERR "reg callback failed %d\n", error); + return error; + } + + /* check for existing callback*/ + if ( axon_priv->callbacks[msg_type].func != NULL) { + printk(KERN_ERR "axon: callback of type %d exists\n", msg_type); + return -4; + } + + /* apply */ + axon_priv->callbacks[msg_type].func = cb_func; + axon_priv->callbacks[msg_type].data = cb_data; + axon_priv->callbacks[msg_type].enabled = 1; + + axon_send_remote_enable(axon_priv, msg_type); + + return 0; +} +EXPORT_SYMBOL_GPL( axon_register_notify_callback); + + +/** + * axon_unregister_notify_callback + */ +void axon_unregister_notify_callback( enum message_type type, + int dev_num) +{ + int msg_type = (int) type; + struct axon *axon_priv; + int error; + + axon_priv = get_axon_priv( msg_type, dev_num, &error); + if ( axon_priv == NULL) { + printk(KERN_ERR "reg callback failed %d\n", error); + return; + } + + /* apply */ + axon_priv->callbacks[msg_type].func = NULL; + axon_priv->callbacks[msg_type].data = NULL; + axon_priv->callbacks[msg_type].enabled = 0; + + axon_send_remote_disable(axon_priv, msg_type); + + return; +} +EXPORT_SYMBOL_GPL( axon_unregister_notify_callback); + +/** + * axon_enable_notify_callback( int dev_num, + */ +void axon_enable_notify_callback(enum message_type type, + int dev_num) +{ + int msg_type = (int) type; + struct axon *axon_priv; + int error; + + axon_priv = get_axon_priv( msg_type, dev_num, &error); + if ( axon_priv == NULL) { + printk(KERN_ERR "enable_notify_callback failed %d\n", error); + return; + } + + /* apply, callback must be registered first */ + if (axon_priv->callbacks[msg_type].func != NULL) { + axon_priv->callbacks[msg_type].enabled = 1; + axon_send_remote_enable(axon_priv, msg_type); + } + return; +} +EXPORT_SYMBOL_GPL( axon_enable_notify_callback); + +/** + * axon_disable_notify_callback - disable notification + */ +void axon_disable_notify_callback(enum message_type type, + int dev_num) +{ + int msg_type = (int) type; + struct axon *axon_priv; + int error; + + axon_priv = get_axon_priv( msg_type, dev_num, &error); + if ( axon_priv == NULL) { + printk(KERN_ERR "axon_disable_notify_callback failed %d\n", + error); + return; + } + + /* apply */ + axon_priv->callbacks[msg_type].enabled = 0; + axon_send_remote_disable(axon_priv, msg_type); + + return; +} +EXPORT_SYMBOL_GPL( axon_disable_notify_callback); + +/** + * axon_send_remote_notification - notify other side + * @type: msg type + * @dev_num: device number + */ +void axon_send_remote_notification( enum message_type type, + int dev_num) +{ + int msg_type = (int) type; + struct axon *axon_priv; + int error; + unsigned int mask; + + axon_priv = get_axon_priv( msg_type, dev_num, &error); + if ( axon_priv == NULL) { + printk(KERN_ERR "remote notification failed %d\n", error); + return; + } + + /* for remote notification, msg_type must be in range 0-7 */ + if ((msg_type < 0 ) || (msg_type >= AXON_MAX_HDW_MSGTYPE)) { + error = -4; + printk(KERN_ERR "remote notification failed %d\n", error); + return; + } + + /* check scratchpad to see if int is disabled */ + mask = SPREG_RD_REMOTE( axon_priv->scratchpad, + remote_sp.int_disable); + if ( mask & ( 1<= AXON_NUM_CALLBACKS)) { + printk(KERN_ERR "Invalid callback type=%d\n", cb_type); + return; + } + + cb = &axon_priv->callbacks[cb_type]; + + if (cb->enabled && cb->func) { + (cb->func) ( cb_type, + cb->data); + } + } +} + +/** + * axon_d2d_callback - process d2d queue + * @type: msg type + * @data: msg data + */ +int axon_d2d_callback(int type, void *data) +{ + struct d2d_message msg; + struct axon *axon_priv = (struct axon *) data; + + BUG_ON( axon_priv == NULL); + + /* drain the d2d message buffer */ + while (axon_receive_d2d_msg(axon_priv, &msg) == 0) { + switch (msg.cmd) { + case D2D_MSG_DIAGS: + pr_info("Diags D2D msg -- 0x%x 0x%x 0x%x 0x%x \n", + msg.data[0], msg.data[1], msg.data[2], + msg.data[3]); + break; + + case D2D_MSG_ENABLE: + if ((msg.data[0] >= 0) && + (msg.data[0] < AXON_MAX_HDW_MSGTYPE)) + axon_priv->callbacks[msg.data[0]]. + remote_enabled = 1; + break; + case D2D_MSG_DISABLE: + if ((msg.data[0] >= 0) && + (msg.data[0] < AXON_MAX_HDW_MSGTYPE)) + axon_priv->callbacks[msg.data[0]]. + remote_enabled = 0; + break; + default: + printk(KERN_WARNING "received d2d msg with unrecognized" + " cmd= 0x%x\n", msg.cmd); + } + } + + return 0; +} Index: linux-2.6.23.1/drivers/misc/triblade/axon_callback.h =================================================================== --- /dev/null +++ linux-2.6.23.1/drivers/misc/triblade/axon_callback.h @@ -0,0 +1,57 @@ +/** + * axon_callbacks - provides user and driver callbacks + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (C) IBM Corporation, 2008 + * + * Authors: H Brett Bolen , + * Tim Schimke , + * Jesse Arroyo , + * Murali N Iyer + * + */ + + +#ifndef __AXON_CALLBACK_H__ +#define __AXON_CALLBACK_H__ + +#include + +#define AXON_MAX_HDW_MSGTYPE 8 +struct axon; + + +struct axon_callback_item { + axon_callback func; + void *data; + int enabled; + int remote_enabled; +}; + + +void axon_do_callback( int cmd, void *priv, + int data1, int data2, + char *aux); + +void axon_send_remote_enable(struct axon *axon_priv, + int msg_type); + +void axon_send_remote_disable(struct axon *axon_priv, + int msg_type); + +int axon_d2d_callback(int type, void *data); + +#endif /* _AXON_CALLBACK_H__ */ Index: linux-2.6.23.1/drivers/misc/triblade/axon_task.h =================================================================== --- /dev/null +++ linux-2.6.23.1/drivers/misc/triblade/axon_task.h @@ -0,0 +1,89 @@ +/** + * axon_taskqueue - handles queue of axon tasks + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (C) IBM Corporation, 2008 + * + * Authors: H Brett Bolen , + * Tim Schimke , + * Jesse Arroyo , + * Murali N Iyer + * + */ + + +#ifndef __AXON_TASK_H__ +#define __AXON_TASK_H__ + +#include "axon.h" + +/** + * struct AXON_TASK_TYPE - task types + */ +enum axon_task_type { + TQ_INIT = 1, + TQ_DIAGS = 2, + TQ_IRQ = 3, + TQ_LAST, +}; + + +/** + * struct AXON_TQ_TASK - work queue item + */ +struct AXON_TQ_TASK { + enum axon_task_type cmd; + void *axon_priv; + int data[4]; + char aux[16]; +}; + +#define TQ_TASK_QUEUE_SZ 16 + +/** + * struct AXON_TASKQUEUE_TYPE - queue of work items + * + * The write index may be updated in interrupt + * context. + * + */ +struct AXON_TASKQUEUE_TYPE { + int status; + struct AXON_TQ_TASK items[TQ_TASK_QUEUE_SZ]; + int size; + int read; + int write; + int num_requests; + int num_responses; + int num_errors; +}; + +/** + * axon_add_task - puts a task on the work queue + * @cmd - command to queue + * @data1 - cmd data + * @data2 - cmd data + * @aux - cmd string + * + */ +void axon_add_task( int cmd, + void *axon_priv, + int data1, + int data2, + char *aux); + +#endif /* __AXON_TASK_H__ */ + --