Subject: [patch 12/16] axon driver, general utility functions Description: This patch provides driver utilities ( such as inter-driver communcation via the d2d msg queue) and diagnostics. 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_diags.c =================================================================== --- /dev/null +++ linux-2.6.23.1/drivers/misc/triblade/axon_diags.c @@ -0,0 +1,453 @@ +/** + * axon_diags - diagnostics + * + * 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 + * + */ + +#undef DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + + +#include + +#include "axon.h" +#include "axon_hw.h" + + + + + +/** + * eatcr - return first line of the str, without carriage return + * @str: axon_priv: instance data + */ +static char *eatcr( const char *str) +{ + static char s[80]; + int i; + snprintf(s, 80, "%s", str); + s[79] = 0; + for( i = 0; i < strlen(s); i++) { + if (s[i] == '\n') { + s[i] = 0; + return s; + } + } + return s; +} + +/** + * axon_hexdump32 + * @banner: text to print as a banner + * @ptr: pointer to data + * @count: number of bytes to print + */ +void axon_hexdump32( char *banner, + u32 *ptr, + int count) +{ + int i, j; + pr_debug( "-- %s -- %d bytes\n", eatcr(banner), count); + + for ( i = 0; i < count; i += 4) { + pr_debug( " 0x%04x: ", i); + for ( j = 0; j < 4; j++) { + if ( i+j < count ) { + pr_debug( " %08x", ptr[i+j]); + } + + } + pr_debug( "\n"); + } +} + +/** + * axon_diags_print_image + * @banner: text to print as a banner + * @addr: pointer to data + * @len: number of bytes to print + */ +void axon_diags_print_image( char *banner, void *addr, int len) +{ + int i; + int start; + unsigned char *byte_addr = (unsigned char *) addr; + pr_debug( "--- image dump of '%s' %d bytes @ %p --\n", + eatcr(banner), len, addr); + + for ( start = 0; start < len; start += 8) { + pr_debug( " 0x%04x: ", start); + for ( i = 0; i < 8; i++) { + pr_debug( " %02x", readb( byte_addr + start + i)); + } + pr_debug( "\n"); + } +} + +#ifndef CONFIG_TB_AXON_PCI +/** + * get_pcie_dcr - read & return the DCR register specified + * @axon_priv:- instance data + * @reg:- register to read + */ +static inline u32 get_pcie_dcr(struct axon *axon_priv, int reg) +{ + return dcr_read(axon_priv->dcrreg_host, axon_priv->dcrreg_base + reg); +} +#endif + +/** + * axon_diags_dump_scratchpad - print first few bytes of scratchpad + * @axon_priv: instance data + * @banner: banner to print + */ +void axon_diags_dump_scratchpad ( struct axon *axon_priv, char *banner) +{ + int i; + int start; + struct scratchpad_struct *sp = axon_priv->scratchpad; + + pr_debug( "axon_priv @ %p ---- '%s' \n", axon_priv, eatcr(banner)); + pr_debug( " axon_priv->mmio_base @ %p\n", + axon_priv->mmio_base); + pr_debug( " axon_priv->scratchpad @ %p \n", sp); + + for ( start = 0; start < 128; start += 8) { + char out[180] = {0}; + int out_len = 0; + + out_len += sprintf( &out[out_len], " 0x%04x: ", start); + for ( i = 0; i < 8; i++) { + out_len += sprintf( &out[out_len], " %02x", + readb( start + i + (char *) sp)); + } + pr_debug("%s\n", out); + } + + pr_debug( ".\n"); + pr_debug( "local sma: %d bytes @ 0x %08x %08x\n", + axon_priv->scratchpad->local_sp.sma_size, + axon_priv->scratchpad->local_sp.sma_phys_hi, + axon_priv->scratchpad->local_sp.sma_phys_lo); + + pr_debug( "remote sma: %d bytes @ 0x %08x %08x\n", + SPREG_RD_REMOTE(sp, remote_sp.sma_size), + SPREG_RD_REMOTE(sp, remote_sp.sma_phys_hi), + SPREG_RD_REMOTE(sp, remote_sp.sma_phys_lo)); + + pr_debug( "local d2d: %d bytes @ 0x %08x %08x\n", + axon_priv->scratchpad->local_sp.d2d_size, + axon_priv->scratchpad->local_sp.d2d_phys_hi, + axon_priv->scratchpad->local_sp.d2d_phys_lo); + + pr_debug( "remote d2d: %d bytes @ 0x %08x %08x\n", + SPREG_RD_REMOTE(sp, remote_sp.d2d_size), + SPREG_RD_REMOTE(sp, remote_sp.d2d_phys_hi), + SPREG_RD_REMOTE(sp, remote_sp.d2d_phys_lo)); + + pr_debug( "local interrupt disable: 0x%x\n", + SPREG_RD(sp, local_sp.int_disable)); + + pr_debug( "remote interrupt disable: 0x%x\n", + SPREG_RD_REMOTE(sp, remote_sp.int_disable)); + + pr_debug( "local.cmd_seqno = 0x%08x\n", + SPREG_RD(sp, local_sp.cmd_seqno) ); + pr_debug( "local.cmd_ack = 0x%08x\n", SPREG_RD(sp, local_sp.cmd_ack) ); + pr_debug( "local.cmd = 0x%08x\n", SPREG_RD(sp, local_sp.cmd) ); + pr_debug( "local.subcmd = 0x%08x\n", SPREG_RD(sp, local_sp.subcmd) ); + for (i = 0; i < 4; i++) { + pr_debug( "local.params[%01d] = 0x%08x\n", i, + SPREG_RD(sp, local_sp.params[i]) ); + } + pr_debug( "remote.cmd_seqno = 0x%08x\n", + SPREG_RD_REMOTE(sp, remote_sp.cmd_seqno) ); + pr_debug( "remote.cmd_ack = 0x%08x\n", + SPREG_RD_REMOTE(sp, remote_sp.cmd_ack) ); + pr_debug( "remote.cmd = 0x%08x\n", SPREG_RD_REMOTE(sp, remote_sp.cmd) ); + pr_debug( "remote.subcmd = 0x%08x\n", + SPREG_RD_REMOTE(sp, remote_sp.subcmd) ); + + pr_debug( "remote.int_disable = 0x%08x\n", + SPREG_RD_REMOTE(sp, remote_sp.int_disable) ); + pr_debug( "remote.d2d_size = 0x%08x\n", + SPREG_RD_REMOTE(sp, remote_sp.d2d_size) ); + pr_debug( "remote.d2d_phys_hi = 0x%08x\n", + SPREG_RD_REMOTE(sp, remote_sp.d2d_phys_hi) ); + pr_debug( "remote.d2d_phys_lo = 0x%08x\n", + SPREG_RD_REMOTE(sp, remote_sp.d2d_phys_lo) ); + pr_debug( "remote.sma_size = 0x%08x\n", + SPREG_RD_REMOTE(sp, remote_sp.sma_size) ); + pr_debug( "remote.sma_phys_hi = 0x%08x\n", + SPREG_RD_REMOTE(sp, remote_sp.sma_phys_hi) ); + pr_debug( "remote.sma_phys_lo = 0x%08x\n", + SPREG_RD_REMOTE(sp, remote_sp.sma_phys_lo) ); + + for (i = 0; i < 4; i++) { + pr_debug( "remote.params[%01d] = 0x%08x\n", + i, SPREG_RD_REMOTE(sp, remote_sp.params[i]) ); + } + pr_debug( "\n"); + +/* for debug */ +#ifndef CONFIG_TB_AXON_PCI + pr_debug( "POM0 upper = 0x%08x\n", + ioread32be(axon_priv->pciecnfg_base_addr + PCIE_CFG_POM0H) ); + pr_debug( "POM0 lower = 0x%08x\n", + ioread32be(axon_priv->pciecnfg_base_addr + PCIE_CFG_POM0L) ); + pr_debug( "POM1 upper = 0x%08x\n", + ioread32be(axon_priv->pciecnfg_base_addr + PCIE_CFG_POM1H) ); + pr_debug( "POM1 lower = 0x%08x\n", + ioread32be(axon_priv->pciecnfg_base_addr + PCIE_CFG_POM1L) ); + pr_debug( "POM2 upper = 0x%08x\n", + ioread32be(axon_priv->pciecnfg_base_addr + PCIE_CFG_POM2H) ); + pr_debug( "POM2 lower = 0x%08x\n", + ioread32be(axon_priv->pciecnfg_base_addr + PCIE_CFG_POM2L) ); + pr_debug( "\n"); + + pr_debug( "MEM0 base upper = 0x%08x\n", + get_pcie_dcr(axon_priv, DCR_MEM0_BASE_UPPER)); + pr_debug( "MEM0 base lower = 0x%08x\n", + get_pcie_dcr(axon_priv, DCR_MEM0_BASE_LOWER)); + pr_debug( "MEM0 mask upper = 0x%08x\n", + get_pcie_dcr(axon_priv, DCR_MEM0_MASK_UPPER)); + pr_debug( "MEM0 mask lower = 0x%08x\n", + get_pcie_dcr(axon_priv, DCR_MEM0_MASK_LOWER)); + pr_debug( "\n"); + + pr_debug( "MEM1 base upper = 0x%08x\n", + get_pcie_dcr(axon_priv, DCR_MEM1_BASE_UPPER)); + pr_debug( "MEM1 base lower = 0x%08x\n", + get_pcie_dcr(axon_priv, DCR_MEM1_BASE_LOWER)); + pr_debug( "MEM1 mask upper = 0x%08x\n", + get_pcie_dcr(axon_priv, DCR_MEM1_MASK_UPPER)); + pr_debug( "MEM1 mask lower = 0x%08x\n", + get_pcie_dcr(axon_priv, DCR_MEM1_MASK_LOWER)); + pr_debug( "\n"); + + pr_debug( "MEM2 base upper = 0x%08x\n", + get_pcie_dcr(axon_priv, DCR_MEM2_BASE_UPPER)); + pr_debug( "MEM2 base lower = 0x%08x\n", + get_pcie_dcr(axon_priv, DCR_MEM2_BASE_LOWER)); + pr_debug( "MEM2 mask upper = 0x%08x\n", + get_pcie_dcr(axon_priv, DCR_MEM2_MASK_UPPER)); + pr_debug( "MEM2 mask lower = 0x%08x\n", + get_pcie_dcr(axon_priv, DCR_MEM2_MASK_LOWER)); + pr_debug( "\n"); + + pr_debug( "PIM0 upper = 0x%08x\n", + ioread32be(axon_priv->pciecnfg_base_addr + PCIE_CFG_PIM0H) ); + pr_debug( "PIM0 lower = 0x%08x\n", + ioread32be(axon_priv->pciecnfg_base_addr + PCIE_CFG_PIM0L) ); + pr_debug( "PIM1 upper = 0x%08x\n", + ioread32be(axon_priv->pciecnfg_base_addr + PCIE_CFG_PIM1H) ); + pr_debug( "PIM1 lower = 0x%08x\n", + ioread32be(axon_priv->pciecnfg_base_addr + PCIE_CFG_PIM1L) ); + pr_debug( "SIZE01 upper = 0x%08x\n", + ioread32be(axon_priv->pciecnfg_base_addr + PCIE_CFG_PIM01SH) ); + pr_debug( "SIZE01 lower = 0x%08x\n", + ioread32be(axon_priv->pciecnfg_base_addr + PCIE_CFG_PIM01SL) ); + pr_debug( "\n"); + + pr_debug( "PIM2 upper = 0x%08x\n", + ioread32be(axon_priv->pciecnfg_base_addr + PCIE_CFG_PIM2H) ); + if (0) { + pr_debug( "Endian debug byte 0 = 0x%02x, byte 3 = 0x%02x\n", + ioread8(axon_priv->pciecnfg_base_addr + PCIE_CFG_PIM2H), + ioread8(axon_priv->pciecnfg_base_addr + PCIE_CFG_PIM2H+3)); + } + pr_debug( "PIM2 lower = 0x%08x\n", + ioread32be(axon_priv->pciecnfg_base_addr + PCIE_CFG_PIM2L) ); + pr_debug( "PIM6 upper = 0x%08x\n", + ioread32be(axon_priv->pciecnfg_base_addr + PCIE_CFG_PIM6H) ); + pr_debug( "PIM6 lower = 0x%08x\n", + ioread32be(axon_priv->pciecnfg_base_addr + PCIE_CFG_PIM6L) ); + pr_debug( "SIZE26 = 0x%08x\n", + ioread32be(axon_priv->pciecnfg_base_addr + PCIE_CFG_PIM26S) ); + pr_debug( "\n"); + + pr_debug( "PIM3 upper = 0x%08x\n", + ioread32be(axon_priv->pciecnfg_base_addr + PCIE_CFG_PIM3H) ); + pr_debug( "PIM3 lower = 0x%08x\n", + ioread32be(axon_priv->pciecnfg_base_addr + PCIE_CFG_PIM3L) ); + pr_debug( "PIM4 upper = 0x%08x\n", + ioread32be(axon_priv->pciecnfg_base_addr + PCIE_CFG_PIM4H) ); + pr_debug( "PIM4 lower = 0x%08x\n", + ioread32be(axon_priv->pciecnfg_base_addr + PCIE_CFG_PIM4L) ); + pr_debug( "SIZE34 upper = 0x%08x\n", + ioread32be(axon_priv->pciecnfg_base_addr + PCIE_CFG_PIM34SH) ); + pr_debug( "SIZE34 lower = 0x%08x\n", + ioread32be(axon_priv->pciecnfg_base_addr + PCIE_CFG_PIM34SL) ); + pr_debug( "\n"); + + pr_debug( "MSI capability reg = 0x%08x\n", + ioread32be(axon_priv->pciecnfg_base_addr + PCIE_CFG_MSICAP) ); + pr_debug( "MSI addr upper = 0x%08x\n", + ioread32be(axon_priv->pciecnfg_base_addr + PCIE_CFG_MSIADDRH) ); + pr_debug( "MSI addr lower = 0x%08x\n", + ioread32be(axon_priv->pciecnfg_base_addr + PCIE_CFG_MSIADDRL) ); + pr_debug( "MSI data = 0x%08x\n", + ioread32be(axon_priv->pciecnfg_base_addr + PCIE_CFG_MSIDATA) ); +#endif +} +/** + * axon_diags_log_d2d - dump start of d2d to log + * @axon_priv: instance data + * @banner: banner to print + */ +void axon_diags_log_d2d( struct axon *priv, char *banner, + int ofs, int len) +{ + int i; + int start; + char s[128]; + unsigned char *addr = (unsigned char *) priv->local_d2d; + pr_info( "--- image dump of '%s' %d bytes @ %p --\n", + eatcr(banner), len, addr); + + for ( start = ofs; start < len + ofs; start += 8) { + int si = 0; + si += snprintf(s, sizeof(s) - si, " 0x%04x: ", start); + for ( i = 0; i < 8; i++) { + si += snprintf( s+si, sizeof(s) - si, + " %02x", readb( addr + start + i)); + } + pr_info("%s\n", s); + } +} + + +/** + * axon_diags_log_d2d - dump start of d2d to log + * @axon_priv: instance data + * @banner: banner to print + */ +extern void axon_diags_log_image( void *ptr, const char *banner, + int ofs, int len) +{ + int start; + unsigned char *addr = (unsigned char *) ptr; + pr_info( "--- image dump of '%s' %d bytes @ %p --\n", + eatcr(banner), len, addr); + + for ( start = ofs; start < len + ofs; start += 8) { + int i; + int si; + static char s[128]; + + si = 0; + si += snprintf(s, sizeof(s) - si, " 0x%04x: ", start); + for ( i = 0; i < 8; i++) { + si += snprintf( s+si, sizeof(s) - si, + " %02x", readb( addr + start + i)); + } + + si += snprintf( s+si, sizeof(s) - si," | "); + + for ( i = 0; i < 8; i++) { + char c = readb( addr+start+i); + if (( c >= ' ') && ( c <= 'z')) { + si += snprintf( s+si, sizeof(s) - si,"%c",c); + } else { + si += snprintf( s+si, sizeof(s) - si,"."); + } + } + pr_info("%s\n", s); + } +} + + + +/** + * axon_diags_log_scratchpad - dump scratchpad to log + * @axon_priv: instance data + * @banner: banner to print + */ +void axon_diags_log_scratchpad ( struct axon *axon_priv, char *banner) +{ + int i; + int start; + + struct scratchpad_struct *sp = axon_priv->scratchpad; + pr_info( "axon_priv @ %p ---- '%s' \n", axon_priv, eatcr(banner)); + pr_info( " axon_priv->mmio_base @ %p\n", + axon_priv->mmio_base); + pr_info( " axon_priv->scratchpad @ %p \n", sp); + + for ( start = 0; start < 128; start += 8) { + char out[180] = {0}; + int out_len = 0; + + out_len += sprintf( &out[out_len], " 0x%04x: ", start); + for ( i = 0; i < 8; i++) { + out_len += sprintf( &out[out_len], " %02x", + readb( start + i + (char *) sp)); + } + pr_info("%s\n", out); + } + + pr_info( ".\n"); + pr_info( "local sma: %d bytes @ 0x %08x %08x\n", + axon_priv->scratchpad->local_sp.sma_size, + axon_priv->scratchpad->local_sp.sma_phys_hi, + axon_priv->scratchpad->local_sp.sma_phys_lo); + + pr_info( "remote sma: %d bytes @ 0x %08x %08x\n", + SPREG_RD_REMOTE(sp, remote_sp.sma_size), + SPREG_RD_REMOTE(sp, remote_sp.sma_phys_hi), + SPREG_RD_REMOTE(sp, remote_sp.sma_phys_lo)); + + pr_info( "local d2d: %d bytes @ 0x %08x %08x\n", + axon_priv->scratchpad->local_sp.d2d_size, + axon_priv->scratchpad->local_sp.d2d_phys_hi, + axon_priv->scratchpad->local_sp.d2d_phys_lo); + + pr_info( "remote d2d: %d bytes @ 0x %08x %08x\n", + SPREG_RD_REMOTE(sp, remote_sp.d2d_size), + SPREG_RD_REMOTE(sp, remote_sp.d2d_phys_hi), + SPREG_RD_REMOTE(sp, remote_sp.d2d_phys_lo)); + + pr_info( "local interrupt disable: 0x%x\n", + SPREG_RD(sp, local_sp.int_disable)); + + pr_info( "remote interrupt disable: 0x%x\n", + SPREG_RD_REMOTE(sp, remote_sp.int_disable)); + +} + Index: linux-2.6.23.1/drivers/misc/triblade/axon_diags.h =================================================================== --- /dev/null +++ linux-2.6.23.1/drivers/misc/triblade/axon_diags.h @@ -0,0 +1,42 @@ +/** + * axon_diags - diagnostics + * + * 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 __LINUX_AXON_DIAGS_H__ +#define __LINUX_AXON_DIAGS_H__ + + +extern void axon_diags_print_image( const char *banner, void *addr, int len); +extern void axon_hexdump32( const char *banner, u32 *ptr, int len); +extern void axon_diags_log_scratchpad( struct axon *priv, const char *banner); +extern void axon_diags_dump_scratchpad ( struct axon *priv, const char *banner); +extern void axon_diags_log_d2d( struct axon *priv, const char *banner, + int ofs, int len); +extern void axon_diags_log_image( void *addr, const char *banner, + int ofs, int len); + + +#endif /* __LINUX_AXON_DIAGS_H__ */ + Index: linux-2.6.23.1/drivers/misc/triblade/axon_util.c =================================================================== --- /dev/null +++ linux-2.6.23.1/drivers/misc/triblade/axon_util.c @@ -0,0 +1,359 @@ +/** + * axon_util - provides common functions such as interface initilization + * and communication. + * + * 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 +#include +#include + +#include "axon.h" +#include "axon_callback.h" +#include "axon_util.h" +#include "axon_diags.h" +#include "axon_mr.h" + +extern const char *axon_name; +extern int axon_major; +extern const struct file_operations axon_fops; + + +/* + * dummy callback + */ +int axon_dummy_callback( int type, + void *data) +{ + pr_debug("dummy_callback(%s)\n", (char *) data); + return 0; +} + + +/* + * axon_init_instance + * @axon_priv - device instance + * @dev - device information + */ +void axon_init_instance( struct axon *axon_priv) +{ + int i; + struct axon_dataq *rq; + + /* force to zero */ + axon_priv->irq = 0; + + axon_priv->id = 0x0101; + axon_priv->ver = 0x00010001; + + axon_priv->mmio_base = NULL; + axon_priv->scratchpad = NULL; + + axon_priv->axon_base_paddr = 0; + axon_priv->c3poreg_base_addr = NULL; + + axon_priv->pciereg_base_paddr = 0; + axon_priv->pciereg_size = 0; + axon_priv->pciereg_base_addr = NULL; + axon_priv->pciecnfg_base_addr = NULL; + + axon_priv->msi_addr = 0; + axon_priv->mbxreg_base_addr = NULL; + axon_priv->dma_mask = 0; + + axon_priv->local_phys_plb5_addr = 0; + axon_priv->raw_sma_ptr = NULL; + axon_priv->raw_sma_order = 0; + axon_priv->raw_d2d_ptr = NULL; + axon_priv->raw_d2d_order = 0; + + axon_priv->local_sma_size = 0; + axon_priv->local_sma_address = NULL; + axon_priv->local_sma_dma_handle = 0; + axon_priv->local_sma_plb5_addr = 0; + axon_priv->remote_sma_size = 0; + axon_priv->remote_sma_address = NULL; + axon_priv->remote_sma_paddr = 0; + axon_priv->remote_sma_plb5_addr = 0; + + axon_priv->local_d2d_size = 0; + axon_priv->local_d2d = NULL; + axon_priv->local_d2d_dma_handle = 0; + axon_priv->local_apnet_plb5_addr = 0; + axon_priv->remote_d2d_size = 0; + axon_priv->remote_d2d = NULL; + axon_priv->remote_d2d_paddr = 0; + axon_priv->remote_apnet_plb5_addr = 0; + + mutex_init(&(axon_priv->open_lock)); + atomic_set(&axon_priv->open_count, 0x0); + +#ifdef CONFIG_TB_AXON_MTRR_SMA + axon_priv->mtrr_reg = -1; +#endif + + /* initialize data queue */ + rq = &axon_priv->readq; + rq->buf_sz = AXON_DATAQ_BUFSZ; + rq->read_index = 0; + rq->write_index = 0; + spin_lock_init( &rq->irq_lock); + init_waitqueue_head( &rq->irq_queue); + + /* clear the callback table */ + for ( i = 0; i < AXON_NUM_CALLBACKS; i++) { + axon_priv->callbacks[i].func = NULL; + axon_priv->callbacks[i].data = NULL; + axon_priv->callbacks[i].enabled = 0; + axon_priv->callbacks[i].remote_enabled = 1; + } + + axon_priv->d2d_msg_rhead = offsetof(struct axon_d2d, msg_buffer); + spin_lock_init(&axon_priv->d2d_msg_lock); + axon_initialize_dacs_sysfs(axon_priv); + + /* dummy callbacks for diagnostics */ + if (0) { + static char *d[] = { "cb_0", "cb_1", "cb_2", "cb_3", + "cb_4", "cb_5", "cb_6", "cb_7", + NULL}; + + for ( i = 0; i < AXON_NUM_CALLBACKS; i++) { + axon_register_notify_callback( i, + axon_priv->index, + d[i], + &axon_dummy_callback); + } + } +} + +/** + * axon_setup_cdev + * @axon_priv: device instance + */ +int __devinit axon_setup_cdev( struct axon *axon_priv) +{ + int err; + + axon_priv->dev_id = MKDEV( axon_major, axon_priv->index); + + + cdev_init( &(axon_priv->cdev), &axon_fops); + axon_priv->cdev.owner = THIS_MODULE; + + err = cdev_add( &axon_priv->cdev, axon_priv->dev_id, 1); + if ( err ) { + printk(KERN_ERR "Error %d adding axon%d", + err, axon_priv->index); + } + + return err; +} + +/** + * axon_util_init_local_scratchpad - initialize scratchpad regs for local + * processor + * @axon_priv: device instance + */ +void axon_util_init_local_scratchpad( struct axon *axon_priv) +{ + int i; + + struct scratchpad_struct *sp; + + if ( axon_priv == NULL) + return; + + sp = axon_priv->scratchpad; + if ( sp == NULL) + return; + + pr_debug("initialize local scratchpad at %p\n", + &sp->local_sp); + + /* init local scratchpad to all zero */ + for (i = 2; i < 16; i++) { + SPREG_WRT(sp, 0, local_sp.sp_array[i]); + } + + /* set sequence numbers to null value */ + SPREG_WRT(sp, SP_NULL_VAL, local_sp.cmd_seqno); + SPREG_WRT(sp, SP_NULL_VAL, local_sp.cmd_ack); + +} + +/** + * axon_init_d2d - initialize the driver-to-driver msg queue + * @d2dp: pointer to d2d msg queue + */ +void axon_init_d2d(struct axon_d2d *d2dp) +{ + int i; + d2dp->msg_head = offsetof(struct axon_d2d, msg_buffer); + d2dp->msg_tail = offsetof(struct axon_d2d, msg_buffer); + for (i = 0; i < 4; i++) { + d2dp->dma_interrupt_values[i] = 0; + } + for (i = 0; i < 2; i++) { + d2dp->dma_channel_seq_issued[i] = 0; + d2dp->dma_channel_seq_complete[i] =0; + } +} + +/** + * axon_send_d2d_msg - send driver-to-driver message to remote driver + * rc = 0, msg sent successfully + * rc = -1, remote side not ready + * rc = -2, msg buffer full + * @axon_priv: device instance + * @msgp: d2d msg pointer + */ +int axon_send_d2d_msg(struct axon *axon_priv, struct d2d_message *msgp) +{ + int rc = 0; + u32 next_rhead; + u32 rtail; + u32 rhead; + u32 start_offset; + + if (axon_priv->remote_d2d == NULL) { + pr_debug("remote driver not ready\n"); + return -1; + } + + pr_debug("send d2d msg cmd=0x%x 0x%x 0x%x 0x%x\n", + msgp->cmd, msgp->data[0], msgp->data[1], msgp->data[2]); + start_offset = offsetof(struct axon_d2d, msg_buffer); + + spin_lock(&axon_priv->d2d_msg_lock); + + rhead = axon_priv->d2d_msg_rhead; + next_rhead = rhead + D2D_MESSAGE_SIZE; + if (next_rhead == (start_offset + D2D_MSG_BUF_SIZE)) + next_rhead = start_offset; /* buffefsr wrapped */ + + rtail = axon_arch_get_rtail(axon_priv); + + + if (next_rhead == rtail) { + pr_debug("msg buffer is full, next_head= 0x%x, tail= 0x%x\n", + next_rhead, rtail); + rc = -2; + } else { + + /* store the message in remote d2d */ + axon_arch_put_msg((u8 *)axon_priv->remote_d2d + rhead, + msgp); + + axon_priv->d2d_msg_rhead = next_rhead; + + /* update remote head pointer */ + wmb(); /* msg head pointer barrier */ + axon_arch_put_rhead(axon_priv, next_rhead); + wmb(); /* msg head pointer barrier */ + + /* wake up remote side */ + axon_send_remote_notification(D2D_MSG_TYPE, + axon_priv->index); + + } + + spin_unlock(&axon_priv->d2d_msg_lock); + return rc; +} + +/** + * axon_receive_d2d_msg - receive driver-to-driver message from remote driver + * rc = 0, msg received successfully + * rc = -1, msg buffer empty + * @axon_priv: device instance + * @msgp: d2d msg pointer + */ +int axon_receive_d2d_msg(struct axon *axon_priv, struct d2d_message *msgp) +{ + int rc = 0; + u32 tail; + u32 head; + struct axon_d2d *local_d2d = axon_priv->local_d2d; + u32 msg_buf_offset = offsetof(struct axon_d2d, msg_buffer); + + /* todo - fix the reinit problem */ + + spin_lock(&axon_priv->d2d_msg_lock); + + tail = local_d2d->msg_tail; + head = local_d2d->msg_head; + pr_debug("rcv d2d_msg, head= 0x%x, tail= 0x%x ofs=0x%x\n", + head, + tail, + msg_buf_offset); + + pr_debug(" locald2d = 0x%p to=%x, ho=%x\n", + axon_priv->local_d2d, + local_d2d->msg_tail, + local_d2d->msg_head); + + + if (head == tail) { + pr_debug("msg buffer is empty\n"); + rc = -1; + } else { + /* todo -- the indexing is broken. */ + int idx = (tail - msg_buf_offset) / sizeof( struct d2d_message ); + + pr_info("reading d2d_msg from idx = %d @ %p\n", + idx, &(local_d2d->msg_buffer[idx].cmd)); + + /* read message from buffer */ + msgp->cmd = local_d2d->msg_buffer[idx].cmd; + msgp->data[0] = local_d2d->msg_buffer[idx].data[0]; + msgp->data[1] = local_d2d->msg_buffer[idx].data[1]; + msgp->data[2] = local_d2d->msg_buffer[idx].data[2]; + + pr_info("rcv d2d_msg, msg.cmd= 0x%x, data[0x%x 0x%x 0x%x]\n", + msgp->cmd, msgp->data[0], msgp->data[1], msgp->data[2]); + + tail += D2D_MESSAGE_SIZE; + if (tail == (msg_buf_offset + D2D_MSG_BUF_SIZE)) + tail = msg_buf_offset; /* buffer wrapped */ + /* update tail pointer */ + local_d2d->msg_tail = tail; + } + + spin_unlock(&axon_priv->d2d_msg_lock); + return rc; +} Index: linux-2.6.23.1/drivers/misc/triblade/axon_util.h =================================================================== --- /dev/null +++ linux-2.6.23.1/drivers/misc/triblade/axon_util.h @@ -0,0 +1,57 @@ +/** + * axon_util - provides common functions such as interface initilization + * and communication. + * + * 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 __LINUX_AXON_UTIL_H__ +#define __LINUX_AXON_UTIL_H__ + +struct d2d_message { /* message for d2d communication (16 bytes) */ + u32 cmd; + u32 data[3]; +}; + +/* message size = 16 bytes */ +#define D2D_MESSAGE_SIZE sizeof(struct d2d_message) + +/* D2D message commands */ +#define D2D_MSG_ENABLE 1 /* data[0] has interrupt type */ +#define D2D_MSG_DISABLE 2 /* data[0] has interrupt type */ +#define D2D_MSG_DIAGS 3 /* data[0] has interrupt type */ + +struct axon; +struct axon_d2d; + +/* prototypes */ +int __devinit axon_setup_cdev(struct axon *axon_priv); + +void axon_init_instance( struct axon *axon_priv); +void axon_util_init_local_scratchpad( struct axon *axon_priv); +void axon_init_d2d(struct axon_d2d *d2dp); + +int axon_send_d2d_msg(struct axon *axon_priv, struct d2d_message *msgp); +int axon_receive_d2d_msg(struct axon *axon_priv, struct d2d_message *msgp); + +#endif /* __LINUX_AXON_UTIL_H__ */ --