From: Jean-Christophe DUBOIS This is the main common part of the Axon driver. It is identical either from the PCI-E host or from the Cell(s) attched to the Axon chip. It provides basic services (DMA, MBX, mapping, ...) and allow some upper level drivers to easily share these resources. In the following patches there will be some examples of driver implementation like Ethernet over PCI-E, user space DMA, ... Some other drivers will be provided later like a block driver to handle the DDR (for swap purpose or fast ramdisk) or a verb layer to use the DMA. Signed-off-by: Jean-Christophe DUBOIS --- Index: linux/drivers/axon/common/axon_class.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/drivers/axon/common/axon_class.c 2006-12-19 17:53:10.000000000 +0100 @@ -0,0 +1,111 @@ +/****************************************************************** + * Copyright (C) 2006 Mercury Computer Systems, Inc. + * 199 Riverneck Road + * Chelmsford, MA 01824-2820 + * (978) 256-1300 + * webinfo@mc.com + * + * 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, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * http://www.gnu.org/copyleft/gpl.html + ******************************************************************/ + + +#include +#include +#include +#include + +#include + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) + +static struct class *axon_class = NULL; + +int +axon_create_class() +{ + if (axon_class == NULL) { + axon_class = class_create(THIS_MODULE, "axon"); + + if (axon_class != NULL) + return 0; + else + return -1; + } else { + return 1; + } + +} + +int +axon_destroy_class() +{ + if (axon_class != NULL) { + class_destroy(axon_class); + axon_class = NULL; + } + + return 0; +} + +void * +axon_get_class() +{ + return axon_class; +} + +#else + +static struct class_simple *axon_class = NULL; + +int +axon_create_class() +{ + if (axon_class == NULL) { + axon_class = class_simple_create(THIS_MODULE, "axon"); + + if (axon_class != NULL) + return 0; + else + return -1; + } else { + return 1; + } + +} + +int +axon_destroy_class() +{ + if (axon_class != NULL) { + class_simple_destroy(axon_class); + axon_class = NULL; + } + + return 0; +} + +void * +axon_get_class() +{ + return axon_class; +} + +#endif + +EXPORT_SYMBOL(axon_create_class); +EXPORT_SYMBOL(axon_destroy_class); +EXPORT_SYMBOL(axon_get_class); Index: linux/drivers/axon/common/axon_dma_ops_dma_aux.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/drivers/axon/common/axon_dma_ops_dma_aux.c 2006-12-19 17:53:10.000000000 +0100 @@ -0,0 +1,533 @@ +/****************************************************************** + * Copyright (C) 2006 Mercury Computer Systems, Inc. + * 199 Riverneck Road + * Chelmsford, MA 01824-2820 + * (978) 256-1300 + * webinfo@mc.com + * + * 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, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * http://www.gnu.org/copyleft/gpl.html + ******************************************************************/ + + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +static int axon_use_aux_dma = 1; + +module_param(axon_use_aux_dma, int, 0644); +MODULE_PARM_DESC(axon_use_aux_dma, + "This allows to define if the driver should try to use the Aux DMA if present. By default it will try to discover and use it but you can request to skip it by setting this parameter to 0"); + +static int axon_aux_dma_is_broken = 1; + +module_param(axon_aux_dma_is_broken, int, 0644); +MODULE_PARM_DESC(axon_aux_dma_is_broken, + "On FCAB the AuxDMA is broken and can't cross 256 bytes bondaries without corrupting data. If you know your AuxDMA is not broken you can set this parameter to 0"); + +static int axon_aux_dma_use_ben_bit = 1; + +module_param(axon_aux_dma_use_ben_bit, int, 0644); +MODULE_PARM_DESC(axon_aux_dma_use_ben_bit, + "Should we use the BEN bit on the DMA engine (required on FCAB)"); + +static void +link(struct axon_dma_ops_t *dma_ops, + struct axon_dma_pkt_t *p_dma_pkt_prev, + struct axon_dma_pkt_t *p_dma_pkt) +{ + struct axon_dma_ops_dma_aux_t *p_dma_ops_dma_aux = + dma_ops->context; + + u32 count; + + u8 *dma_pkt = (u8 *) p_dma_pkt_prev->addr; + + + (void) p_dma_ops_dma_aux; + + + dbg_log("\t Linking 0x%p to previous 0x%p \n", p_dma_pkt->addr, + p_dma_pkt_prev->addr); + + axon_writel(BE_HI32_FROM_BE64(p_dma_pkt->plb_bus_addr), + dma_pkt + AuxDMA_SGHn); + axon_writel(BE_LO32_FROM_BE64(p_dma_pkt->plb_bus_addr), + dma_pkt + AuxDMA_SGLn); + + + count = axon_readl(dma_pkt + DMAx_CTCn); + count = be32_set_bit(count, DMAx_CTCn_LK); + + + axon_writel(count, dma_pkt + DMAx_CTCn); +} + +static u32 +is_eib_address(u64 addr) +{ + return (addr & AXON_PLB_XDR_CHAN0_MASK) == + AXON_PLB_XDR_CHAN0_OFFSET ? 1 : 0; +} + +static u32 +compute_max_size(u64 addr, u32 max_size) +{ + if (axon_aux_dma_is_broken && axon_aux_dma_use_ben_bit) { + + if (is_eib_address(addr)) + max_size = + MIN(max_size, 256 - ((addr + 256) % 256)); + } + + return max_size; +} + +static u32 +max_packet_size(struct axon_dma_cmd_t *p_dma_cmd, + axon_dma_xfer_width width) +{ + u32 max_size = + MIN(p_dma_cmd->byte_count, 1024 << width); + + max_size = MIN(compute_max_size(p_dma_cmd->src_addr, max_size), + compute_max_size(p_dma_cmd->dst_addr, max_size)); + + + return ((max_size >> width) << width); +} + +static u32 +format(struct axon_dma_ops_t *dma_ops, + struct axon_dma_cmd_t *p_dma_cmd, + struct axon_dma_pkt_t *p_dma_pkt, + struct axon_dma_pkt_t *p_dma_pkt_prev) +{ + struct axon_dma_ops_dma_aux_t *p_dma_ops_dma_aux = + dma_ops->context; + + u32 crn; + u32 count; + u32 byte_count; + u8 *dma_pkt = (u8 *) p_dma_pkt->addr; + axon_dma_xfer_width width; + u8 dma_is_complete = 0; + + + (void) p_dma_ops_dma_aux; + + dbg_log("Creating DMA packet in 0x%p:\n", p_dma_pkt->addr); + dbg_log(" from 0x%016" AXON_U64_FMT_T " to 0x%016" AXON_U64_FMT_T + " \n", be64_to_cpu(p_dma_cmd->src_addr), + be64_to_cpu(p_dma_cmd->dst_addr)); + + width = MIN(dma_ops_get_best_align_width(p_dma_cmd->src_addr, + p_dma_cmd->byte_count), + dma_ops_get_best_align_width(p_dma_cmd->dst_addr, + p_dma_cmd->byte_count)); + + if (axon_aux_dma_is_broken && !axon_aux_dma_use_ben_bit) { + width = AXON_WIDTH_BYTE; + } + + + axon_writel(BE_HI32_FROM_BE64(p_dma_cmd->src_addr), + dma_pkt + AuxDMA_SAHn); + axon_writel(BE_LO32_FROM_BE64(p_dma_cmd->src_addr), + dma_pkt + AuxDMA_SALn); + + axon_writel(BE_HI32_FROM_BE64(p_dma_cmd->dst_addr), + dma_pkt + AuxDMA_DAHn); + axon_writel(BE_LO32_FROM_BE64(p_dma_cmd->dst_addr), + dma_pkt + AuxDMA_DALn); + + byte_count = max_packet_size(p_dma_cmd, width); + + if (byte_count == p_dma_cmd->byte_count) + dma_is_complete = 1; + + + count = byte_count >> width; + dbg_log("\t %d bytes = %d of %d bytes long word \n", byte_count, + count, 1 << width); + + count = __cpu_to_be32(count); + + + if (dma_is_complete && (p_dma_cmd->intr == DMA_INTR_NOWAIT)) { + count = be32_set_bit(count, AuxDMA_CTCn_ETIE); + } + + + count = be32_set_bit(count, AuxDMA_CTCn_EIE); + + axon_writel(count, dma_pkt + AuxDMA_CTCn); + + + if (p_dma_pkt_prev != NULL) { + dma_ops->link(dma_ops, p_dma_pkt_prev, p_dma_pkt); + } + + crn = 0; + + + crn = + be32_set_bit_range(crn, AuxDMA_CRn_PW_hi, AuxDMA_CRn_PW_lo, + width); + + + crn = be32_set_bit(crn, AuxDMA_CRn_CIE); + + + crn = be32_clr_bit(crn, AuxDMA_CRn_PL); + + + crn = be32_set_bit(crn, AuxDMA_CRn_DAI); + crn = be32_set_bit(crn, AuxDMA_CRn_SAI); + + + if (axon_aux_dma_use_ben_bit) { + crn = be32_set_bit(crn, AuxDMA_CRn_BEN); + } else { + crn = be32_clr_bit(crn, AuxDMA_CRn_BEN); + } + + + crn = + be32_set_bit_range(crn, AuxDMA_CRn_TM_hi, AuxDMA_CRn_TM_lo, + AuxDMA_CRn_TM_SW_INITIATED); + + + crn = + be32_set_bit_range(crn, AuxDMA_CRn_CP_hi, AuxDMA_CRn_CP_lo, + AuxDMA_CRn_CP_HIGH_PRIORITY); + + + crn = be32_set_bit(crn, AuxDMA_CRn_ETD); + + + crn = be32_set_bit(crn, AuxDMA_CRn_TCE); + + + wmb(); + crn = be32_set_bit(crn, AuxDMA_CRn_CE); + + + if (dma_is_complete && (p_dma_cmd->intr == DMA_INTR_NOWAIT)) { + dbg_log("\t Setting interrupt bit \n"); + crn = be32_set_bit(crn, AuxDMA_CRn_CIE); + } + + axon_writel(crn, dma_pkt + DMAx_CRn); + wmb(); + + return byte_count; +} + +static void +queue(struct axon_dma_ops_t *dma_ops, struct axon_dma_pkt_t *p_dma_pkt) +{ + + struct axon_dma_ops_dma_aux_t *p_dma_ops_dma_aux = + dma_ops->context; + + axon_writel(BE_HI32_FROM_BE64(p_dma_pkt->plb_bus_addr), + p_dma_ops_dma_aux->p_dma_channel + AuxDMA_SGH); + + axon_writel(BE_LO32_FROM_BE64(p_dma_pkt->plb_bus_addr), + p_dma_ops_dma_aux->p_dma_channel + AuxDMA_SGL); + + wmb(); + +} + +static void +start(struct axon_dma_ops_t *dma_ops, struct axon_dma_pkt_t *p_dma_pkt) +{ + u32 sgc; + + struct axon_dma_ops_dma_aux_t *p_dma_ops_dma_aux = + dma_ops->context; + + + spin_lock(&p_dma_ops_dma_aux->lock); + + sgc = dma_aux_read(p_dma_ops_dma_aux, AuxDMA_SGC); + + dbg_log("AuxDMA_SGC was set to 0x%08x\n", sgc); + + sgc = + be32_set_bit(sgc, + AuxDMA_SGC_EMn + p_dma_ops_dma_aux->channel_id); + + + sgc = + be32_clr_bit(sgc, + AuxDMA_SGC_SGLn + p_dma_ops_dma_aux->channel_id); + + dbg_log("writing 0x%08x to AuxDMA_SGC\n", sgc); + + dma_aux_write(p_dma_ops_dma_aux, AuxDMA_SGC, sgc); + + + sgc = dma_aux_read(p_dma_ops_dma_aux, AuxDMA_SGC); + + + sgc = + be32_set_bit(sgc, + AuxDMA_SGC_SSGn + p_dma_ops_dma_aux->channel_id); + + dbg_log("writing 0x%08x to AuxDMA_SGC\n", sgc); + + dma_aux_write(p_dma_ops_dma_aux, AuxDMA_SGC, sgc); + + + sgc = dma_aux_read(p_dma_ops_dma_aux, AuxDMA_SGC); + + spin_unlock(&p_dma_ops_dma_aux->lock); + +} + +static void +reset(struct axon_dma_ops_t *dma_ops) +{ + struct axon_dma_ops_dma_aux_t *p_dma_ops_dma_aux = + dma_ops->context; + + u32 sr = 0x88000000 >> p_dma_ops_dma_aux->channel_id; + + + dbg_log("Clearing Status register \n"); + + dma_aux_write(p_dma_ops_dma_aux, AuxDMA_SR, sr); + + + sr = dma_aux_read(p_dma_ops_dma_aux, AuxDMA_SR); +} + + +static irqreturn_t +err_interrupt_handler(void *data, int irq, void *dev_id, + struct pt_regs *regs) +{ + struct axon_dma_ops_t *p_dma_ops = data; + struct axon_dma_ops_dma_aux_t *p_dma_ops_dma_aux = + p_dma_ops->context; + + u32 sr; + + dbg_log("DmaAux error interrupt triggered \n"); + + sr = dma_aux_read(p_dma_ops_dma_aux, AuxDMA_SR); + + dbg_log("Status register is set to 0x%08x\n", sr); + + reset(p_dma_ops); + + return IRQ_HANDLED; +} + +static char *aux_dma_interrupt_name[4] = { + "Axon Aux_DMA_Error chan 0", + "Axon Aux_DMA_Error chan 1", + "Axon Aux_DMA_Error chan 2", + "Axon Aux_DMA_Error chan 3" +}; + +static void +destroy(struct axon_dma_ops_t *p_dma_ops) +{ + if (p_dma_ops) { + struct axon_dma_ops_dma_aux_t *p_dma_ops_dma_aux = + p_dma_ops->context; + + if (p_dma_ops_dma_aux) { + axon_unregister_irq_handler(p_dma_ops_dma_aux-> + p_axon, + AXON_BEI_INTR_AUX_DMA_CH0_ERR + + + p_dma_ops_dma_aux-> + channel_id, + err_interrupt_handler); + + kfree(p_dma_ops_dma_aux); + } + + kfree(p_dma_ops); + } +} + +int +axon_dma_ops_dma_aux_create(struct axon_t *p_axon, + axon_dma_channel_t channel, + struct axon_dma_ops_t **pp_dma_ops) +{ + int ret = 0; + + struct axon_dma_ops_t *p_dma_ops; + struct axon_dma_ops_dma_aux_t *p_dma_ops_dma_aux; + unsigned dmaslp, + tmp; + + if (axon_use_aux_dma == 0) + return -ENODEV; + + tmp = dmaslp = + axon_readl(axon_regs_dma_aux_get(p_axon) + AuxDMA_SLP); + tmp = __be32_to_cpu(tmp); + dbg_log("AuxDMA SLP is 0x%08x \n", tmp); + + + if ((tmp & 0x07C00000) != 0x07C00000) { + dbg_err("No Aux DMA detected \n"); + return -ENODEV; + } + + + axon_writel(0, axon_regs_dma_aux_get(p_axon) + AuxDMA_SLP); + + + tmp = axon_readl(axon_regs_dma_aux_get(p_axon) + AuxDMA_SLP); + tmp = __be32_to_cpu(tmp); + + + if ((tmp & 0x07C00000) != 0x07C00000) { + dbg_err("No Aux DMA detected \n"); + + axon_writel(dmaslp, + axon_regs_dma_aux_get(p_axon) + AuxDMA_SLP); + return -ENODEV; + } + + + axon_writel(dmaslp, axon_regs_dma_aux_get(p_axon) + AuxDMA_SLP); + + p_dma_ops = kzalloc(sizeof(struct axon_dma_ops_t), GFP_KERNEL); + + if (p_dma_ops == NULL) { + dbg_err + ("Unable to allocated dma_ops operation in dma_aux \n"); + ret = -ENOMEM; + goto err_dma_ops; + } + + p_dma_ops_dma_aux = + kzalloc(sizeof(struct axon_dma_ops_dma_aux_t), GFP_KERNEL); + + if (p_dma_ops_dma_aux == NULL) { + dbg_err + ("Unable to allocated dma_ops_dma_aux operation \n"); + ret = -ENOMEM; + goto err_dma_ops_dma_aux; + } + + + switch (channel) { + case AXON_DMA_CHANNEL_0: + p_dma_ops_dma_aux->p_dma_channel = + axon_regs_dma_aux_get(p_axon) + AuxDMA_CR0; + p_dma_ops_dma_aux->channel_id = 0; + break; + + case AXON_DMA_CHANNEL_1: + p_dma_ops_dma_aux->p_dma_channel = + axon_regs_dma_aux_get(p_axon) + AuxDMA_CR1; + p_dma_ops_dma_aux->channel_id = 1; + break; + + case AXON_DMA_CHANNEL_2: + p_dma_ops_dma_aux->p_dma_channel = + axon_regs_dma_aux_get(p_axon) + AuxDMA_CR2; + p_dma_ops_dma_aux->channel_id = 2; + break; + + case AXON_DMA_CHANNEL_3: + p_dma_ops_dma_aux->p_dma_channel = + axon_regs_dma_aux_get(p_axon) + AuxDMA_CR3; + p_dma_ops_dma_aux->channel_id = 3; + break; + + default: + ret = -EINVAL; + dbg_err + ("Wrong channel specified during DMA instance creation \n"); + goto err_dma_channel; + break; + }; + + p_dma_ops_dma_aux->channel = channel; + + spin_lock_init(&p_dma_ops_dma_aux->lock); + + + p_dma_ops_dma_aux->p_regs = axon_regs_dma_aux_get(p_axon); + + p_dma_ops_dma_aux->p_axon = p_axon; + + + ret = axon_register_irq_handler(p_axon, + AXON_BEI_INTR_AUX_DMA_CH0_ERR + + p_dma_ops_dma_aux->channel_id, + err_interrupt_handler, + aux_dma_interrupt_name + [p_dma_ops_dma_aux->channel_id], + p_dma_ops); + + + p_dma_ops->context = p_dma_ops_dma_aux; + + p_dma_ops->format = format; + p_dma_ops->queue = queue; + p_dma_ops->start = start; + p_dma_ops->resume = NULL; + p_dma_ops->link = link; + p_dma_ops->reset = reset; + p_dma_ops->mbox = NULL; + p_dma_ops->destroy = destroy; + + + + *pp_dma_ops = p_dma_ops; + + goto no_err; + + + err_dma_channel: + kfree(p_dma_ops_dma_aux); + + err_dma_ops_dma_aux: + kfree(p_dma_ops); + + err_dma_ops: + + + no_err: + + return ret; + +} Index: linux/drivers/axon/common/axon_dma_ops_dma_soft.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/drivers/axon/common/axon_dma_ops_dma_soft.c 2006-12-19 17:53:10.000000000 +0100 @@ -0,0 +1,432 @@ +/****************************************************************** + * Copyright (C) 2006 Mercury Computer Systems, Inc. + * 199 Riverneck Road + * Chelmsford, MA 01824-2820 + * (978) 256-1300 + * webinfo@mc.com + * + * 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, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * http://www.gnu.org/copyleft/gpl.html + ******************************************************************/ + + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +static int axon_use_soft_dma = 1; + +module_param(axon_use_soft_dma, int, 0644); +MODULE_PARM_DESC(axon_use_soft_dma, + "This allows to define if the driver should try to use the Emulated soft DMA. By default it will use it as the fallback mechanism but you can request to skip it by setting this parameter to 0"); + +static void +link(struct axon_dma_ops_t *dma_ops, + struct axon_dma_pkt_t *p_dma_pkt_prev, + struct axon_dma_pkt_t *p_dma_pkt) +{ + + struct axon_dma_ops_dma_soft_t *p_dma_ops_dma_soft = + dma_ops->context; + + struct axon_dma_soft_cmd_t *p_dma_soft_cmd_prev = + p_dma_pkt_prev->addr; + struct axon_dma_soft_cmd_t *p_dma_soft_cmd = p_dma_pkt->addr; + + + (void) p_dma_ops_dma_soft; + + p_dma_soft_cmd_prev->next = p_dma_soft_cmd; +} + + +static u32 +format(struct axon_dma_ops_t *dma_ops, + struct axon_dma_cmd_t *p_dma_cmd, + struct axon_dma_pkt_t *p_dma_pkt, + struct axon_dma_pkt_t *p_dma_pkt_prev) +{ + struct axon_dma_ops_dma_soft_t *p_dma_ops_dma_soft = + dma_ops->context; + struct addr_xltr_t *p_xltr = p_dma_ops_dma_soft->p_addr_xltr; + + dma_addr_t src_bus_addr, + dst_bus_addr; + + + struct axon_dma_soft_cmd_t *p_dma_soft_cmd = p_dma_pkt->addr; + + dbg_log("Soft DMA is storing xfer command \n"); + + + dbg_log("PLB src addr = 0x%016" AXON_PLB_ADDR_FMT_T "\n", + __be64_to_cpu(p_dma_cmd->src_addr)); + dbg_log("PLB dst addr = 0x%016" AXON_PLB_ADDR_FMT_T "\n", + __be64_to_cpu(p_dma_cmd->dst_addr)); + + + if (p_xltr->is_local(p_xltr, p_dma_cmd->src_addr) == 1) { + src_bus_addr = + p_xltr->from_plb(p_xltr, p_dma_cmd->src_addr); + + if (src_bus_addr != AXON_INVALID_BUS_ADDR) { + dbg_log("BUS src addr = 0x%016" AXON_PLB_ADDR_FMT_T + "\n", src_bus_addr); + p_dma_soft_cmd->direction = + AXON_DMA_SOFT_DIRECTION_FROM_CPU; + p_dma_soft_cmd->cpu_addr = __va(src_bus_addr); + p_dma_soft_cmd->plb_addr = p_dma_cmd->dst_addr; + } else { + } + } else if (p_xltr->is_local(p_xltr, p_dma_cmd->dst_addr) == 1) { + dst_bus_addr = + p_xltr->from_plb(p_xltr, p_dma_cmd->dst_addr); + + if (dst_bus_addr != AXON_INVALID_BUS_ADDR) { + dbg_log("BUS dst addr = 0x%016" AXON_PLB_ADDR_FMT_T + "\n", dst_bus_addr); + p_dma_soft_cmd->direction = + AXON_DMA_SOFT_DIRECTION_TO_CPU; + p_dma_soft_cmd->cpu_addr = __va(dst_bus_addr); + p_dma_soft_cmd->plb_addr = p_dma_cmd->src_addr; + } else { + } + } else { + + p_dma_soft_cmd->direction = + AXON_DMA_SOFT_DIRECTION_INVALID; + dbg_err("Setting invalid direction for plb_src_addr=0x%016" + AXON_PLB_ADDR_FMT_T ",plb_dst_addr=0x%016" + AXON_PLB_ADDR_FMT_T "\n", + __be64_to_cpu(p_dma_cmd->src_addr), + __be64_to_cpu(p_dma_cmd->dst_addr)); + } + + p_dma_soft_cmd->xfer_size = p_dma_cmd->byte_count; + + p_dma_soft_cmd->p_mbox = NULL; + + + p_dma_soft_cmd->next = NULL; + + dbg_log("size = 0x%08x\n", p_dma_soft_cmd->xfer_size); + dbg_log("CPU addr = %p\n", p_dma_soft_cmd->cpu_addr); + dbg_log("plb_src_addr = 0x%016" AXON_PLB_ADDR_FMT_T "\n", + __be64_to_cpu(p_dma_cmd->src_addr)); + dbg_log("plb_dst_addr = 0x%016" AXON_PLB_ADDR_FMT_T "\n", + __be64_to_cpu(p_dma_cmd->dst_addr)); + dbg_log("direction = %s\n", + p_dma_soft_cmd->direction == + AXON_DMA_SOFT_DIRECTION_FROM_CPU ? + "AXON_DMA_SOFT_DIRECTION_FROM_CPU" : + "AXON_DMA_SOFT_DIRECTION_TO_CPU"); + + + if (p_dma_pkt_prev != NULL) { + + dbg_log("Soft DMA is linking xfer command to previous \n"); + + link(dma_ops, p_dma_pkt_prev, p_dma_pkt); + } + + return p_dma_cmd->byte_count; +} + + +static void +queue(struct axon_dma_ops_t *dma_ops, struct axon_dma_pkt_t *p_dma_pkt) +{ + + struct axon_dma_ops_dma_soft_t *p_dma_ops_dma_soft = + dma_ops->context; + + dbg_log("Soft DMA 0x%p is queuing initial command 0x%p \n", + p_dma_ops_dma_soft, p_dma_pkt->addr); + + + p_dma_ops_dma_soft->p_first_cmd = p_dma_pkt->addr; + +} + +static void +mbox(struct axon_dma_ops_t *dma_ops, + struct axon_mbox_t *p_mbox, + u8 * mbox_data, + struct axon_dma_pkt_t *p_dma_pkt, + struct axon_dma_pkt_t *p_dma_pkt_prev) +{ + struct axon_dma_ops_dma_soft_t *p_dma_ops_dma_soft = + dma_ops->context; + struct axon_dma_soft_cmd_t *p_dma_soft_cmd = p_dma_pkt->addr; + + dbg_log("Soft DMA is storing MBOX command \n"); + + + (void) p_dma_ops_dma_soft; + + + p_dma_soft_cmd->p_mbox = p_mbox; + + + memcpy(p_dma_soft_cmd->mbox, mbox_data, AXON_SMS_SIZE); + + + p_dma_soft_cmd->next = NULL; + + + + if (p_dma_pkt_prev != NULL) { + dbg_log("Soft DMA is linking MBOX command to previous \n"); + + link(dma_ops, p_dma_pkt_prev, p_dma_pkt); + } +} + +static void +start(struct axon_dma_ops_t *dma_ops, struct axon_dma_pkt_t *p_dma_pkt) +{ + + struct axon_dma_ops_dma_soft_t *p_dma_ops_dma_soft = + dma_ops->context; + + dbg_log("Soft DMA 0x%p is starting \n", p_dma_ops_dma_soft); + + schedule_work(&p_dma_ops_dma_soft->dma_engine_task); +} + + +static void +reset(struct axon_dma_ops_t *dma_ops) +{ + struct axon_dma_ops_dma_soft_t *p_dma_ops_dma_soft = + dma_ops->context; + + dbg_log("Soft DMA 0x%p is being reset \n", p_dma_ops_dma_soft); + + p_dma_ops_dma_soft->p_first_cmd = NULL; + +} + + +static void +dma_engine_entry(void *data) +{ + struct axon_dma_ops_t *p_dma_ops = (struct axon_dma_ops_t *) data; + struct axon_dma_ops_dma_soft_t *p_dma_ops_dma_soft = + p_dma_ops->context; + + + struct axon_dma_soft_cmd_t *p_dma_cmd = + p_dma_ops_dma_soft->p_first_cmd; + p_dma_ops_dma_soft->p_first_cmd = NULL; + + dbg_log + ("Soft DMA 0x%p has started to process command(s) with 0x%p\n", + p_dma_ops_dma_soft, p_dma_cmd); + + while (p_dma_cmd != NULL) { + + dbg_log("Soft DMA is processing 0x%p \n", p_dma_cmd); + + if (p_dma_cmd->p_mbox == NULL) { + + struct axon_pio_t *p_pio = + p_dma_ops_dma_soft->p_pio; + + switch (p_dma_cmd->direction) { + + case AXON_DMA_SOFT_DIRECTION_FROM_CPU: + dbg_log + ("Soft DMA: from CPU=0x%p to PLB=0x%016" + AXON_PLB_ADDR_FMT_T " (%u bytes)\n", + p_dma_cmd->cpu_addr, + p_dma_cmd->plb_addr, + p_dma_cmd->xfer_size); + p_pio->copy_toio(p_pio, + p_dma_cmd->plb_addr, + p_dma_cmd->cpu_addr, + p_dma_cmd->xfer_size); + break; + + case AXON_DMA_SOFT_DIRECTION_TO_CPU: + dbg_log("Soft DMA: from PLB=0x%016" + AXON_PLB_ADDR_FMT_T + " to CPU=0x%p (%u bytes)\n", + p_dma_cmd->plb_addr, + p_dma_cmd->cpu_addr, + p_dma_cmd->xfer_size); + p_pio->copy_fromio(p_pio, + p_dma_cmd->cpu_addr, + p_dma_cmd->plb_addr, + p_dma_cmd->xfer_size); + break; + + case AXON_DMA_SOFT_DIRECTION_INVALID: + default: + dbg_err + ("Invalid direction within a SOft DMA command packet \n"); + break; + + } + + + + } else { + int ret = 0; + + struct axon_sms_msg_t msg; + + + msg.channel = + p_dma_cmd-> + mbox[AXON_SMS_CHANNEL_BYTE] & + AXON_SMS_CHANNEL_MASK; + + dbg_log + ("Soft DMA: Generating mailbox for 0x%p on channel %d \n", + p_dma_cmd->p_mbox, msg.channel); + memcpy(msg.payload, + &(p_dma_cmd->mbox[AXON_SMS_PAYLOAD_BYTE]), + AXON_SMS_SIZE - AXON_SMS_CHANNEL_SIZE); + + ret = axon_sms_send(p_dma_ops_dma_soft->p_sms, + p_dma_cmd->p_mbox, &msg); + if (ret < 0) { + + dbg_err + ("Unable to send SMS from Soft DMA\n"); + + + } + } + + + + p_dma_cmd = p_dma_cmd->next; + } + dbg_log("Soft DMA 0x%p has completed command processing \n", + p_dma_ops_dma_soft); + +} + +static void +destroy(struct axon_dma_ops_t *p_dma_ops) +{ + if (p_dma_ops) { + struct axon_dma_ops_dma_soft_t *p_dma_ops_dma_soft = + p_dma_ops->context; + + + flush_scheduled_work(); + + + + if (p_dma_ops_dma_soft) + kfree(p_dma_ops_dma_soft); + + kfree(p_dma_ops); + } +} + +int +axon_dma_ops_dma_soft_create(struct axon_t *p_axon, + struct addr_xltr_t *p_addr_xltr, + axon_dma_channel_t channel, + struct axon_sms_t *p_sms, + struct axon_pio_t *p_pio, + struct axon_dma_ops_t **pp_dma_ops) +{ + int ret = 0; + + struct axon_dma_ops_t *p_dma_ops; + struct axon_dma_ops_dma_soft_t *p_dma_ops_dma_soft; + + if (axon_use_soft_dma == 0) + return -ENODEV; + + + BUG_ON(sizeof(struct axon_dma_soft_cmd_t) > DMAx_DESCRIPTOR_SIZE); + + p_dma_ops = kzalloc(sizeof(struct axon_dma_ops_t), GFP_KERNEL); + + if (p_dma_ops == NULL) { + dbg_err + ("Unable to allocated dma_ops operation in dma_soft \n"); + ret = -ENOMEM; + goto err_dma_ops; + } + + p_dma_ops_dma_soft = + kzalloc(sizeof(struct axon_dma_ops_dma_soft_t), GFP_KERNEL); + + if (p_dma_ops_dma_soft == NULL) { + dbg_err + ("Unable to allocated dma_ops_dma_soft operation \n"); + ret = -ENOMEM; + goto err_dma_ops_dma_soft; + } + + + + p_dma_ops->context = p_dma_ops_dma_soft; + + p_dma_ops_dma_soft->p_sms = p_sms; + p_dma_ops_dma_soft->p_pio = p_pio; + p_dma_ops_dma_soft->p_addr_xltr = p_addr_xltr; + + p_dma_ops->format = format; + p_dma_ops->queue = queue; + p_dma_ops->start = start; + p_dma_ops->resume = NULL; + p_dma_ops->link = link; + p_dma_ops->reset = reset; + p_dma_ops->mbox = mbox; + p_dma_ops->destroy = destroy; + + INIT_WORK(&p_dma_ops_dma_soft->dma_engine_task, + dma_engine_entry, p_dma_ops); + + spin_lock_init(&p_dma_ops_dma_soft->lock); + + + + *pp_dma_ops = p_dma_ops; + + goto no_err; + + + err_dma_ops_dma_soft: + kfree(p_dma_ops); + + err_dma_ops: + + + no_err: + + return ret; + +} Index: linux/drivers/axon/common/axon_dma_ops_dmax.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/drivers/axon/common/axon_dma_ops_dmax.c 2006-12-19 17:53:10.000000000 +0100 @@ -0,0 +1,490 @@ +/****************************************************************** + * Copyright (C) 2006 Mercury Computer Systems, Inc. + * 199 Riverneck Road + * Chelmsford, MA 01824-2820 + * (978) 256-1300 + * webinfo@mc.com + * + * 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, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * http://www.gnu.org/copyleft/gpl.html + ******************************************************************/ + + +#include +#include +#include +#include + +#include +#include +#ifdef __powerpc__ +#include +#endif + +#include +#include +#include +#include +#include +#include + +static int axon_use_dmax = 1; + +module_param(axon_use_dmax, int, 0644); +MODULE_PARM_DESC(axon_use_dmax, + "This allows to define if the driver should try to use the DMAX if present. By default it will try to discover and use it but you can request to skip it by setting this parameter to 0"); + +static void +link(struct axon_dma_ops_t *dma_ops, + struct axon_dma_pkt_t *p_dma_pkt_prev, + struct axon_dma_pkt_t *p_dma_pkt) +{ + struct axon_dma_ops_dmax_t *p_dma_ops_dmax = dma_ops->context; + + u32 count; + + u8 *dma_pkt = (u8 *) p_dma_pkt_prev->addr; + + + (void) p_dma_ops_dmax; + + dbg_log("\t Linking 0x%p to previous 0x%p \n", p_dma_pkt->addr, + p_dma_pkt_prev->addr); + + axon_writel(BE_HI32_FROM_BE64(p_dma_pkt->plb_bus_addr), + dma_pkt + DMAx_SGHn); + axon_writel(BE_LO32_FROM_BE64(p_dma_pkt->plb_bus_addr), + dma_pkt + DMAx_SGLn); + + + count = axon_readl(dma_pkt + DMAx_CTCn); + count = be32_set_bit(count, DMAx_CTCn_LK); + + + axon_writel(count, dma_pkt + DMAx_CTCn); +} + +static u32 +format(struct axon_dma_ops_t *dma_ops, + struct axon_dma_cmd_t *p_dma_cmd, + struct axon_dma_pkt_t *p_dma_pkt, + struct axon_dma_pkt_t *p_dma_pkt_prev) +{ + struct axon_dma_ops_dmax_t *p_dma_ops_dmax = dma_ops->context; + + u32 crn; + u32 count; + u8 *dma_pkt = (u8 *) p_dma_pkt->addr; + axon_dma_xfer_width width; + + count = p_dma_cmd->byte_count; + + + (void) p_dma_ops_dmax; + + dbg_log("Creating DMA packet in 0x%p:\n", p_dma_pkt->addr); + dbg_log(" from 0x%016" AXON_U64_FMT_T " to 0x%016" AXON_U64_FMT_T + " \n", be64_to_cpu(p_dma_cmd->src_addr), + be64_to_cpu(p_dma_cmd->dst_addr)); + + width = MIN(dma_ops_get_best_align_width(p_dma_cmd->src_addr, + count), + dma_ops_get_best_align_width(p_dma_cmd->dst_addr, + count)); + + + axon_writel(BE_HI32_FROM_BE64(p_dma_cmd->src_addr), + dma_pkt + DMAx_SAHn); + axon_writel(BE_LO32_FROM_BE64(p_dma_cmd->src_addr), + dma_pkt + DMAx_SALn); + + axon_writel(BE_HI32_FROM_BE64(p_dma_cmd->dst_addr), + dma_pkt + DMAx_DAHn); + axon_writel(BE_LO32_FROM_BE64(p_dma_cmd->dst_addr), + dma_pkt + DMAx_DALn); + + + count = count >> width; + + count = MIN(count, 1024 * 1024); + + dbg_log("\t %d of %d bytes long word (total = %d bytes)\n", count, + 1 << width, p_dma_cmd->byte_count); + + if (p_dma_cmd->byte_count > (count * (1 << width))) + dbg_log + ("DMAX Packet (%d * %d = %d) is smaller than transfert (%d)\n", + count, 1 << width, count << width, + p_dma_cmd->byte_count); + + axon_writel(__cpu_to_be32(count), dma_pkt + DMAx_CTCn); + + + if (p_dma_pkt_prev != NULL) { + dma_ops->link(dma_ops, p_dma_pkt_prev, p_dma_pkt); + } + + + crn = 0; + + + crn = + be32_set_bit_range(crn, DMAx_CRn_PW_hi, DMAx_CRn_PW_lo, width); + + + + wmb(); + crn = be32_set_bit(crn, DMAx_CRn_CE); + + + if (p_dma_cmd->intr != DMA_NO_INTR) { + dbg_log("\t Setting interrupt bit \n"); + crn = be32_set_bit(crn, DMAx_CRn_BIE); + crn = be32_set_bit(crn, DMAx_CRn_BAR); + } + + if (p_dma_cmd->intr == DMA_INTR_NOWAIT) { + dbg_log("\t No wait bit \n"); + crn = be32_set_bit(crn, DMAx_CRn_CIM); + } + + axon_writel(crn, dma_pkt + DMAx_CRn); + wmb(); + + return (count << width); +} + +static void +queue(struct axon_dma_ops_t *dma_ops, struct axon_dma_pkt_t *p_dma_pkt) +{ + struct axon_dma_ops_dmax_t *p_dma_ops_dmax = dma_ops->context; + + axon_writel(BE_HI32_FROM_BE64(p_dma_pkt->plb_bus_addr), + p_dma_ops_dmax->p_dma_channel + DMAx_SGHn); + + axon_writel(BE_LO32_FROM_BE64(p_dma_pkt->plb_bus_addr), + p_dma_ops_dmax->p_dma_channel + DMAx_SGLn); + wmb(); +} + +static void +start(struct axon_dma_ops_t *dma_ops, struct axon_dma_pkt_t *p_dma_pkt) +{ + u32 sgcn; + + struct axon_dma_ops_dmax_t *p_dma_ops_dmax = dma_ops->context; + + sgcn = be32_set_bit(0, DMAx_SGCn_SSG); + axon_writel(sgcn, p_dma_ops_dmax->p_dma_channel + DMAx_SGCn); + +} + +static void +resume(struct axon_dma_ops_t *dma_ops, struct axon_dma_pkt_t *p_dma_pkt) +{ + struct axon_dma_ops_dmax_t *p_dma_ops_dmax = dma_ops->context; + + u32 resume_reg; + + resume_reg = be32_set_bit(0, DMAx_CHRESn_CHR); + axon_writel(resume_reg, + p_dma_ops_dmax->p_dma_channel + DMAx_CHRESn); +} + +static void +reset(struct axon_dma_ops_t *dma_ops) +{ + struct axon_dma_ops_dmax_t *p_dma_ops_dmax = dma_ops->context; + + u32 options_reg, + arbitration_mod_reg, + status_reg; + + options_reg = dmax_read(p_dma_ops_dmax, DMAx_OPTIONS); + dbg_log("DMA options register was set to 0x%08x \n", + __cpu_to_be32(options_reg)); + + + options_reg = be32_set_bit(options_reg, 28); + + options_reg = be32_set_bit(options_reg, 29); + dmax_write(p_dma_ops_dmax, DMAx_OPTIONS, options_reg); + dbg_log("DMA options register is set to 0x%08x \n", + __cpu_to_be32(options_reg)); + + arbitration_mod_reg = dmax_read(p_dma_ops_dmax, DMAx_PLBARB); + dbg_log("DMA Arbitration mode register was set to 0x%08x \n", + __cpu_to_be32(arbitration_mod_reg)); + + arbitration_mod_reg = be32_set_bit(arbitration_mod_reg, 1); + + dbg_log("Enabling round robin by writing 0x%08x\n", + __cpu_to_be32(arbitration_mod_reg)); + + dmax_write(p_dma_ops_dmax, DMAx_PLBARB, arbitration_mod_reg); + + arbitration_mod_reg = dmax_read(p_dma_ops_dmax, DMAx_PLBARB); + dbg_log("DMA Arbitration mode register is set to 0x%08x \n", + __cpu_to_be32(arbitration_mod_reg)); + + while (be32_isset_bit + (status_reg = + dmax_read(p_dma_ops_dmax, DMAx_SR), + 20 + p_dma_ops_dmax->channel_id)) { + dbg_log("DMAX Channel %d is still running \n", + p_dma_ops_dmax->channel_id); + } + + if (be32_isset_bit + (status_reg, (p_dma_ops_dmax->channel_id + 1) * 4)) { + dbg_err("DMAX Channel %d is in error \n", + p_dma_ops_dmax->channel_id); + dbg_inf("DMA status reg was set to 0x%08x \n", + __cpu_to_be32(status_reg)); + } else + dbg_log("DMA status reg was set to 0x%08x \n", + __cpu_to_be32(status_reg)); + + + status_reg = be32_set_bit(0, p_dma_ops_dmax->channel_id); + status_reg = + be32_set_bit(status_reg, (p_dma_ops_dmax->channel_id + 1) * 4); + + dbg_log("Clearing Status register \n"); + dmax_write(p_dma_ops_dmax, DMAx_SR, status_reg); +} + +static irqreturn_t +err_interrupt_handler(void *data, int irq, void *dev_id, + struct pt_regs *regs) +{ + struct axon_dma_ops_t *p_dma_ops = data; + struct axon_dma_ops_dmax_t *p_dma_ops_dmax = p_dma_ops->context; + + u32 sr; + + dbg_inf("DMAX error interrupt triggered \n"); + + sr = dmax_read(p_dma_ops_dmax, DMAx_SR); + + dbg_inf("Status register is set to 0x%08x\n", sr); + + reset(p_dma_ops); + + return IRQ_HANDLED; +} + +static irqreturn_t +err_slave_interrupt_handler(void *data, int irq, void *dev_id, + struct pt_regs *regs) +{ + struct axon_dma_ops_t *p_dma_ops = data; + struct axon_dma_ops_dmax_t *p_dma_ops_dmax = p_dma_ops->context; + + u32 sr; + + dbg_inf("DMAX Slave error interrupt triggered \n"); + + sr = dmax_read(p_dma_ops_dmax, DMAx_PSE); + + dbg_inf("DMA PLB Slave Error register is set to 0x%08x\n", sr); + + + + return IRQ_HANDLED; +} + +static char *dmax_interrupt_name[4] = { + "Axon DMAX_Error chan 0", + "Axon DMAX_Error chan 1", + "Axon DMAX_Error chan 2", + "Axon DMAX_Error chan 3" +}; + +static int PLB_slave_error_interrupt_registered = 0; + +static void +destroy(struct axon_dma_ops_t *p_dma_ops) +{ + if (p_dma_ops) { + struct axon_dma_ops_dmax_t *p_dma_ops_dmax = + p_dma_ops->context; + + if (p_dma_ops_dmax) { + if (p_dma_ops_dmax->type == AXON_SYS_NODE) { + axon_unregister_irq_handler + (p_dma_ops_dmax->p_axon, + AXON_BEI_INTR_DMAX_CH0_ERR + + p_dma_ops_dmax->channel_id, + err_interrupt_handler); + + if (PLB_slave_error_interrupt_registered) { + axon_unregister_irq_handler + (p_dma_ops_dmax->p_axon, + AXON_BEI_INTR_DMAX_SLAVE_ERR, + err_slave_interrupt_handler); + PLB_slave_error_interrupt_registered + = 0; + } + } + + kfree(p_dma_ops_dmax); + } + + kfree(p_dma_ops); + } +} + +int +axon_dma_ops_dmax_create(struct axon_t *p_axon, + axon_dma_channel_t channel, + enum axon_sys_type_t type, + struct axon_dma_ops_t **pp_dma_ops) +{ + int ret = 0; + + struct axon_dma_ops_t *p_dma_ops; + struct axon_dma_ops_dmax_t *p_dma_ops_dmax; + unsigned dmarev; + + *pp_dma_ops = NULL; + + if (axon_use_dmax == 0) + return -ENODEV; + + + dmarev = + __be32_to_cpu(axon_readl + (axon_regs_dmax_get(p_axon) + DMAx_REVID)); + dbg_log("DMA revision is 0x%08x \n", dmarev); + + if (dmarev != 0x12200) { + dbg_err("No DMAX engine detected: DMAx_REVID = 0x%08x \n", + dmarev); + return -ENODEV; + } + + p_dma_ops = kzalloc(sizeof(struct axon_dma_ops_t), GFP_KERNEL); + + if (p_dma_ops == NULL) { + dbg_err + ("Unable to allocated dma_ops operation in dmax \n"); + ret = -ENOMEM; + goto err_dma_ops; + } + + p_dma_ops_dmax = + kzalloc(sizeof(struct axon_dma_ops_dmax_t), GFP_KERNEL); + + if (p_dma_ops_dmax == NULL) { + dbg_err("Unable to allocated dma_ops_dmax operation \n"); + ret = -ENOMEM; + goto err_dma_ops_dmax; + } + + p_dma_ops_dmax->type = type; + + switch (channel) { + case AXON_DMA_CHANNEL_0: + p_dma_ops_dmax->p_dma_channel = + axon_regs_dmax_get(p_axon) + DMAx_CR0; + p_dma_ops_dmax->channel_id = 0; + break; + + case AXON_DMA_CHANNEL_1: + p_dma_ops_dmax->p_dma_channel = + axon_regs_dmax_get(p_axon) + DMAx_CR1; + p_dma_ops_dmax->channel_id = 1; + break; + + case AXON_DMA_CHANNEL_2: + p_dma_ops_dmax->p_dma_channel = + axon_regs_dmax_get(p_axon) + DMAx_CR2; + p_dma_ops_dmax->channel_id = 2; + break; + + case AXON_DMA_CHANNEL_3: + p_dma_ops_dmax->p_dma_channel = + axon_regs_dmax_get(p_axon) + DMAx_CR3; + p_dma_ops_dmax->channel_id = 3; + break; + + default: + dbg_err + ("Invalid channel specified during DMA instance creation \n"); + ret = -EINVAL; + goto err_dma_channel; + break; + }; + + + p_dma_ops_dmax->p_regs = axon_regs_dmax_get(p_axon); + + p_dma_ops_dmax->p_axon = p_axon; + + if (type == AXON_SYS_NODE) { + ret = axon_register_irq_handler(p_axon, + AXON_BEI_INTR_DMAX_CH0_ERR + + + p_dma_ops_dmax->channel_id, + err_interrupt_handler, + dmax_interrupt_name + [p_dma_ops_dmax-> + channel_id], p_dma_ops); + if (ret) + goto err_dma_channel; + + ret = axon_register_irq_handler(p_axon, + AXON_BEI_INTR_DMAX_SLAVE_ERR, + err_slave_interrupt_handler, + "Axon DMAX_PLB_Slave_Error interrupt", + p_dma_ops); + + if (ret == 0) + PLB_slave_error_interrupt_registered = 1; + else + ret = 0; + } + + + p_dma_ops->context = p_dma_ops_dmax; + + p_dma_ops->format = format; + p_dma_ops->queue = queue; + p_dma_ops->start = start; + p_dma_ops->resume = resume; + p_dma_ops->resume = NULL; + p_dma_ops->link = link; + p_dma_ops->reset = reset; + p_dma_ops->mbox = NULL; + p_dma_ops->destroy = destroy; + + + *pp_dma_ops = p_dma_ops; + + return ret; + + err_dma_channel: + kfree(p_dma_ops_dmax); + + err_dma_ops_dmax: + kfree(p_dma_ops); + + err_dma_ops: + + + return ret; +} Index: linux/drivers/axon/common/axon_dmax.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/drivers/axon/common/axon_dmax.c 2006-12-19 17:53:10.000000000 +0100 @@ -0,0 +1,1029 @@ +/****************************************************************** + * Copyright (C) 2006 Mercury Computer Systems, Inc. + * 199 Riverneck Road + * Chelmsford, MA 01824-2820 + * (978) 256-1300 + * webinfo@mc.com + * + * 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, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * http://www.gnu.org/copyleft/gpl.html + ******************************************************************/ + + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +static int +axon_dma_request_pkt_alloc_P(struct axon_dma_req_t *p_dma_req, + struct axon_dma_pkt_t **pp_dma_pkt, + int *p_index) +{ + int ret = 0; + + struct axon_dma_pkt_t *p_dma_pkt; + int index; + + index = p_dma_req->current_pkt; + + if (index >= MAX_CMD_PKT) { + dbg_err("A DMA req cannot have more than %d packets\n", + MAX_CMD_PKT); + return -ENOMEM; + } + + + p_dma_pkt = &(p_dma_req->pkts[index]); + + + p_dma_pkt->addr = + dma_pool_alloc(p_dma_req->p_dma_pool, GFP_KERNEL, + &p_dma_pkt->cpu_bus_addr); + if (p_dma_pkt->addr != NULL) { + + + p_dma_pkt->plb_bus_addr = + p_dma_req->p_addr_xltr->to_plb(p_dma_req->p_addr_xltr, + p_dma_pkt-> + cpu_bus_addr); + + + + p_dma_req->current_pkt++; + + *pp_dma_pkt = p_dma_pkt; + + if (p_index != NULL) { + *p_index = index; + } + + + } else { + dbg_err("Unable to allocated DMA packet \n"); + ret = -ENOMEM; + } + + return ret; +} + + +int +axon_dma_request_pkt_dat_alloc(struct axon_dma_req_t *p_dma_req, + struct axon_dma_pkt_t **pp_dma_pkt) +{ + + + return axon_dma_request_pkt_alloc_P(p_dma_req, pp_dma_pkt, NULL); + + + +} + + +void +axon_dma_request_pkt_cmd_first_get(struct axon_dma_req_t *p_dma_req, + struct axon_dma_pkt_t + **pp_dma_pkt_first) +{ + + struct axon_dma_pkt_t *p_dma_pkt_first = NULL; + + if (p_dma_req->first_pkt != -1) { + p_dma_pkt_first = &(p_dma_req->pkts[p_dma_req->first_pkt]); + } + + *pp_dma_pkt_first = p_dma_pkt_first; + +} + +void +axon_dma_request_pkt_cmd_last_get(struct axon_dma_req_t *p_dma_req, + struct axon_dma_pkt_t **pp_dma_pkt_last) +{ + + struct axon_dma_pkt_t *p_dma_pkt_last = NULL; + + if (p_dma_req->last_pkt != -1) { + p_dma_pkt_last = &(p_dma_req->pkts[p_dma_req->last_pkt]); + } + + *pp_dma_pkt_last = p_dma_pkt_last; + +} + +void +axon_dma_request_pkt_cmd_prev_last_get(struct axon_dma_req_t *p_dma_req, struct axon_dma_pkt_t + **pp_dma_pkt_prev_last) +{ + + struct axon_dma_pkt_t *p_dma_pkt_prev_last = NULL; + + if (p_dma_req->previous_last_pkt != -1) { + p_dma_pkt_prev_last = + &(p_dma_req->pkts[p_dma_req->previous_last_pkt]); + } + + *pp_dma_pkt_prev_last = p_dma_pkt_prev_last; + +} + +int +axon_dma_request_pkt_cmd_alloc(struct axon_dma_req_t *p_dma_req, + struct axon_dma_pkt_t **pp_dma_pkt) +{ + int ret = 0; + + int index_allocated_pkt; + + + + ret = + axon_dma_request_pkt_alloc_P(p_dma_req, pp_dma_pkt, + &index_allocated_pkt); + + if (ret >= 0) { + + + if (p_dma_req->first_pkt == -1) { + p_dma_req->first_pkt = index_allocated_pkt; + } + + + + p_dma_req->previous_last_pkt = p_dma_req->last_pkt; + p_dma_req->last_pkt = index_allocated_pkt; + + } + + return ret; + + +} + +int +axon_dma_request_create(struct axon_dmax_t *p_axon_dmax, + struct axon_dma_req_t **pp_dma_req, + int nb_max_cmd_pkts) +{ + + int ret = 0; + + struct axon_dma_req_t *p_dma_req = NULL; + + spin_lock_bh(&p_axon_dmax->lock_lists); + + if (!list_empty(&p_axon_dmax->requests_free)) { + + + p_dma_req = list_entry(p_axon_dmax->requests_free.next, + struct axon_dma_req_t, list); + + list_del(p_axon_dmax->requests_free.next); + + } else { + dbg_err + ("DMA request creation has been requested but no request are available \n"); + ret = -ENOMEM; + } + + spin_unlock_bh(&p_axon_dmax->lock_lists); + + *pp_dma_req = p_dma_req; + + return ret; +} + + +int +axon_dma_request_initial_create(struct axon_dmax_t *p_axon_dmax, + struct axon_dma_req_t **pp_dma_req, + int nb_max_cmd_pkts) +{ + + int ret = 0; + + struct axon_dma_req_t *p_dma_req; + + p_dma_req = kmalloc(sizeof(struct axon_dma_req_t), GFP_KERNEL); + + if (p_dma_req != NULL) { + + p_dma_req->p_axon_dmax = p_axon_dmax; + + p_dma_req->pkt_size = DMAx_DESCRIPTOR_SIZE; + + + p_dma_req->p_dma_pool = p_axon_dmax->p_dma_pool; + + + p_dma_req->current_pkt = 0; + p_dma_req->last_pkt = -1; + p_dma_req->first_pkt = -1; + p_dma_req->previous_last_pkt = -1; + + p_dma_req->completion_handler = NULL; + p_dma_req->completion_context = NULL; + + + p_dma_req->p_addr_xltr = dmax_addr_xltr_get(p_axon_dmax); + + + p_dma_req->p_dma_channel = p_axon_dmax->p_dma_channel; + + } else { + dbg_err("Unable to allocate DMA request\n"); + ret = -ENOMEM; + } + + *pp_dma_req = p_dma_req; + + return ret; + +} + +int +axon_dma_request_create_pool(struct axon_dmax_t *p_axon_dmax, int nb_reqs) +{ + int i_req; + int ret = 0; + + for (i_req = 0; (i_req < nb_reqs) && (ret == 0); i_req++) { + struct axon_dma_req_t *p_dma_req; + + + ret = + axon_dma_request_initial_create(p_axon_dmax, + &p_dma_req, 128); + if (ret >= 0) { + + list_add_tail(&p_dma_req->list, + &p_dma_req->p_axon_dmax-> + requests_free); + + } else { + dbg_err + ("Unable to create request #%d during pool creation\n", + i_req); + } + + } + + return ret; +} + +static void +axon_dma_request_destroy_pool(struct axon_dmax_t *p_axon_dmax) +{ + struct list_head *p_cursor; + struct list_head *p_next; + struct axon_dma_req_t *p_dma_req; + + list_for_each_safe(p_cursor, p_next, &p_axon_dmax->requests_free) { + + p_dma_req = + list_entry(p_cursor, struct axon_dma_req_t, list); + + list_del(p_cursor); + kfree(p_dma_req); + + } + +} + +int +axon_dma_request_push_xfer(struct axon_dma_req_t *p_dma_req, + struct axon_dma_req_xfer_t *p_dma_req_xfer) +{ + int ret = 0; + + struct axon_dma_pkt_t *p_dma_pkt; + + + struct axon_dma_cmd_t dma_cmd; + + dbg_log("Pushing Write DMA command\n"); + + dma_cmd.dst_addr = p_dma_req_xfer->dst; + dma_cmd.src_addr = p_dma_req_xfer->src; + dma_cmd.byte_count = p_dma_req_xfer->size; + dma_cmd.intr = p_dma_req_xfer->intr; + + while (dma_cmd.byte_count > 0) { + u32 size; + + + struct axon_dma_pkt_t *p_dma_pkt_prev = NULL; + + + + ret = + axon_dma_request_pkt_cmd_alloc(p_dma_req, &p_dma_pkt); + + if (ret < 0) { + dbg_err("Unable to allocate DMA command packet\n"); + ret = -ENOMEM; + break; + } + + + axon_dma_request_pkt_cmd_prev_last_get(p_dma_req, + &p_dma_pkt_prev); + + + size = + p_dma_req->p_axon_dmax->p_dma_ops->format(p_dma_req-> + p_axon_dmax-> + p_dma_ops, + &dma_cmd, + p_dma_pkt, + p_dma_pkt_prev); + + + if (size == 0) { + dbg_err + ("Underlying DMA is unable to process this request.\n"); + ret = -EINVAL; + break; + } + + + dma_cmd.dst_addr = + __cpu_to_be64(__be64_to_cpu(dma_cmd.dst_addr) + size); + dma_cmd.src_addr = + __cpu_to_be64(__be64_to_cpu(dma_cmd.src_addr) + size); + dma_cmd.byte_count -= size; + } + + return ret; + +} + +int +axon_dma_request_push_u32(struct axon_dma_req_t *p_dma_req, + struct axon_dma_req_u32_t *p_dma_req_u32) +{ + int ret = 0; + + struct axon_dma_pkt_t *p_dma_pkt; + + dbg_log("Pushing immediate u32 DMA command \n"); + + + ret = axon_dma_request_pkt_dat_alloc(p_dma_req, &p_dma_pkt); + + if (ret >= 0) { + + struct axon_dma_req_xfer_t dma_req_xfer = + AXON_DMA_REQ_XFER_INIT; + + u32 *p_data = p_dma_pkt->addr; + + + + *p_data = p_dma_req_u32->data; + + wmb(); + + dma_req_xfer.src = p_dma_pkt->plb_bus_addr; + dma_req_xfer.dst = p_dma_req_u32->dst; + dma_req_xfer.size = sizeof(u32); + dma_req_xfer.intr = p_dma_req_u32->intr; + + ret = axon_dma_request_push_xfer(p_dma_req, &dma_req_xfer); + + } else { + dbg_err + ("Unable to allocate DMA packet for interrupt payload\n"); + ret = -ENOMEM; + } + + + return ret; +} + +static int +axon_dma_request_push_mbox_by_ops(struct axon_dma_req_t *p_dma_req, + struct axon_dma_req_mbox_t + *p_dma_req_mbox) +{ + int ret = 0; + + struct axon_dma_pkt_t *p_dma_pkt; + struct axon_mbox_t *p_mbox = p_dma_req_mbox->p_dst_mbox; + + ret = axon_dma_request_pkt_cmd_alloc(p_dma_req, &p_dma_pkt); + + if (ret >= 0) { + + + struct axon_dma_pkt_t *p_dma_pkt_prev = NULL; + + + axon_dma_request_pkt_cmd_prev_last_get(p_dma_req, + &p_dma_pkt_prev); + + + p_dma_req->p_axon_dmax->p_dma_ops->mbox(p_dma_req-> + p_axon_dmax-> + p_dma_ops, p_mbox, + p_dma_req_mbox-> + msg, p_dma_pkt, + p_dma_pkt_prev); + } else { + + dbg_err("Unable to push mailbox request though ops \n"); + + } + + return ret; + +} + + +static int +axon_dma_request_push_mbox_by_write(struct axon_dma_req_t *p_dma_req, struct axon_dma_req_mbox_t + *p_dma_req_mbox) +{ + int ret = 0; + + struct axon_dma_pkt_t *p_dma_pkt; + struct axon_mbox_t *p_mbox = p_dma_req_mbox->p_dst_mbox; + + ret = axon_dma_request_pkt_dat_alloc(p_dma_req, &p_dma_pkt); + + if (ret >= 0) { + + void *p_mbox_msg = p_dma_pkt->addr; + plb_addr_t mbox_plb_bus_dst; + dma_addr_t mbox_cpu_bus_dst; + volatile void *mbox_cpu_dst; + size_t dma_msg_size; + struct axon_dma_req_xfer_t dma_req_xfer = + AXON_DMA_REQ_XFER_INIT; + + + dma_msg_size = + MIN(p_dma_req_mbox->msg_size, + p_mbox->mbox_msg_max_size_get(p_mbox)); + + + memcpy(p_mbox_msg, p_dma_req_mbox->msg, dma_msg_size); + + + p_mbox->mbox_msg_alloc(p_mbox, &mbox_cpu_bus_dst, + &mbox_cpu_dst); + + + mbox_plb_bus_dst = + p_dma_req->p_addr_xltr->to_plb(p_dma_req->p_addr_xltr, + mbox_cpu_bus_dst); + + wmb(); + + + dma_req_xfer.src = p_dma_pkt->plb_bus_addr; + dma_req_xfer.dst = mbox_plb_bus_dst; + dma_req_xfer.size = dma_msg_size; + dma_req_xfer.intr = DMA_NO_INTR; + + ret = axon_dma_request_push_xfer(p_dma_req, &dma_req_xfer); + + if (ret >= 0) { + + volatile void *intr_cpu_dst; + plb_addr_t intr_plb_bus_dst; + u32 cookie; + + + + if (p_mbox->mbox_int_alloc(p_mbox, + &intr_plb_bus_dst, + &intr_cpu_dst, &cookie)) + { + + struct axon_dma_req_u32_t dma_req_u32 = + AXON_DMA_REQ_U32_INIT; + + dma_req_u32.dst = intr_plb_bus_dst; + dma_req_u32.data = cookie; + dma_req_u32.intr = DMA_NO_INTR; + + ret = + axon_dma_request_push_u32(p_dma_req, + &dma_req_u32); + if (ret < 0) { + dbg_err + ("Unable to push Immediate data for mailbox interrupt \n"); + } + } + } else { + dbg_err + ("Unable to push Remote mailbox request \n"); + } + } else { + dbg_err("Unable to allocate DMA packet for remote mbox\n"); + ret = -ENOMEM; + } + + return ret; + + +} + +int +axon_dma_request_push_mbox(struct axon_dma_req_t *p_dma_req, + struct axon_dma_req_mbox_t *p_dma_req_mbox) +{ + int ret = 0; + + + if (p_dma_req_mbox->p_dst_mbox == NULL) { + + switch (p_dma_req_mbox->dst_id) { + + case AXON_DMA_TARGET_SELF: + p_dma_req_mbox->p_dst_mbox = + p_dma_req->p_axon_dmax->p_axon_mbox_self; + break; + + case AXON_DMA_TARGET_PEER: + p_dma_req_mbox->p_dst_mbox = + p_dma_req->p_axon_dmax->p_axon_mbox_peer; + break; + default: + ret = -EINVAL; + dbg_err + ("Unspecified target mailbox while processing a DMA mailbox request \n"); + break; + + }; + } + + if (ret == 0 && (p_dma_req_mbox->p_dst_mbox != NULL)) { + + + if (p_dma_req->p_axon_dmax->p_dma_ops->mbox != NULL) { + + dbg_log + ("Inserting Mbox in DMA chain through dedicated command \n"); + + ret = + axon_dma_request_push_mbox_by_ops(p_dma_req, + p_dma_req_mbox); + } + + else { + + dbg_log + ("Inserting Mbox in DMA chain through generic write \n"); + ret = + axon_dma_request_push_mbox_by_write(p_dma_req, + p_dma_req_mbox); + } + } else { + dbg_err + ("Invalid mailbox object specified in a Push Mbox DMA request \n"); + } + + return ret; + +} + + + +static void +axon_dma_request_queue_to_dma(struct axon_dma_req_t *p_dma_req) +{ + + + spin_lock_bh(&p_dma_req->p_axon_dmax->lock); + + + if (p_dma_req->p_axon_dmax->p_last_dma_req == NULL) { + + dbg_log("Starting new DMA transfer 0x%p\n", p_dma_req); + + + dbg_log("Queueing DMA transfer 0x%p with pkt=%d in 0x%p\n", + p_dma_req, p_dma_req->first_pkt, + &(p_dma_req->pkts[p_dma_req->first_pkt])); + + p_dma_req->p_axon_dmax->p_dma_ops->queue(p_dma_req-> + p_axon_dmax-> + p_dma_ops, + &(p_dma_req-> + pkts[p_dma_req-> + first_pkt])); + + + + p_dma_req->p_axon_dmax->p_last_dma_req = p_dma_req; + + + dbg_log + ("Starting DMA transfer 0x%p with pkt=%d in 0x%p with addr=0x%p\n", + p_dma_req, p_dma_req->first_pkt, + &(p_dma_req->pkts[p_dma_req->first_pkt]), + p_dma_req->pkts[p_dma_req->first_pkt].addr); + p_dma_req->p_axon_dmax->p_dma_ops->start(p_dma_req-> + p_axon_dmax-> + p_dma_ops, + &(p_dma_req-> + pkts[p_dma_req-> + first_pkt])); + + } else { + + + if (p_dma_req->p_axon_dmax->p_dma_ops->resume != NULL) { + + struct axon_dma_pkt_t *p_dma_pkt_first_new_req; + struct axon_dma_pkt_t *p_dma_pkt_last_old_req; + + dbg_log("Resuming new DMA transfer 0x%p\n", + p_dma_req); + + axon_dma_request_pkt_cmd_first_get(p_dma_req, + &p_dma_pkt_first_new_req); + + + axon_dma_request_pkt_cmd_last_get(p_dma_req-> + p_axon_dmax-> + p_last_dma_req, + &p_dma_pkt_last_old_req); + + + + p_dma_req->p_axon_dmax->p_dma_ops->link(p_dma_req-> + p_axon_dmax-> + p_dma_ops, + p_dma_pkt_last_old_req, + p_dma_pkt_first_new_req); + + + p_dma_req->p_axon_dmax->p_last_dma_req = p_dma_req; + + + p_dma_req->p_axon_dmax->p_dma_ops-> + resume(p_dma_req->p_axon_dmax->p_dma_ops, + p_dma_pkt_first_new_req); + + } else { + + dbg_log + ("Queueing 0x%p (pkt=%d in 0x%p with addr=0x%p) for later processing (no resume DMA support) \n", + p_dma_req, p_dma_req->first_pkt, + &(p_dma_req->pkts[p_dma_req->first_pkt]), + p_dma_req->pkts[p_dma_req->first_pkt].addr); + + spin_lock_bh(&p_dma_req->p_axon_dmax->lock_lists); + + + list_add_tail(&p_dma_req->list, + &p_dma_req->p_axon_dmax-> + request_pending); + + spin_unlock_bh(&p_dma_req->p_axon_dmax-> + lock_lists); + } + + } + + spin_unlock_bh(&p_dma_req->p_axon_dmax->lock); + +} + +int +axon_dma_request_queue(struct axon_dma_req_t *p_dma_req, + axon_dma_completion_handler_t completion_handler, + void *context) +{ + int ret = 0; + struct axon_dma_req_mbox_t dma_req_mbox = AXON_DMA_REQ_MBOX_INIT; + struct axon_sms_t *p_axon_sms = p_dma_req->p_axon_dmax->p_axon_sms; + + struct axon_sms_msg_t self_msg; + u8 self_msg_encoded[AXON_SMS_SIZE]; + + + dbg_log("Queueing DMA request 0x%p\n", p_dma_req); + + + memcpy(self_msg.payload, &p_dma_req, sizeof(p_dma_req)); + self_msg.channel = AXON_SMS_CHANNEL_DMA_CPL; + + + ret = + axon_sms_encode(p_axon_sms, &self_msg, self_msg_encoded, 1, + AXON_SMS_SIZE); + if (ret >= 0) { + + dma_req_mbox.dst_id = AXON_DMA_TARGET_SELF; + dma_req_mbox.msg = self_msg_encoded; + dma_req_mbox.msg_size = AXON_SMS_SIZE; + + ret = axon_dma_request_push_mbox(p_dma_req, &dma_req_mbox); + + + if (ret >= 0) { + + + p_dma_req->completion_handler = completion_handler; + p_dma_req->completion_context = context; + + + axon_dma_request_queue_to_dma(p_dma_req); + + } else { + dbg_err + ("Unable to push self completion DMA request \n"); + } + + } else { + dbg_err + ("Unable to encode SMS for self notification DMA request \n"); + } + + return ret; + +} + +void +axon_dma_request_clear(struct axon_dma_req_t *p_dma_req) +{ + int i_pkt; + + dbg_log("Clearing DMA request 0x%p\n", p_dma_req); + + + for (i_pkt = 0; i_pkt < p_dma_req->current_pkt; i_pkt++) { + dma_pool_free(p_dma_req->p_dma_pool, + p_dma_req->pkts[i_pkt].addr, + p_dma_req->pkts[i_pkt].cpu_bus_addr); + } + + p_dma_req->current_pkt = 0; + p_dma_req->last_pkt = -1; + p_dma_req->first_pkt = -1; + p_dma_req->previous_last_pkt = -1; + + p_dma_req->completion_handler = NULL; + p_dma_req->completion_context = NULL; + +} + +void +axon_dma_request_destroy(struct axon_dma_req_t *p_dma_req) +{ + struct axon_dmax_t *p_axon_dmax = p_dma_req->p_axon_dmax; + + dbg_log("Destroying DMA request 0x%p\n", p_dma_req); + + axon_dma_request_clear(p_dma_req); + + spin_lock_bh(&p_axon_dmax->lock_lists); + + list_add_tail(&p_dma_req->list, + &p_dma_req->p_axon_dmax->requests_free); + + spin_unlock_bh(&p_axon_dmax->lock_lists); + + } + + + +static int +dmax_sms_handler(void *context, struct axon_sms_msg_t *p_msg) +{ + struct axon_dma_req_t *p_dma_req; + struct axon_dmax_t *p_axon_dmax = NULL; + + + memcpy(&p_dma_req, p_msg->payload, sizeof(p_dma_req)); + dbg_log("Receiving DMA completion for 0x%p\n", p_dma_req); + + + p_axon_dmax = p_dma_req->p_axon_dmax; + + + if (p_dma_req->completion_handler != NULL) { + p_dma_req->completion_handler(p_axon_dmax, p_dma_req, + p_dma_req-> + completion_context); + } + + + spin_lock_bh(&p_axon_dmax->lock); + + if (p_axon_dmax->p_last_dma_req == p_dma_req) { + p_axon_dmax->p_last_dma_req = NULL; + } + + + axon_dma_request_destroy(p_dma_req); + + + + spin_lock_bh(&p_axon_dmax->lock_lists); + + if (!list_empty(&p_axon_dmax->request_pending)) { + + + struct axon_dma_req_t *p_pending_dma_req = + list_entry(p_axon_dmax->request_pending.next, + struct axon_dma_req_t, + list); + + list_del(p_axon_dmax->request_pending.next); + + + spin_unlock_bh(&p_axon_dmax->lock_lists); + spin_unlock_bh(&p_axon_dmax->lock); + + + dbg_log("Resuming DMA request 0x%p\n", p_pending_dma_req); + + axon_dma_request_queue_to_dma(p_pending_dma_req); + + } else { + spin_unlock_bh(&p_axon_dmax->lock_lists); + spin_unlock_bh(&p_axon_dmax->lock); + } + + return 0; + +} + + +int +axon_dma_create(struct axon_t *p_axon, + struct axon_mbox_t *p_axon_mbox_self, + struct axon_mbox_t *p_axon_mbox_peer, + struct axon_sms_t *p_axon_sms, + struct addr_xltr_t *p_addr_xltr, + struct axon_dma_ops_t *p_dma_ops, + struct axon_dmax_t **pp_axon_dmax) +{ + + int ret = 0; + + struct axon_dmax_t *p_axon_dmax; + + + p_axon_dmax = kzalloc(sizeof(struct axon_dmax_t), GFP_KERNEL); + + if (p_axon_dmax != NULL) { + if (ret != 0) { + dbg_err + ("Wrong channel specified during DMA instance creation \n"); + goto err_dma_channel; + } + + if (p_axon != NULL) { + p_axon_dmax->p_axon = p_axon; + } else { + dbg_err + ("Invalid Axon handler in axon_dma_create \n"); + goto err_invalid_handle; + } + + if (p_axon != NULL) { + p_axon_dmax->p_axon_mbox_self = p_axon_mbox_self; + } else { + dbg_err + ("Invalid Self Mbox handler in axon_dma_create \n"); + goto err_invalid_handle; + } + if (p_axon != NULL) { + p_axon_dmax->p_axon_mbox_peer = p_axon_mbox_peer; + } else { + dbg_err + ("Invalid Peer Mbox handler in axon_dma_create \n"); + goto err_invalid_handle; + } + if (p_axon != NULL) { + p_axon_dmax->p_axon_sms = p_axon_sms; + } else { + dbg_err + ("Invalid SMS Axon handler in axon_dma_create \n"); + goto err_invalid_handle; + } + + if (p_axon != NULL) { + p_axon_dmax->p_dma_ops = p_dma_ops; + } else { + dbg_err + ("Invalid DMA ops handler in axon_dma_create \n"); + goto err_invalid_handle; + } + + + INIT_LIST_HEAD(&p_axon_dmax->requests_free); + INIT_LIST_HEAD(&p_axon_dmax->request_pending); + INIT_LIST_HEAD(&p_axon_dmax->request_processing); + + + p_axon_dmax->p_dma_pool = dma_pool_create(AXON_DRIVER_NAME, axon_get_device(p_axon_dmax->p_axon), DMAx_DESCRIPTOR_SIZE, DMAx_DESCRIPTOR_ALIGNEMENT, 0 + ); + + + p_axon_dmax->p_addr_xltr = p_addr_xltr; + + + p_axon_dmax->p_dma_ops->reset(p_axon_dmax->p_dma_ops); + + ret = axon_sms_subscribe(p_axon_dmax->p_axon_sms, + AXON_SMS_CHANNEL_DMA_CPL, + dmax_sms_handler, p_axon_dmax); + if (ret < 0) { + dbg_err + ("Unable to subscribe to the SMS service from the DMA engine \n"); + goto err_sms_subscribe; + } + + + p_axon_dmax->p_last_dma_req = NULL; + + spin_lock_init(&p_axon_dmax->lock); + spin_lock_init(&p_axon_dmax->lock_lists); + + ret = axon_dma_request_create_pool(p_axon_dmax, 128); + if (ret < 0) { + dbg_err + ("Unable to create initial DMA request pool \n"); + } + + + } else { + ret = -ENOMEM; + goto err_alloc; + } + + *pp_axon_dmax = p_axon_dmax; + goto no_err; + + + err_sms_subscribe: + + + err_invalid_handle: + err_dma_channel: + kfree(p_axon_dmax); + + err_alloc: + + + no_err: + + return ret; +} + +void +axon_dma_destroy(struct axon_dmax_t *p_axon_dmax) +{ + if (p_axon_dmax) { + axon_dma_request_destroy_pool(p_axon_dmax); + + axon_sms_unsubscribe(p_axon_dmax->p_axon_sms, + AXON_SMS_CHANNEL_DMA_CPL, + dmax_sms_handler); + + if (p_axon_dmax->p_dma_pool) + dma_pool_destroy(p_axon_dmax->p_dma_pool); + + kfree(p_axon_dmax); + } + +} + + +EXPORT_SYMBOL(axon_dma_request_create); +EXPORT_SYMBOL(axon_dma_request_push_xfer); +EXPORT_SYMBOL(axon_dma_request_push_u32); +EXPORT_SYMBOL(axon_dma_request_push_mbox); +EXPORT_SYMBOL(axon_dma_request_queue); +EXPORT_SYMBOL(axon_dma_request_clear); +EXPORT_SYMBOL(axon_dma_request_destroy); +EXPORT_SYMBOL(axon_dma_create); +EXPORT_SYMBOL(axon_dma_destroy); Index: linux/drivers/axon/common/axon_dmax_P.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/drivers/axon/common/axon_dmax_P.h 2006-12-19 17:53:10.000000000 +0100 @@ -0,0 +1,139 @@ +/****************************************************************** + * Copyright (C) 2006 Mercury Computer Systems, Inc. + * 199 Riverneck Road + * Chelmsford, MA 01824-2820 + * (978) 256-1300 + * webinfo@mc.com + * + * 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, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * http://www.gnu.org/copyleft/gpl.html + ******************************************************************/ + + +#ifndef AXON_DMAX_P_H +#define AXON_DMAX_P_H + +#include + +#include +#include +#include + + +struct axon_dma_req_t; + +struct axon_dmax_t { + + + struct addr_xltr_t *p_addr_xltr; + + + struct axon_t *p_axon; + + + struct axon_mbox_t *p_axon_mbox_self; + + + struct axon_mbox_t *p_axon_mbox_peer; + + + struct axon_sms_t *p_axon_sms; + + + int host_intr; + + + spinlock_t lock; + + struct axon_dma_req_t *p_last_dma_req; + + + volatile u8 *p_dma_channel; + + + struct axon_dma_ops_t *p_dma_ops; + + + struct dma_pool *p_dma_pool; + + + spinlock_t lock_lists; + + struct list_head requests_free; + + + struct list_head request_pending; + + + struct list_head request_processing; + +}; + + + +struct axon_dma_req_t { +#define MAX_CMD_PKT 128 + + struct axon_dmax_t *p_axon_dmax; + + + struct dma_pool *p_dma_pool; + + + struct axon_dma_pkt_t pkts[MAX_CMD_PKT]; + + + struct addr_xltr_t *p_addr_xltr; + + + + size_t pkt_size; + + + int current_pkt; + + + int last_pkt; + int previous_last_pkt; + + + int first_pkt; + + + volatile u8 *p_dma_channel; + + + struct list_head list; + + + axon_dma_completion_handler_t completion_handler; + void *completion_context; +}; + + +static inline struct addr_xltr_t * +dmax_addr_xltr_get(struct axon_dmax_t *p_axon_dma) +{ + return p_axon_dma->p_addr_xltr; +} + +static inline struct axon_t * +dmax_axon_get(struct axon_dmax_t *p_axon_dma) +{ + return p_axon_dma->p_axon; +} + +#endif Index: linux/drivers/axon/common/axon_mbox_hw.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/drivers/axon/common/axon_mbox_hw.c 2006-12-19 17:53:10.000000000 +0100 @@ -0,0 +1,626 @@ +/****************************************************************** + * Copyright (C) 2006 Mercury Computer Systems, Inc. + * 199 Riverneck Road + * Chelmsford, MA 01824-2820 + * (978) 256-1300 + * webinfo@mc.com + * + * 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, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * http://www.gnu.org/copyleft/gpl.html + ******************************************************************/ + + +#include +#include +#include +#include + +#include +#ifdef __powerpc__ +#include +#endif + +#include +#include +#include +#include +#include +#include + +static int axon_mbx_int_use_poll_mode = 0; + +module_param(axon_mbx_int_use_poll_mode, int, 0644); +MODULE_PARM_DESC(axon_mbx_int_use_poll_mode, + "This parameter allows to schedule a tasklet every 20 millisecond to check for any incomming mailbox. It does happen on early Axon that you will miss MBX insterrupts on the Cell if they are configured in indirect mode (through the MPIC). So this is usefull to work arround such hardware bugs. Default value is 0 except is indirect interrupt is requested on Cell. This parameter is only usefull on the Cell side."); + +static int axon_mbx_use_dir_int = 1; + +module_param(axon_mbx_use_dir_int, int, 0644); +MODULE_PARM_DESC(axon_mbx_use_dir_int, + "This parameter allows to choose if the Axon MBX will use direct or indirect (through MPIC) mode. By default the MBX interrupt will be configured in direct mode but you can select indirect by setting this parameter to 0. Note that for now if you select indirect mode, the polling mode will be automatically enabled. This parameter is only usefull on the Cell side."); + +static inline void +mbox_write_reg(struct axon_mbox_hw_t *p_mbox, u32 value, u32 dcr_addr) +{ + __raw_writel(value, (p_mbox->p_regs) + dcr_addr); + +} + +static inline u32 +mbox_read_reg(struct axon_mbox_hw_t *p_mbox, u32 dcr_addr) +{ + return __raw_readl((p_mbox->p_regs) + dcr_addr); + +} + + +int +mbox_hw_subscribe(struct axon_mbox_t *p_axon_mbox, + axon_mbox_handler_t handler, void *context) +{ + int ret = 0; + struct axon_mbox_hw_t *p_axon_mbox_hw = p_axon_mbox->context; + struct axon_mbox_subscriber_t *p_axon_mbox_subscriber; + + dbg_log("%s\n", __FUNCTION__); + + p_axon_mbox_subscriber = + kzalloc(sizeof(struct axon_mbox_subscriber_t), GFP_KERNEL); + + if (p_axon_mbox_subscriber != NULL) { + p_axon_mbox_subscriber->handler = handler; + p_axon_mbox_subscriber->context = context; + + list_add_tail(&p_axon_mbox_subscriber->list, + &p_axon_mbox_hw->subscriber_list); + + } else { + ret = -ENOMEM; + } + + + return ret; +} + +int +mbox_hw_unsubscribe(struct axon_mbox_t *p_axon_mbox, + axon_mbox_handler_t handler) +{ + int ret = -EINVAL; + + struct list_head *p_cursor; + struct list_head *p_next; + + struct axon_mbox_hw_t *p_axon_mbox_hw = p_axon_mbox->context; + struct axon_mbox_subscriber_t *p_subscriber; + + dbg_log("%s\n", __FUNCTION__); + + list_for_each_safe(p_cursor, p_next, + &p_axon_mbox_hw->subscriber_list) { + p_subscriber = + list_entry(p_cursor, struct axon_mbox_subscriber_t, + list); + + if ((p_subscriber->handler == handler)) { + list_del(p_cursor); + kfree(p_subscriber); + + ret = 0; + } + } + + return ret; +} + + +int +mbox_hw_msg_alloc(struct axon_mbox_t *p_axon_mbox, dma_addr_t * p_bus_addr, + volatile void **p_cpu_addr) +{ + struct axon_mbox_hw_t *p_axon_mbox_hw = + (struct axon_mbox_hw_t *) p_axon_mbox->context; + + dbg_log("%s\n", __FUNCTION__); + + *p_cpu_addr = axon_regs_mbox_get(p_axon_mbox_hw->p_axon); + + *p_bus_addr = p_axon_mbox_hw->mbox_bus_addr; + + return 0; +} + +void +mbox_hw_base_addr_set(struct axon_mbox_t *p_axon_mbox, + dma_addr_t mbox_base_addr, u32 mbox_size) +{ + dbg_log("%s\n", __FUNCTION__); + + + +} + +size_t +mbox_hw_msg_max_size_get(struct axon_mbox_t *p_axon_mbox) +{ + struct axon_mbox_hw_t *p_axon_mbox_hw = + (struct axon_mbox_hw_t *) p_axon_mbox->context; + + dbg_log("%s\n", __FUNCTION__); + + return p_axon_mbox_hw->ring_msg_size; + +} + +static int +mbox_hw_int_alloc(struct axon_mbox_t *p_axon_mbox, + plb_addr_t * p_intr_plb_addr, + volatile void **pp_intr_cpu_addr, u32 * p_cookie) +{ + struct axon_mbox_hw_t *p_axon_mbox_hw = + (struct axon_mbox_hw_t *) p_axon_mbox->context; + + dbg_log("%s\n", __FUNCTION__); + + + (void) p_axon_mbox_hw; + + + return 0; + +} + +static void +mbox_hw_reset(struct axon_mbox_t *p_axon_mbox) +{ + dbg_log("%s\n", __FUNCTION__); + + +} + +static u32 +mbox_hw_size_get(struct axon_mbox_t *p_axon_mbox) +{ + dbg_log("%s\n", __FUNCTION__); + + + return 0; +} + +static void +mbox_task_entry(unsigned long data) +{ + struct axon_mbox_t *p_axon_mbox = (struct axon_mbox_t *) data; + struct axon_mbox_hw_t *p_axon_mbox_hw = + (struct axon_mbox_hw_t *) p_axon_mbox->context; + + u8 msg[p_axon_mbox_hw->ring_msg_size]; + size_t msg_size = p_axon_mbox_hw->ring_msg_size; + + + u32 pop_message_count = 0x0; + u32 read_offset; + + dbg_log("Tasklet has received mbox message \n"); + + + while ((axon_ring_msg_pop(p_axon_mbox_hw->p_ring, msg, msg_size) == + 0)) { + struct list_head *p_cursor; + struct axon_mbox_subscriber_t *p_subscriber; + + dbg_log("Found one pending message onto the rings \n"); + + pop_message_count++; + + list_for_each(p_cursor, &p_axon_mbox_hw->subscriber_list) { + + p_subscriber = + list_entry(p_cursor, + struct axon_mbox_subscriber_t, + list); + + + dbg_log("Dispatching one message to 0x%p\n", + p_subscriber->handler); + + p_subscriber->handler(p_subscriber->context, msg, + msg_size); + } + } + + if (pop_message_count) { + + read_offset = axon_ring_offset_get(p_axon_mbox_hw->p_ring); + + dbg_log + ("Informing the hardware we are at 0x%08x byte offset \n", + read_offset); + read_offset = cpu_to_be32(read_offset); + mbox_write_reg(p_axon_mbox_hw, read_offset, + AXON_MBOX_READ_OFFSET); + dbg_log("Hardware informed \n"); + } +} + +static irqreturn_t +mbox_interrupt_handler(void *data, int irq, void *dev_id, + struct pt_regs *regs) +{ + struct axon_mbox_t *p_axon_mbox = (struct axon_mbox_t *) data; + struct axon_mbox_hw_t *p_axon_mbox_hw = + (struct axon_mbox_hw_t *) p_axon_mbox->context; + + dbg_log("%s\n", __FUNCTION__); + + tasklet_schedule(&p_axon_mbox_hw->mbox_task); + + + return IRQ_HANDLED; +} + +static irqreturn_t +mbox_overflow_handler(void *data, int irq, void *dev_id, + struct pt_regs *regs) +{ + struct axon_mbox_t *p_axon_mbox = (struct axon_mbox_t *) data; + struct axon_mbox_hw_t *p_axon_mbox_hw = + (struct axon_mbox_hw_t *) p_axon_mbox->context; + + dbg_err("Mailbox overflow \n"); + + return IRQ_HANDLED; +} + +static void +mbox_interrupt_poller(void *data) +{ + + int dummy; + struct axon_mbox_t *p_axon_mbox = (struct axon_mbox_t *) data; + struct axon_mbox_hw_t *p_axon_mbox_hw = + (struct axon_mbox_hw_t *) p_axon_mbox->context; + + + if (axon_ring_has_msg(p_axon_mbox_hw->p_ring, &dummy)) { + tasklet_schedule(&p_axon_mbox_hw->mbox_task); + } + + if (!queue_delayed_work(p_axon_mbox_hw->irq_poller_wq, &p_axon_mbox_hw->irq_poller, 20 * (HZ / 1000))) { + + dbg_err("Unable to Queue delayed work \n"); + } +} + +static void +axon_mbox_hw_init(struct axon_mbox_hw_t *p_mbox, size_t size_order) +{ + + dbg_log("%s\n", __FUNCTION__); + + + if ((size_order - 15) == AXON_MBOX_CR_SIZE_32K) { + + u32 cr = 0x0; + u64 ring_base_cpu_addr; + + dbg_log("Doing hardware mailbox init \n"); + + dbg_log("Mbox plb access hi addr was set to 0x%08x \n", + mbox_read_reg(p_mbox, + AXON_MBOX_ACCESS_REGION_ADDR_HI)); + dbg_log("Mbox plb access lo addr was set to 0x%08x \n", + mbox_read_reg(p_mbox, + AXON_MBOX_ACCESS_REGION_ADDR_LO)); + dbg_log("Mbox plb access mask hi was set to 0x%08x \n", + mbox_read_reg(p_mbox, + AXON_MBOX_ACCESS_REGION_MASK_HI)); + dbg_log("Mbox plb access mask lo was set to 0x%08x \n", + mbox_read_reg(p_mbox, + AXON_MBOX_ACCESS_REGION_MASK_LO)); + + + mbox_write_reg(p_mbox, + AXON_MBOX_DEFAULT_ACCESS_REGION_ADDR_HI, + AXON_MBOX_ACCESS_REGION_ADDR_HI); + mbox_write_reg(p_mbox, + AXON_MBOX_DEFAULT_ACCESS_REGION_ADDR_LO, + AXON_MBOX_ACCESS_REGION_ADDR_LO); + mbox_write_reg(p_mbox, + AXON_MBOX_DEFAULT_ACCESS_REGION_MASK_HI, + AXON_MBOX_ACCESS_REGION_MASK_HI); + mbox_write_reg(p_mbox, + AXON_MBOX_DEFAULT_ACCESS_REGION_MASK_LO, + AXON_MBOX_ACCESS_REGION_MASK_LO); + mbox_write_reg(p_mbox, + AXON_MBOX_DEFAULT_ACCESS_REGION_ADDR_HI, + AXON_MBOX_MESSAGE_ADDR_HI); + mbox_write_reg(p_mbox, + AXON_MBOX_DEFAULT_ACCESS_REGION_ADDR_LO, + AXON_MBOX_MESSAGE_ADDR_LO); + + dbg_log("Mbox plb access hi addr is set to 0x%08x \n", + mbox_read_reg(p_mbox, + AXON_MBOX_ACCESS_REGION_ADDR_HI)); + dbg_log("Mbox plb access lo addr is set to 0x%08x \n", + mbox_read_reg(p_mbox, + AXON_MBOX_ACCESS_REGION_ADDR_LO)); + dbg_log("Mbox plb access hi mask is set to 0x%08x \n", + mbox_read_reg(p_mbox, + AXON_MBOX_ACCESS_REGION_MASK_HI)); + dbg_log("Mbox plb access lo mask is set to 0x%08x \n", + mbox_read_reg(p_mbox, + AXON_MBOX_ACCESS_REGION_MASK_LO)); + + + ring_base_cpu_addr = axon_ring_base_get(p_mbox->p_ring); + dbg_log("Ring is located in 0x%016" AXON_U64_FMT_T " \n", + ring_base_cpu_addr); + + + dbg_log("Writing Ring address within the hardware \n"); + mbox_write_reg(p_mbox, + BE_HI32_FROM_BE64(ring_base_cpu_addr), + AXON_MBOX_BASE_ADDR_HI); + mbox_write_reg(p_mbox, + BE_LO32_FROM_BE64(ring_base_cpu_addr), + AXON_MBOX_BASE_ADDR_LO); + + + dbg_log("Init of the Read/write offset \n"); + mbox_write_reg(p_mbox, 0x0, AXON_MBOX_WRITE_OFFSET); + mbox_write_reg(p_mbox, (1 << size_order) - 1, + AXON_MBOX_READ_OFFSET); + + + cr = be32_set_bit_range(cr, AXON_MBOX_CR_SIZE_hi, + AXON_MBOX_CR_SIZE_lo, + AXON_MBOX_CR_SIZE_32K); + + + if (p_mbox->int_number == AXON_BEI_INTR_MBOX_DIRECT) + cr = be32_set_bit(cr, AXON_MBOX_CR_INTR_DIRECT); + else + cr = be32_set_bit(cr, AXON_MBOX_CR_INTR_INDIRECT); + + + cr = be32_set_bit(cr, AXON_MBOX_CR_EN); + + + dbg_log + ("Setting the mailbox configuration register to 0x%08x \n", + cr); + mbox_write_reg(p_mbox, cr, AXON_MBOX_CR); + + + } else { + dbg_err + ("Invalid mailbox size specified only 32K supported \n"); + } +} + +static void +axon_mbox_hw_cleanup(struct axon_mbox_hw_t *p_mbox) +{ + dbg_log("%s\n", __FUNCTION__); + + + mbox_write_reg(p_mbox, 0, AXON_MBOX_CR); + + + mbox_write_reg(p_mbox, AXON_MBOX_DISABLE_ACCESS_REGION_MASK_LO, + AXON_MBOX_ACCESS_REGION_MASK_LO); +} + +int +axon_mbox_hw_create(struct axon_t *p_axon, + struct addr_xltr_t *p_addr_xltr, + size_t size_order, dma_addr_t mbox_bus_addr, + struct axon_mbox_t *p_axon_mbox) +{ + int ret = 0; + + struct axon_mbox_hw_t *p_axon_mbox_hw; + + dbg_log("%s\n", __FUNCTION__); + + p_axon_mbox_hw = + kzalloc(sizeof(struct axon_mbox_hw_t), GFP_KERNEL); + + if (p_axon_mbox_hw == NULL) { + dbg_err + ("Unable to allocated memory for software mailbox \n"); + ret = -ENOMEM; + goto err_alloc_mbox; + } + + p_axon_mbox_hw->p_axon = p_axon; + + p_axon_mbox_hw->mbox_bus_addr = mbox_bus_addr; + + INIT_LIST_HEAD(&p_axon_mbox_hw->subscriber_list); + + p_axon_mbox->context = p_axon_mbox_hw; + + + if (size_order != 0) { + + + ret = + axon_ring_create(p_axon, size_order, 1, + &p_axon_mbox_hw->p_ring); + + if (ret < 0) { + dbg_err("Unable to create ring \n"); + goto err_ring_create; + } + + + p_axon_mbox_hw->ring_msg_size = + axon_ring_msg_max_size_get(p_axon_mbox_hw->p_ring); + + + p_axon_mbox_hw->p_regs = axon_regs_dcr_get(p_axon); + dbg_log("Caching DCR_regs located in 0x%p \n", + p_axon_mbox_hw->p_regs); + + + tasklet_init(&p_axon_mbox_hw->mbox_task, + mbox_task_entry, (unsigned long) p_axon_mbox); + + + if (axon_mbx_use_dir_int) { + printk(KERN_ERR "axon use direct INT\n"); + p_axon_mbox_hw->int_number = + AXON_BEI_INTR_MBOX_DIRECT; + } else { + printk(KERN_ERR "axon does not use direct INT\n"); + p_axon_mbox_hw->int_number = + AXON_BEI_INTR_MBOX_INDIRECT; + axon_mbx_int_use_poll_mode = 1; + } + + + ret = axon_register_irq_handler(p_axon, + p_axon_mbox_hw->int_number, + mbox_interrupt_handler, + axon_mbx_use_dir_int ? + "Axon HW_MBX_direct" : + "Axon HW_MBX_indirect", + p_axon_mbox); + + if (ret != 0) { + dbg_err + ("Unable to register Mailbox DMAx interrupt handler \n"); + goto err_register_irq_notif; + } + + ret = axon_register_irq_handler(p_axon, + AXON_BEI_INTR_MBOX_OVERFLOW, + mbox_overflow_handler, + "Axon HW_MBX_overflow", + p_axon_mbox); + + if (ret != 0) { + dbg_err + ("Unable to register Mailbox DMAx overflow handler \n"); + goto err_register_irq_overflow; + } + + if (axon_mbx_int_use_poll_mode) { + p_axon_mbox_hw->irq_poller_wq = + create_singlethread_workqueue("mbox_hw"); + INIT_WORK(&p_axon_mbox_hw->irq_poller, + mbox_interrupt_poller, p_axon_mbox); + PREPARE_WORK(&p_axon_mbox_hw->irq_poller, + mbox_interrupt_poller, p_axon_mbox); + + if (!queue_delayed_work(p_axon_mbox_hw->irq_poller_wq, &p_axon_mbox_hw->irq_poller, 20 * (HZ / 1000))) { + dbg_err("Unable to Queue delayed work \n"); + ret = -EBUSY; + goto err_queuing_poll_wq; + } else { + dbg_log("Polling Queue has started \n"); + } + } + + + axon_mbox_hw_init(p_axon_mbox_hw, size_order); + } else { + + p_axon_mbox_hw->ring_msg_size = 16; + } + + + p_axon_mbox->mbox_msg_max_size_get = mbox_hw_msg_max_size_get; + p_axon_mbox->mbox_msg_alloc = mbox_hw_msg_alloc; + p_axon_mbox->mbox_subscribe = mbox_hw_subscribe; + p_axon_mbox->mbox_unsubscribe = mbox_hw_unsubscribe; + p_axon_mbox->mbox_int_alloc = mbox_hw_int_alloc; + p_axon_mbox->mbox_base_addr_set = mbox_hw_base_addr_set; + p_axon_mbox->mbox_reset = mbox_hw_reset; + p_axon_mbox->mbox_size_get = mbox_hw_size_get; + + return ret; + + err_queuing_poll_wq: + if (axon_mbx_int_use_poll_mode) { + destroy_workqueue(p_axon_mbox_hw->irq_poller_wq); + p_axon_mbox_hw->irq_poller_wq = NULL; + } + + axon_unregister_irq_handler(p_axon_mbox_hw->p_axon, + AXON_BEI_INTR_MBOX_OVERFLOW, + mbox_overflow_handler); + + err_register_irq_overflow: + axon_unregister_irq_handler(p_axon_mbox_hw->p_axon, + p_axon_mbox_hw->int_number, + mbox_interrupt_handler); + + err_register_irq_notif: + if (p_axon_mbox_hw->p_ring != NULL) { + axon_ring_destroy(p_axon_mbox_hw->p_ring); + } + + err_ring_create: + kfree(p_axon_mbox_hw); + + err_alloc_mbox: + + + return ret; +} + +void +axon_mbox_hw_destroy(struct axon_mbox_t *p_axon_mbox) +{ + dbg_log("%s\n", __FUNCTION__); + + if (p_axon_mbox) { + struct axon_mbox_hw_t *p_axon_mbox_hw = + p_axon_mbox->context; + + + if (p_axon_mbox_hw && (p_axon_mbox_hw->p_ring != NULL)) { + if (p_axon_mbox_hw->irq_poller_wq) { + flush_workqueue(p_axon_mbox_hw-> + irq_poller_wq); + destroy_workqueue(p_axon_mbox_hw-> + irq_poller_wq); + p_axon_mbox_hw->irq_poller_wq = NULL; + } + + axon_unregister_irq_handler(p_axon_mbox_hw->p_axon, + AXON_BEI_INTR_MBOX_OVERFLOW, + mbox_overflow_handler); + + axon_unregister_irq_handler(p_axon_mbox_hw->p_axon, + p_axon_mbox_hw-> + int_number, + mbox_interrupt_handler); + + tasklet_kill(&p_axon_mbox_hw->mbox_task); + + axon_mbox_hw_cleanup(p_axon_mbox_hw); + + if (p_axon_mbox_hw->p_ring) + axon_ring_destroy(p_axon_mbox_hw->p_ring); + } + + kfree(p_axon_mbox_hw); + } +} Index: linux/drivers/axon/common/axon_mbox_sw.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/drivers/axon/common/axon_mbox_sw.c 2006-12-19 17:53:10.000000000 +0100 @@ -0,0 +1,492 @@ +/****************************************************************** + * Copyright (C) 2006 Mercury Computer Systems, Inc. + * 199 Riverneck Road + * Chelmsford, MA 01824-2820 + * (978) 256-1300 + * webinfo@mc.com + * + * 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, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * http://www.gnu.org/copyleft/gpl.html + ******************************************************************/ + + +#include + +#include +#include +#include +#include +#include +#include + + +#define RING_LOOK_AHEAD_WINDOW 4 + +int +mbox_sw_subscribe(struct axon_mbox_t *p_axon_mbox, + axon_mbox_handler_t handler, void *context) +{ + int ret = 0; + struct axon_mbox_sw_t *p_axon_mbox_sw = p_axon_mbox->context; + struct axon_mbox_subscriber_t *p_axon_mbox_subscriber; + + p_axon_mbox_subscriber = + kzalloc(sizeof(struct axon_mbox_subscriber_t), GFP_KERNEL); + + if (p_axon_mbox_subscriber != NULL) { + + p_axon_mbox_subscriber->handler = handler; + p_axon_mbox_subscriber->context = context; + + list_add_tail(&p_axon_mbox_subscriber->list, + &p_axon_mbox_sw->subscriber_list); + + } else { + ret = -ENOMEM; + } + + + return ret; + +} + +int +mbox_sw_unsubscribe(struct axon_mbox_t *p_axon_mbox, + axon_mbox_handler_t handler) +{ + int ret = -EINVAL; + + struct list_head *p_cursor; + struct list_head *p_next; + + struct axon_mbox_sw_t *p_axon_mbox_sw = p_axon_mbox->context; + struct axon_mbox_subscriber_t *p_subscriber; + + list_for_each_safe(p_cursor, p_next, + &p_axon_mbox_sw->subscriber_list) { + + p_subscriber = + list_entry(p_cursor, struct axon_mbox_subscriber_t, + list); + if ((p_subscriber->handler == handler)) { + + list_del(p_cursor); + kfree(p_subscriber); + + ret = 0; + } + + } + + return ret; + +} + + +int +mbox_sw_msg_alloc(struct axon_mbox_t *p_axon_mbox, dma_addr_t * p_bus_addr, + volatile void **p_cpu_addr) +{ + struct axon_mbox_sw_t *p_axon_mbox_sw = + (struct axon_mbox_sw_t *) p_axon_mbox->context; + + + if (p_axon_mbox_sw->p_ring_self != NULL) { + axon_ring_msg_alloc(p_axon_mbox_sw->p_ring_self, + p_bus_addr, (void **) p_cpu_addr); + } else { + if (atomic_read(&p_axon_mbox_sw->mbox_up) && + (p_axon_mbox_sw->mbox_base_cpu != NULL)) { + unsigned long flags; + + spin_lock_irqsave(&p_axon_mbox_sw->lock, flags); + + *p_bus_addr = p_axon_mbox_sw->mbox_next_addr; + *p_cpu_addr = p_axon_mbox_sw->mbox_base_cpu + + (p_axon_mbox_sw->mbox_next_addr - + p_axon_mbox_sw->mbox_base_addr); + + + p_axon_mbox_sw->mbox_next_addr += + p_axon_mbox_sw->ring_msg_size; + dbg_log + ("Setting next software shadow mbox pointer to 0x%" + AXON_DMA_ADDR_FMT_T "\n", + p_axon_mbox_sw->mbox_next_addr); + + + if (p_axon_mbox_sw->mbox_next_addr >= + (p_axon_mbox_sw->mbox_base_addr + + p_axon_mbox_sw->mbox_size)) { + dbg_log + ("Wrapping software shadow mbox pointer to 0x%" + AXON_DMA_ADDR_FMT_T "\n", + p_axon_mbox_sw->mbox_base_addr); + p_axon_mbox_sw->mbox_next_addr = + p_axon_mbox_sw->mbox_base_addr; + } + + spin_unlock_irqrestore(&p_axon_mbox_sw->lock, + flags); + + } else { + dbg_err + ("Trying to allocate message from Software shadow mailbox, but the information has not been received\n"); + return -1; + } + } + + return 0; +} + +static void +mbox_sw_mapper_wq(void *data) +{ + struct axon_mbox_sw_t *p_axon_mbox_sw = data; + + + if (p_axon_mbox_sw->type == AXON_MBOX_SHADOW) { + + + if (p_axon_mbox_sw->mbox_base_cpu != NULL) { + iounmap(p_axon_mbox_sw->mbox_base_cpu); + p_axon_mbox_sw->mbox_base_cpu = NULL; + } + + if (p_axon_mbox_sw->mbox_base_addr != 0) { + + p_axon_mbox_sw->mbox_base_cpu = + ioremap(p_axon_mbox_sw->mbox_base_addr, + p_axon_mbox_sw->mbox_size); + if (p_axon_mbox_sw->mbox_base_cpu == NULL) { + dbg_err + ("Unable to ioremap shadow mailbox for 0x%" + AXON_DMA_ADDR_FMT_T "\n", + p_axon_mbox_sw->mbox_base_addr); + } else { + dbg_log + ("Remote mailbox has been mapped into shadow mailbox in 0x%p \n", + p_axon_mbox_sw->mbox_base_cpu); + atomic_set(&p_axon_mbox_sw->mbox_up, 1); + } + } + + + } + +} + +void +mbox_sw_base_addr_set(struct axon_mbox_t *p_axon_mbox, + dma_addr_t mbox_base_addr, u32 mbox_size) +{ + + struct axon_mbox_sw_t *p_axon_mbox_sw = + (struct axon_mbox_sw_t *) p_axon_mbox->context; + + dbg_log("Setting Software Mailbox base to 0x%" AXON_DMA_ADDR_FMT_T + "\n", mbox_base_addr); + atomic_set(&p_axon_mbox_sw->mbox_up, 0); + + p_axon_mbox_sw->mbox_next_addr = mbox_base_addr; + p_axon_mbox_sw->mbox_base_addr = mbox_base_addr; + p_axon_mbox_sw->mbox_size = mbox_size; + + + if (p_axon_mbox_sw->type == AXON_MBOX_SHADOW) { + schedule_work(&p_axon_mbox_sw->mbox_mapper); + } + +} + +dma_addr_t +mbox_sw_base_addr_get(struct axon_mbox_t *p_axon_mbox) +{ + + struct axon_mbox_sw_t *p_axon_mbox_sw = + (struct axon_mbox_sw_t *) p_axon_mbox->context; + return axon_ring_base_get(p_axon_mbox_sw->p_ring_remote); + +} + + +size_t +mbox_sw_msg_max_size_get(struct axon_mbox_t * p_axon_mbox) +{ + struct axon_mbox_sw_t *p_axon_mbox_sw = + (struct axon_mbox_sw_t *) p_axon_mbox->context; + + return p_axon_mbox_sw->ring_msg_size; + +} + +static int +mbox_sw_int_alloc(struct axon_mbox_t *p_axon_mbox, + plb_addr_t * p_intr_plb_addr, + volatile void **pp_intr_cpu_addr, u32 * p_cookie) +{ + struct axon_mbox_sw_t *p_axon_mbox_sw = + (struct axon_mbox_sw_t *) p_axon_mbox->context; + + + (void) p_axon_mbox_sw; + + + *p_cookie = be32_set_bit(0, AXON_INTR_MBOX_DMA); + + + *p_intr_plb_addr = + __cpu_to_be64(AXON_PLB_UTL_REGS_OFFSET + UTL_ISSR); + + + + *pp_intr_cpu_addr = + axon_regs_utl_get(p_axon_mbox_sw->p_axon) + UTL_ISSR; + + + return 1; + +} + +static void +mbox_sw_reset(struct axon_mbox_t *p_axon_mbox) +{ + struct axon_mbox_sw_t *p_axon_mbox_sw = p_axon_mbox->context; + + + axon_ring_reset(p_axon_mbox_sw->p_ring_remote); +} + +static u32 +mbox_sw_size_get(struct axon_mbox_t *p_axon_mbox) +{ + struct axon_mbox_sw_t *p_axon_mbox_sw = p_axon_mbox->context; + + return p_axon_mbox_sw->mbox_size; +} + +static void +mbox_dma_task_entry(unsigned long data) +{ + struct axon_mbox_t *p_axon_mbox = (struct axon_mbox_t *) data; + struct axon_mbox_sw_t *p_axon_mbox_sw = + (struct axon_mbox_sw_t *) p_axon_mbox->context; + + u8 msg[p_axon_mbox_sw->ring_msg_size]; + size_t msg_size = p_axon_mbox_sw->ring_msg_size; + + + dbg_log("Tasklet has received mbox message \n"); + + + while ((axon_ring_msg_pop + (p_axon_mbox_sw->p_ring_self, msg, msg_size) == 0) + || + (axon_ring_msg_pop + (p_axon_mbox_sw->p_ring_remote, msg, msg_size) + == 0)) { + + struct list_head *p_cursor; + struct axon_mbox_subscriber_t *p_subscriber; + + dbg_log("Found one pending message onto the rings \n"); + + list_for_each(p_cursor, &p_axon_mbox_sw->subscriber_list) { + + p_subscriber = + list_entry(p_cursor, + struct axon_mbox_subscriber_t, + list); + + + dbg_log("Dispatching one message to 0x%p\n", + p_subscriber->handler); + + p_subscriber->handler(p_subscriber->context, msg, + msg_size); + + + } + } +} + +static irqreturn_t +mbox_dma_interrupt_handler(void *data, int irq, void *dev_id, + struct pt_regs *regs) +{ + struct axon_mbox_t *p_axon_mbox = (struct axon_mbox_t *) data; + struct axon_mbox_sw_t *p_axon_mbox_sw = + (struct axon_mbox_sw_t *) p_axon_mbox->context; + + tasklet_schedule(&p_axon_mbox_sw->mbox_dma_task); + + + + return IRQ_HANDLED; +} + + + +int +axon_mbox_sw_create(struct axon_t *p_axon, enum axon_mbox_type_t type, + struct addr_xltr_t *p_addr_xltr, size_t size_order, + struct axon_mbox_t *p_axon_mbox) +{ + + int ret = 0; + + struct axon_mbox_sw_t *p_axon_mbox_sw; + + p_axon_mbox_sw = + kzalloc(sizeof(struct axon_mbox_sw_t), GFP_KERNEL); + + if (p_axon_mbox_sw == NULL) { + dbg_err + ("Unable to allocated memory for software mailbox \n"); + ret = -ENOMEM; + goto err_alloc_mbox; + } + + atomic_set(&p_axon_mbox_sw->mbox_up, 0); + + p_axon_mbox_sw->p_axon = p_axon; + p_axon_mbox_sw->mbox_size = 1 << size_order; + p_axon_mbox_sw->p_addr_xltr = p_addr_xltr; + p_axon_mbox_sw->type = type; + + + if (p_axon_mbox_sw->type == AXON_MBOX_LOCAL) { + + + ret = + axon_ring_create(p_axon, size_order, 0, + &p_axon_mbox_sw->p_ring_self); + + if (ret < 0) { + dbg_err + ("Unable to create ring for self notification \n"); + goto err_ring_create_self; + } + + + p_axon_mbox_sw->ring_msg_size = + axon_ring_msg_max_size_get(p_axon_mbox_sw-> + p_ring_self); + + + ret = + axon_ring_create(p_axon, size_order, + RING_LOOK_AHEAD_WINDOW, + &p_axon_mbox_sw->p_ring_remote); + if (ret < 0) { + dbg_err + ("Unable to create ring for remote notification \n"); + goto err_ring_create_remote; + } + + + + tasklet_init(&p_axon_mbox_sw->mbox_dma_task, + mbox_dma_task_entry, + (unsigned long) p_axon_mbox); + + + ret = axon_register_irq_handler(p_axon, + AXON_INTR_MBOX_DMA, + mbox_dma_interrupt_handler, + "Axon Soft_MBX", + p_axon_mbox); + + if (ret != 0) { + dbg_err + ("Unable to register Mailbox DMAx interrupt handler \n"); + goto err_register_irq; + } + } else { + + p_axon_mbox_sw->ring_msg_size = 16; + p_axon_mbox_sw->mbox_base_cpu = NULL; + INIT_WORK(&p_axon_mbox_sw->mbox_mapper, mbox_sw_mapper_wq, + p_axon_mbox_sw); + } + + + + p_axon_mbox->mbox_msg_max_size_get = mbox_sw_msg_max_size_get; + p_axon_mbox->mbox_msg_alloc = mbox_sw_msg_alloc; + p_axon_mbox->mbox_subscribe = mbox_sw_subscribe; + p_axon_mbox->mbox_unsubscribe = mbox_sw_unsubscribe; + p_axon_mbox->mbox_int_alloc = mbox_sw_int_alloc; + p_axon_mbox->mbox_base_addr_set = mbox_sw_base_addr_set; + p_axon_mbox->mbox_reset = mbox_sw_reset; + p_axon_mbox->mbox_size_get = mbox_sw_size_get; + + INIT_LIST_HEAD(&p_axon_mbox_sw->subscriber_list); + + spin_lock_init(&p_axon_mbox_sw->lock); + + p_axon_mbox->context = p_axon_mbox_sw; + + goto no_err; + + + err_register_irq: + axon_ring_destroy(p_axon_mbox_sw->p_ring_remote); + + err_ring_create_remote: + axon_ring_destroy(p_axon_mbox_sw->p_ring_self); + + err_ring_create_self: + kfree(p_axon_mbox_sw); + + err_alloc_mbox: + + + no_err: + + return ret; + +} + +void +axon_mbox_sw_destroy(struct axon_mbox_t *p_axon_mbox) +{ + struct axon_mbox_sw_t *p_axon_mbox_sw = p_axon_mbox->context; + + if (p_axon_mbox_sw->type == AXON_MBOX_LOCAL) { + axon_unregister_irq_handler(p_axon_mbox_sw->p_axon, + AXON_INTR_MBOX_DMA, + mbox_dma_interrupt_handler); + + tasklet_kill(&p_axon_mbox_sw->mbox_dma_task); + + if (p_axon_mbox_sw->p_ring_remote != NULL) { + axon_ring_destroy(p_axon_mbox_sw->p_ring_remote); + } + + if (p_axon_mbox_sw->p_ring_self != NULL) { + axon_ring_destroy(p_axon_mbox_sw->p_ring_self); + } + } else { + flush_scheduled_work(); + + if (p_axon_mbox_sw->mbox_base_cpu != NULL) { + iounmap(p_axon_mbox_sw->mbox_base_cpu); + } + } + + kfree(p_axon_mbox_sw); +} Index: linux/drivers/axon/common/axon_pio_pci.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/drivers/axon/common/axon_pio_pci.c 2006-12-19 17:53:10.000000000 +0100 @@ -0,0 +1,322 @@ +/****************************************************************** + * Copyright (C) 2006 Mercury Computer Systems, Inc. + * 199 Riverneck Road + * Chelmsford, MA 01824-2820 + * (978) 256-1300 + * webinfo@mc.com + * + * 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, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * http://www.gnu.org/copyleft/gpl.html + ******************************************************************/ + + +#include +#include +#include +#include +#include + +static int +map_on_local_bus(struct axon_pio_pci_t *p_axon_pio_pci, plb_addr_t dst, + dma_addr_t * p_bus_addr, size_t size) +{ + int ret = 0; + + dma_addr_t dst_bus_addr; + + + if (p_axon_pio_pci->p_pim != NULL) { + + axon_pim_map(p_axon_pio_pci->p_pim, dst, size); + } + + + + dst_bus_addr = + p_axon_pio_pci->p_addr_xltr->from_plb(p_axon_pio_pci-> + p_addr_xltr, dst); + + + if (dst_bus_addr != AXON_INVALID_BUS_ADDR) { + + *p_bus_addr = dst_bus_addr; + + } else { + + ret = -EIO; + dbg_log("Unable to find an existing PCI address for 0x%016" + AXON_PLB_ADDR_FMT_T " \n", dst); + *p_bus_addr = 0x0; + } + + return ret; + +} + +static void * +do_ioremap(struct axon_pio_pci_t *p_axon_pio_pci, plb_addr_t dst, + size_t size) +{ + int ret = 0; + + dma_addr_t dst_bus_addr; + void *dst_cpu_addr = NULL; + + + ret = map_on_local_bus(p_axon_pio_pci, dst, &dst_bus_addr, size); + + if (ret == 0) { + + + dst_cpu_addr = ioremap(dst_bus_addr, size); + + } + + return dst_cpu_addr; +} + +static void +do_iounmap(struct axon_pio_pci_t *p_axon_pio_pci, plb_addr_t dst, + void *dst_cpu) +{ + + if (p_axon_pio_pci->p_pim != NULL) { + + axon_pim_unmap(p_axon_pio_pci->p_pim, dst); + } + + iounmap(dst_cpu); + +} + + +#define AXON_READ(size,type) \ +static int \ +axon_pio_pci_read##type(struct axon_pio_t* p_axon_pio, plb_addr_t src, u##size * p_data) \ +{ \ + int ret = 0; \ + struct axon_pio_pci_t* p_axon_pio_pci = p_axon_pio -> context; \ + void* src_cpu_addr; \ + \ + \ + src_cpu_addr = do_ioremap( p_axon_pio_pci, src, size / 8); \ + if ( src_cpu_addr != NULL ) { \ +\ + *p_data = read##type( src_cpu_addr ); \ +\ + do_iounmap( p_axon_pio_pci, src, src_cpu_addr ); \ +\ + } else {\ + dbg_err("Unable to map IO space located on the bus 0x%p(%lld bytes) \n", src_cpu_addr, (unsigned long long)size / 8);\ + ret = -EIO;\ + }\ +\ + return ret;\ +} + +AXON_READ(8, b) AXON_READ(16, w) AXON_READ(32, l) + +#if BITS_PER_LONG > 32 + AXON_READ(64, q) +#endif +#define AXON_WRITE(size, type) \ +static int \ +axon_pio_pci_write##type(struct axon_pio_t* p_axon_pio, plb_addr_t dst, u##size data) \ +{ \ + int ret = 0; \ + struct axon_pio_pci_t* p_axon_pio_pci = p_axon_pio -> context; \ + void* dst_cpu_addr; \ + \ + \ + dst_cpu_addr = do_ioremap( p_axon_pio_pci, dst, size / 8); \ + if ( dst_cpu_addr != NULL ) { \ +\ + write##type( data, dst_cpu_addr ); \ +\ + do_iounmap( p_axon_pio_pci, dst, dst_cpu_addr ); \ +\ + } else {\ + dbg_err("Unable to map IO space located on the bus 0x%p(%lld bytes) \n", dst_cpu_addr, (unsigned long long)size / 8);\ + ret = -EIO;\ + }\ +\ + return ret;\ +} + AXON_WRITE(8, b) AXON_WRITE(16, w) AXON_WRITE(32, l) + +#if BITS_PER_LONG > 32 + AXON_WRITE(64, q) +#endif + static int + + + + + + + + + + + + + + + + axon_pio_pci_memcpy_toio(struct axon_pio_t *p_axon_pio, + plb_addr_t dst, void *src, size_t size) +{ + int ret = 0; + struct axon_pio_pci_t *p_axon_pio_pci = p_axon_pio->context; + + void *dst_cpu_addr; + + + dst_cpu_addr = do_ioremap(p_axon_pio_pci, dst, size); + if (dst_cpu_addr != NULL) { + + memcpy_toio(dst_cpu_addr, src, size); + + do_iounmap(p_axon_pio_pci, dst, dst_cpu_addr); + + } else { + dbg_err("Unable to map IO space located on the bus 0x%016" + AXON_PLB_ADDR_FMT_T "(%zd bytes) \n", dst, size); + ret = -EIO; + } + + return ret; + +} + +static int +axon_pio_pci_memcpy_fromio(struct axon_pio_t *p_axon_pio, void *dst, + plb_addr_t src, size_t size) +{ + int ret = 0; + struct axon_pio_pci_t *p_axon_pio_pci = p_axon_pio->context; + + void *src_cpu_addr; + + + src_cpu_addr = do_ioremap(p_axon_pio_pci, src, size); + if (src_cpu_addr != NULL) { + + memcpy_fromio(dst, src_cpu_addr, size); + + do_iounmap(p_axon_pio_pci, src, src_cpu_addr); + + } else { + dbg_err("Unable to map IO space located on the bus 0x%016" + AXON_PLB_ADDR_FMT_T "(%zd bytes) \n", src, size); + ret = -EIO; + } + + return ret; +} + + +int +axon_pio_pci_create(struct axon_t *p_axon, struct axon_pim_t *p_pim, + struct axon_pio_t **pp_axon_pio) +{ + int ret = 0; + + struct axon_pio_t *p_axon_pio; + struct axon_pio_pci_t *p_axon_pio_pci; + + p_axon_pio = kzalloc(sizeof(struct axon_pio_t), GFP_KERNEL); + if (p_axon_pio == NULL) { + ret = -ENOMEM; + dbg_err("Unable to allocated axon_pio_t \n"); + goto err_alloc_pio; + } + + p_axon_pio_pci = + kzalloc(sizeof(struct axon_pio_pci_t), GFP_KERNEL); + if (p_axon_pio_pci == NULL) { + ret = -ENOMEM; + dbg_err("Unable to allocated axon_pio_pci_t \n"); + goto err_alloc_pio_pci; + } + + + p_axon_pio->context = p_axon_pio_pci; + + + + p_axon_pio_pci->p_addr_xltr = axon_addr_xltr_get(p_axon); + + p_axon_pio_pci->p_axon = p_axon; + + p_axon_pio_pci->p_pim = p_pim; + + p_axon_pio->writeb = axon_pio_pci_writeb; + p_axon_pio->writes = axon_pio_pci_writew; + p_axon_pio->writel = axon_pio_pci_writel; +#if BITS_PER_LONG > 32 + p_axon_pio->writeq = axon_pio_pci_writeq; +#else + p_axon_pio->writeq = NULL; +#endif + + p_axon_pio->readb = axon_pio_pci_readb; + p_axon_pio->reads = axon_pio_pci_readw; + p_axon_pio->readl = axon_pio_pci_readl; +#if BITS_PER_LONG > 32 + p_axon_pio->readq = axon_pio_pci_readq; +#else + p_axon_pio->readq = NULL; +#endif + + p_axon_pio->copy_toio = axon_pio_pci_memcpy_toio; + p_axon_pio->copy_fromio = axon_pio_pci_memcpy_fromio; + + + + *pp_axon_pio = p_axon_pio; + + goto no_err; + + err_alloc_pio_pci: + kfree(p_axon_pio); + + err_alloc_pio: + + + no_err: + + return ret; +} + + +void +axon_pio_pci_destroy(struct axon_pio_t *p_axon_pio) +{ + if (p_axon_pio) { + struct axon_pio_pci_t *p_axon_pio_pci = + p_axon_pio->context; + + + if (p_axon_pio_pci) + kfree(p_axon_pio_pci); + + kfree(p_axon_pio); + } + + + +} Index: linux/drivers/axon/common/axon_ring.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/drivers/axon/common/axon_ring.c 2006-12-19 17:53:10.000000000 +0100 @@ -0,0 +1,473 @@ +/****************************************************************** + * Copyright (C) 2006 Mercury Computer Systems, Inc. + * 199 Riverneck Road + * Chelmsford, MA 01824-2820 + * (978) 256-1300 + * webinfo@mc.com + * + * 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, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * http://www.gnu.org/copyleft/gpl.html + ******************************************************************/ + + +#include +#include +#include +#include +#include +#include + +#define AXON_RING_MSG_ORDER 4 +#define AXON_RING_MSG_SIZE (1 << AXON_RING_MSG_ORDER ) + +#define WRAP(idx) ( (idx) & p_axon_ring -> msg_wrap_mask ) + +static inline void * +axon_ring_msg_idx_to_cpu(struct axon_ring_t *p_axon_ring, unsigned int idx) +{ + return (WRAP(idx) << AXON_RING_MSG_ORDER) + p_axon_ring->msg_base; +} + +#if defined(AXON_DEBUG_RING) +static void +dump_bitmap(struct axon_ring_t *p_axon_ring) +{ + int i_bit; + char buffer[128]; + char *buf_tmp = buffer; + + for (i_bit = 0; i_bit < sizeof(buffer) / 2 - 1; i_bit++) { + if (test_bit(i_bit, p_axon_ring->msg_bitmap)) { + buf_tmp += sprintf(buf_tmp, "1:"); + } else { + buf_tmp += sprintf(buf_tmp, "0:"); + } + + } + dbg_log("Ring 0x%p bitmap(0x%p): %s \n", p_axon_ring, + p_axon_ring->msg_bitmap, buffer); + +} +#endif + + +inline void +axon_ring_msg_alloc(struct axon_ring_t *p_axon_ring, + dma_addr_t * p_bus_addr, void **pp_cpu_addr) +{ + + unsigned int free_msg_index; + unsigned long free_msg_offset; + + + free_msg_index = + ((unsigned int) atomic_inc_return(&p_axon_ring->msg_free_idx)) + - 1; + + + set_bit(WRAP(free_msg_index), p_axon_ring->msg_bitmap); + + + free_msg_index &= p_axon_ring->msg_wrap_mask; + + + free_msg_offset = free_msg_index << AXON_RING_MSG_ORDER; + + + + *p_bus_addr = p_axon_ring->msg_base_cpu_bus_addr + free_msg_offset; + + + *pp_cpu_addr = p_axon_ring->msg_base + free_msg_offset; + + dbg_log + ("Ring 0x%p: allocating message idx=0x%08x cpu=0x%p, bus=0x%p \n", + p_axon_ring, free_msg_index, *pp_cpu_addr, + (void *) (*p_bus_addr)); + +# if defined(AXON_DEBUG_RING) + dump_bitmap(p_axon_ring); +# endif + +} + +size_t +axon_ring_msg_max_size_get(struct axon_ring_t *p_axon_ring) +{ + return p_axon_ring->msg_size; +} + + +u32 +axon_ring_offset_get(struct axon_ring_t * p_axon_ring) +{ + return (atomic_read(&p_axon_ring->msg_current_idx) & p_axon_ring-> + msg_wrap_mask) << AXON_RING_MSG_ORDER; +} + +static inline int +__axon_ring_has_msg(struct axon_ring_t *p_axon_ring, int *found_idx) +{ + unsigned int current_idx, + free_idx, + idx; + + + int second_scan = 0; + + + current_idx = + (unsigned int) atomic_read(&p_axon_ring->msg_current_idx); + free_idx = (unsigned int) atomic_read(&p_axon_ring->msg_free_idx); + + idx = current_idx; + + dbg_log + ("Ring 0x%p: starting search for message from 0x%08x to 0x%08x \n", + p_axon_ring, current_idx, free_idx); + + + while (idx != free_idx) { + u8 *msg = + (u8 *) axon_ring_msg_idx_to_cpu(p_axon_ring, idx); + + dbg_log("Ring 0x%p: idx=0x%08x(@ 0x%p) contains 0x%02x \n", + p_axon_ring, idx, msg, *msg); + + + if (*msg != p_axon_ring->null_pattern) { + + if (idx == current_idx || second_scan) { + dbg_log + ("Ring 0x%p: found one message in 0x%08x \n", + p_axon_ring, idx); + *found_idx = idx; + return 1; + + } else { + + idx = current_idx; + second_scan = 1; + } + + } else { + + idx++; + } + + } + + dbg_log("Ring 0x%p: no message found \n", p_axon_ring); + + return 0; +} + + +int +axon_ring_has_msg(struct axon_ring_t *p_axon_ring, int *found_idx) +{ + return __axon_ring_has_msg(p_axon_ring, found_idx); +} + + +int +axon_ring_msg_pop(struct axon_ring_t *p_axon_ring, void *msg, + size_t msg_size) +{ + int ret = 0; + int msg_idx; + + + + if (__axon_ring_has_msg(p_axon_ring, &msg_idx)) { + +# if defined(AXON_DEBUG_RING) + dump_bitmap(p_axon_ring); +# endif + if (test_and_clear_bit + (WRAP(msg_idx), p_axon_ring->msg_bitmap)) { + + u8 *ring_msg = + (u8 *) axon_ring_msg_idx_to_cpu(p_axon_ring, + msg_idx); + + dbg_log + ("Ring 0x%p: Msg idx=0x%08x markes as free\n", + p_axon_ring, msg_idx); + + + + if (p_axon_ring->look_ahead_window) { + dma_addr_t dummy_bus_add; + void *dummy_cpu_addr; + + dbg_log + ("Ring 0x%p: Keeping LookAhead window by pre-allocating a message\n", + p_axon_ring); + axon_ring_msg_alloc(p_axon_ring, + &dummy_bus_add, + &dummy_cpu_addr); + } + + + memcpy(msg, ring_msg, msg_size); + + + *((u64 *) ring_msg) = + *((u64 *) p_axon_ring->p_null_word); + *((u64 *) ring_msg + 1) = + *((u64 *) p_axon_ring->p_null_word + 1); + + + if (msg_idx == + atomic_read(&p_axon_ring->msg_current_idx)) { + + dbg_log + ("Ring 0x%p: Trying to free from watermark set at idx=0x%08x\n", + p_axon_ring, msg_idx); + + do { + msg_idx++; + + } + while (test_bit + (WRAP(msg_idx), + p_axon_ring->msg_bitmap) == 0 + && (msg_idx != + atomic_read(&p_axon_ring-> + msg_free_idx))); + + atomic_set(&p_axon_ring->msg_current_idx, + msg_idx); + dbg_log + ("Ring 0x%p: New watermark set at idx=0x%08x\n", + p_axon_ring, msg_idx); + } + + } else { + dbg_log + ("Ring 0x%p: Concurrent access. Giving up!\n", + p_axon_ring); +# if defined(AXON_DEBUG_RING) + dump_bitmap(p_axon_ring); +# endif + ret = -EAGAIN; + } + } else { + + dbg_log("Ring 0x%p: no message pending in 0x%08x \n", + p_axon_ring, + atomic_read(&p_axon_ring->msg_current_idx)); + ret = -EAGAIN; + } + + return ret; +} + +dma_addr_t +axon_ring_base_get(struct axon_ring_t * p_axon_ring) +{ + return p_axon_ring->msg_base_cpu_bus_addr; +} + +static void * +axon_ring_map_nocache(struct axon_ring_t *p_axon_ring) +{ + return p_axon_ring->msg_base = + (void *) ioremap(p_axon_ring->msg_base_cpu_bus_addr, + p_axon_ring->size); +} + +static void +axon_ring_unmap(struct axon_ring_t *p_axon_ring) +{ + iounmap(p_axon_ring->msg_base); + p_axon_ring->msg_base = NULL; +} + +int +axon_ring_create(struct axon_t *p_axon, size_t size_order, + size_t look_ahead_window, + struct axon_ring_t **pp_axon_ring) +{ + int ret = 0; + struct axon_ring_t *p_axon_ring; + + p_axon_ring = kzalloc(sizeof(struct axon_ring_t), GFP_KERNEL); + + if (p_axon_ring != NULL) { + p_axon_ring->p_axon = p_axon; + + + p_axon_ring->size_order = size_order; + p_axon_ring->size = (1 << p_axon_ring->size_order); + + p_axon_ring->msg_size = AXON_RING_MSG_SIZE; + p_axon_ring->null_pattern = 0xFF; + + p_axon_ring->p_null_word = + kzalloc(p_axon_ring->msg_size, GFP_KERNEL); + if (p_axon_ring->p_null_word == NULL) { + ret = -ENOMEM; + goto err_alloc; + } + + + p_axon_ring->msg_bitmap = + kzalloc((p_axon_ring->size / p_axon_ring->msg_size), + GFP_KERNEL); + + if (p_axon_ring->msg_bitmap == NULL) { + ret = -ENOMEM; + goto err_alloc; + } + + + atomic_set(&p_axon_ring->msg_free_idx, 0); + atomic_set(&p_axon_ring->msg_current_idx, 0); + + p_axon_ring->look_ahead_window = look_ahead_window; + + + p_axon_ring->msg_wrap_mask = + (1 << (p_axon_ring->size_order - AXON_RING_MSG_ORDER)) + - 1; + dbg_log("Ring wrap mask set to 0x%08x \n", + p_axon_ring->msg_wrap_mask); + + spin_lock_init(&p_axon_ring->lock); + + p_axon_ring->msg_virtual = + dma_alloc_coherent(axon_get_device(p_axon), + p_axon_ring->size, + &p_axon_ring->msg_base_cpu_bus_addr, + GFP_KERNEL); + + if (p_axon_ring->msg_virtual == NULL) { + ret = -ENOMEM; + goto err_alloc; + } + + dbg_log("Ring allocated in CPU=0x%p BUS=0x%016" + AXON_DMA_ADDR_FMT_T " \n", + p_axon_ring->msg_virtual, + p_axon_ring->msg_base_cpu_bus_addr); + + if (axon_ring_map_nocache(p_axon_ring) == NULL) { + ret = -ENOMEM; + goto err_alloc; + } + dbg_log("Ring mapped as non-cacheable in CPU=0x%p \n", + p_axon_ring->msg_base); + + axon_ring_reset(p_axon_ring); + } else { + ret = -ENOMEM; + goto err_alloc; + } + + *pp_axon_ring = p_axon_ring; + + goto no_err; + + + + err_alloc: + axon_ring_destroy(p_axon_ring); + + no_err: + + return ret; + +} + +void +axon_ring_destroy(struct axon_ring_t *p_axon_ring) +{ + if (p_axon_ring) { + if (p_axon_ring->msg_base) + axon_ring_unmap(p_axon_ring); + + if (p_axon_ring->msg_virtual) + dma_free_coherent(axon_get_device + (p_axon_ring->p_axon), + p_axon_ring->size, + p_axon_ring->msg_virtual, + p_axon_ring-> + msg_base_cpu_bus_addr); + + if (p_axon_ring->p_null_word) + kfree(p_axon_ring->p_null_word); + + + atomic_set(&p_axon_ring->msg_free_idx, -1); + atomic_set(&p_axon_ring->msg_current_idx, -1); + + p_axon_ring->size = 0; + p_axon_ring->msg_size = 0; + p_axon_ring->msg_base = 0; + p_axon_ring->msg_virtual = 0; + p_axon_ring->msg_base_cpu_bus_addr = 0; + p_axon_ring->p_null_word = 0; + kfree(p_axon_ring); + } +} + +void +axon_ring_reset(struct axon_ring_t *p_axon_ring) +{ + + if (p_axon_ring) { + unsigned long flags; + int look_ahead_idx; + + + spin_lock_irqsave(&p_axon_ring->lock, flags); + + dbg_log("Ring 0x%p is being reset \n", p_axon_ring); + + p_axon_ring->msg_next = p_axon_ring->msg_base; + + atomic_set(&p_axon_ring->msg_free_idx, 0); + atomic_set(&p_axon_ring->msg_current_idx, 0); + + + if (p_axon_ring->msg_base) + memset(p_axon_ring->msg_base, + p_axon_ring->null_pattern, + p_axon_ring->size); + if (p_axon_ring->p_null_word) + memset(p_axon_ring->p_null_word, + p_axon_ring->null_pattern, + p_axon_ring->msg_size); + if (p_axon_ring->msg_bitmap) + memset(p_axon_ring->msg_bitmap, 0, + (p_axon_ring->size / + p_axon_ring->msg_size)); + + for (look_ahead_idx = 0; + look_ahead_idx < p_axon_ring->look_ahead_window; + look_ahead_idx++) { + + dma_addr_t dummy_bus_add; + void *dummy_cpu_addr; + + axon_ring_msg_alloc(p_axon_ring, &dummy_bus_add, + &dummy_cpu_addr); + } + spin_unlock_irqrestore(&p_axon_ring->lock, flags); + } +} Index: linux/drivers/axon/common/axon_ring_P.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/drivers/axon/common/axon_ring_P.h 2006-12-19 17:53:10.000000000 +0100 @@ -0,0 +1,76 @@ +/****************************************************************** + * Copyright (C) 2006 Mercury Computer Systems, Inc. + * 199 Riverneck Road + * Chelmsford, MA 01824-2820 + * (978) 256-1300 + * webinfo@mc.com + * + * 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, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * http://www.gnu.org/copyleft/gpl.html + ******************************************************************/ + + +#ifndef AXON_MBOX_RING_H +#define AXON_MBOX_RING_H + + +#include + +#include + +struct axon_ring_t { + + struct axon_t *p_axon; + + size_t size_order; + size_t size; + + void *msg_virtual; + + void *msg_base; + + dma_addr_t msg_base_cpu_bus_addr; + + void *msg_next; + + + void *msg_bitmap; + + + atomic_t msg_current_idx; + + + atomic_t msg_free_idx; + + + unsigned int msg_wrap_mask; + + + size_t msg_size; + + + u8 *p_null_word; + u8 null_pattern; + + spinlock_t lock; + + + size_t look_ahead_window; + +}; + + +#endif Index: linux/drivers/axon/common/axon_sms.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/drivers/axon/common/axon_sms.c 2006-12-19 17:53:10.000000000 +0100 @@ -0,0 +1,654 @@ +/****************************************************************** + * Copyright (C) 2006 Mercury Computer Systems, Inc. + * 199 Riverneck Road + * Chelmsford, MA 01824-2820 + * (978) 256-1300 + * webinfo@mc.com + * + * 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, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * http://www.gnu.org/copyleft/gpl.html + ******************************************************************/ + + +#include + +#include +#include +#include +#include +#include + + +int +axon_sms_subscribe(struct axon_sms_t *p_axon_sms, int channel, + axon_sms_handler_t handler, void *context) +{ + int ret = 0; + struct axon_sms_subscriber_t *p_axon_sms_subscriber; + + struct list_head *p_cursor; + struct list_head *p_next; + + + list_for_each_safe(p_cursor, p_next, &p_axon_sms->subscriber_list) { + + p_axon_sms_subscriber = + list_entry(p_cursor, struct axon_sms_subscriber_t, + list); + if ((p_axon_sms_subscriber->channel == channel) + && (p_axon_sms_subscriber->handler == handler)) { + + dbg_err + ("SMS subscribe: handler 0x%p already registered on channel %d \n", + handler, channel); + return -EINVAL; + } + } + + p_axon_sms_subscriber = + kzalloc(sizeof(struct axon_sms_subscriber_t), GFP_KERNEL); + + if (p_axon_sms_subscriber != NULL) { + p_axon_sms_subscriber->handler = handler; + p_axon_sms_subscriber->context = context; + p_axon_sms_subscriber->channel = channel; + + dbg_log("New SMS subscriber 0x%p on channel %d \n", + handler, channel); + list_add_tail(&p_axon_sms_subscriber->list, + &p_axon_sms->subscriber_list); + + } else { + ret = -ENOMEM; + } + + return ret; +} + +int +axon_sms_unsubscribe(struct axon_sms_t *p_axon_sms, int channel, + axon_sms_handler_t handler) +{ + int ret = -EINVAL; + + struct list_head *p_cursor; + struct list_head *p_next; + + struct axon_sms_subscriber_t *p_subscriber; + + list_for_each_safe(p_cursor, p_next, &p_axon_sms->subscriber_list) { + + p_subscriber = + list_entry(p_cursor, struct axon_sms_subscriber_t, + list); + if ((p_subscriber->channel == channel) + && (p_subscriber->handler == handler)) { + + dbg_log + ("SMS unsubscribe from 0x%p on channel %d \n", + handler, channel); + list_del(p_cursor); + kfree(p_subscriber); + + ret = 0; + } + + } + + return ret; + +} + +#if defined(AXON_DEBUG_MODULE) || defined(AXON_DEBUG) +static void +print_fragment(u8 * p_fragment, size_t size_fragment) +{ + char store[128]; + char *buffer = store; + int is_fragmented; + size_t i_size; + + is_fragmented = + p_fragment[AXON_SMS_CHANNEL_BYTE] & AXON_SMS_FRAGMENTED_BIT; + + if (is_fragmented) { + buffer += sprintf(buffer, "F"); + } else { + buffer += sprintf(buffer, "."); + } + buffer += + sprintf(buffer, ":C=%02x", + p_fragment[AXON_SMS_CHANNEL_BYTE] & + AXON_SMS_CHANNEL_MASK); + + if (is_fragmented) { + + if (p_fragment[AXON_SMS_FRAGMENT_BYTE] & + AXON_SMS_FRAGMENT_END) { + buffer += sprintf(buffer, ":E"); + } else { + buffer += sprintf(buffer, ":."); + } + + i_size = AXON_SMS_FRAGMENTED_PAYLOAD_BYTE; + buffer += + sprintf(buffer, ":S=%1x", + p_fragment[AXON_SMS_FRAGMENT_BYTE] & + AXON_SMS_FRAGMENT_PAYLOAD_SIZE_MASK); + + } else { + + buffer += sprintf(buffer, ":."); + buffer += sprintf(buffer, ":S=%1x", 0xF); + i_size = AXON_SMS_PAYLOAD_BYTE; + } + + buffer += sprintf(buffer, ":D="); + while (i_size < size_fragment) { + buffer += sprintf(buffer, "%02x", p_fragment[i_size]); + i_size++; + } + + dbg_log("Frag=%s\n", store); +} +#else +#define print_fragment(a, b) do { } while(0); +#endif + +static void +print_msg(struct axon_sms_msg_t *p_msg) +{ + char store[128]; + char *buffer = store; + int i_byte; + + buffer += sprintf(buffer, "Channel=%d Payload=", p_msg->channel); + for (i_byte = 0; i_byte < AXON_SMS_PAYLOAD_SIZE; i_byte++) { + buffer += + sprintf(buffer, "%02x:", + (unsigned char) p_msg->payload[i_byte]); + } + dbg_log("SMS is: %s\n", store); + + +} + +int +axon_sms_encode(struct axon_sms_t *p_axon_sms, + struct axon_sms_msg_t *p_msg, + u8 * p_fragments, u8 nb_fragments, u8 size_fragments) +{ + int ret = 0; + + int i_byte = 0; + u8 *p_fragment; + int i_fragment = 0; + + + + if (nb_fragments == 1) { + + p_fragment = p_fragments; + + dbg_log("SMS encoding message on one fragment \n"); + if (size_fragments >= p_axon_sms->mbox_msg_size) { + + + p_fragment[AXON_SMS_CHANNEL_BYTE] = + (p_msg-> + channel & AXON_SMS_CHANNEL_MASK) & + (~AXON_SMS_FRAGMENTED_BIT); + memcpy(&(p_fragment[AXON_SMS_PAYLOAD_BYTE]), + p_msg->payload, AXON_SMS_PAYLOAD_SIZE); + + + print_fragment(p_fragment, size_fragments); + + } else { + dbg_err + ("Not enough room available for encoding SMS into one fragments \n"); + ret = -EINVAL; + } + + } else { + + + int max_fragment_payload_size = + size_fragments - AXON_SMS_FRAGMENT_HEADER_SIZE; + + dbg_log("SMS encoding message on %d fragments \n", + nb_fragments); + + + ret = -EINVAL; + + + + while ((i_byte < AXON_SMS_PAYLOAD_SIZE) + && (i_fragment < nb_fragments)) { + + + int fragment_payload_size = + MIN(max_fragment_payload_size, + (AXON_SMS_PAYLOAD_SIZE - i_byte)); + + + p_fragment = + p_fragments + (i_fragment * size_fragments); + + + p_fragment[AXON_SMS_CHANNEL_BYTE] = + (p_msg-> + channel & AXON_SMS_CHANNEL_MASK) | + AXON_SMS_FRAGMENTED_BIT; + + + p_fragment[AXON_SMS_FRAGMENT_BYTE] = + fragment_payload_size & + AXON_SMS_FRAGMENT_PAYLOAD_SIZE_MASK; + + + if (i_byte + max_fragment_payload_size > + AXON_SMS_PAYLOAD_SIZE) { + + p_fragment[AXON_SMS_FRAGMENT_BYTE] |= + AXON_SMS_FRAGMENT_END; + + + ret = 0; + } + + memcpy(& + (p_fragment + [AXON_SMS_FRAGMENTED_PAYLOAD_BYTE]), + &(p_msg->payload[i_byte]), + fragment_payload_size); + + + i_byte += max_fragment_payload_size; + i_fragment++; + + + print_fragment(p_fragment, size_fragments); + + } + } + + return ret; + +} + +static u8 +axon_sms_decode(struct axon_sms_t *p_axon_sms, u8 * msg, + struct axon_sms_msg_t *p_decoded_msg) +{ + + struct axon_msg_fragment_t *p_fragment; + int size_payload; + + + + p_decoded_msg->channel = + msg[AXON_SMS_CHANNEL_BYTE] & AXON_SMS_CHANNEL_MASK; + + + if (msg[AXON_SMS_CHANNEL_BYTE] & AXON_SMS_FRAGMENTED_BIT) { + + + + size_payload = + msg[AXON_SMS_FRAGMENT_BYTE] & + AXON_SMS_FRAGMENT_PAYLOAD_SIZE_MASK; + + + + p_fragment = + &(p_axon_sms->p_msg_fragments[p_decoded_msg->channel]); + + dbg_log + ("Decoding fragmented message of %d byte to be stored in 0x%p (channel=%u)\n", + size_payload, p_fragment, p_decoded_msg->channel); + + + print_fragment(msg, p_axon_sms->mbox_msg_size); + + + if (size_payload + p_fragment->free_byte < + p_axon_sms->mbox_msg_size) { + + + memcpy(& + (p_fragment->p_data[p_fragment->free_byte]), + &(msg[AXON_SMS_FRAGMENTED_PAYLOAD_BYTE]), + size_payload); + + p_fragment->free_byte += size_payload; + + } else { + + dbg_err + ("Fragment Overflown has been detected on channel %d (stored=%d, fragment=%d) \n", + p_decoded_msg->channel, p_fragment->free_byte, + size_payload); + dbg_err("Discarding message \n"); + + p_fragment->free_byte = 0; + + } + + + if (msg[AXON_SMS_FRAGMENT_BYTE] & AXON_SMS_FRAGMENT_END) { + + dbg_log("End of fragment detected \n"); + + + memcpy(p_decoded_msg->payload, + p_fragment->p_data, + p_axon_sms->mbox_msg_size - + AXON_SMS_CHANNEL_SIZE); + + + memset(p_fragment->p_data, 0, + p_axon_sms->mbox_msg_size); + p_fragment->free_byte = 0; + + dbg_log + ("Fragmented message has been reconstituted \n"); + print_msg(p_decoded_msg); + + + + } else { + p_decoded_msg->channel = + AXON_SMS_CHANNEL_FRAGMENTED; + + } + + + + } else { + + + print_fragment(msg, p_axon_sms->mbox_msg_size); + + memcpy(p_decoded_msg->payload, + &(msg[AXON_SMS_PAYLOAD_BYTE]), + p_axon_sms->mbox_msg_size - AXON_SMS_CHANNEL_SIZE); + + p_decoded_msg->channel = + msg[AXON_SMS_CHANNEL_BYTE] & AXON_SMS_CHANNEL_MASK; + } + + + + return p_decoded_msg->channel; + +} + +static void +sms_mbox_dispatch(void *context, u8 * msg, size_t msg_size) +{ + struct axon_sms_t *p_axon_sms = (struct axon_sms_t *) context; + + struct list_head *p_cursor; + struct axon_sms_subscriber_t *p_subscriber; + + + struct axon_sms_msg_t decoded_msg; + + dbg_log("SMS service has received mailbox(es)\n"); + + + if (axon_sms_decode(p_axon_sms, msg, &decoded_msg) != + AXON_SMS_CHANNEL_FRAGMENTED) { + + dbg_log("Looking for subscriber to channel %d\n", + decoded_msg.channel); + + list_for_each(p_cursor, &p_axon_sms->subscriber_list) { + + p_subscriber = + list_entry(p_cursor, + struct axon_sms_subscriber_t, list); + + if (decoded_msg.channel == p_subscriber->channel) { + + dbg_log + ("Dispatching one message to 0x%p\n", + p_subscriber->handler); + + p_subscriber->handler(p_subscriber-> + context, + &decoded_msg); + + } + + + } + } +} + + +int +axon_sms_send(struct axon_sms_t *p_axon_sms, + struct axon_mbox_t *p_mbox_dst, struct axon_sms_msg_t *p_msg) +{ + int ret = 0; + + unsigned long flags; + + + u8 nb_fragments = + (AXON_SMS_PAYLOAD_SIZE / + (p_axon_sms->max_atomic_write - + AXON_SMS_FRAGMENT_HEADER_SIZE)) + + ((AXON_SMS_PAYLOAD_SIZE % + (p_axon_sms->max_atomic_write - + AXON_SMS_FRAGMENT_HEADER_SIZE) != 0) ? 1 : 0); + + u8 p_msg_fragment[nb_fragments * + p_axon_sms->max_atomic_write]; + int i_fragment; + + dma_addr_t mbox_bus_addr; + volatile void *mbox_cpu_addr; + + plb_addr_t intr_plb_addr; + volatile void *intr_cpu_addr; + u32 cookie; + + + dbg_log("Asking to encode SMS on %u fragment(s) of %d bytes\n", + nb_fragments, p_axon_sms->max_atomic_write); + ret = + axon_sms_encode(p_axon_sms, p_msg, p_msg_fragment, + nb_fragments, p_axon_sms->max_atomic_write); + + if (ret == 0) { + + + dbg_log("Sending SMS \n"); + print_msg(p_msg); + + + spin_lock_irqsave(&p_axon_sms->lock_send, flags); + + for (i_fragment = 0; i_fragment < nb_fragments; + i_fragment++) { + + + ret = + p_mbox_dst->mbox_msg_alloc(p_mbox_dst, + &mbox_bus_addr, + &mbox_cpu_addr); + if (ret == -1) { + + break; + } + + + + AXON_SMS_MAX_ATOMIC_WRITE(* + (AXON_SMS_MAX_ATOMIC_TYPE + *) +(p_msg_fragment + (i_fragment * p_axon_sms->max_atomic_write)), +mbox_cpu_addr); + + } + + + if (ret == 0) { + + if (p_mbox_dst-> + mbox_int_alloc(p_mbox_dst, &intr_plb_addr, + &intr_cpu_addr, &cookie)) { + + + axon_writel(cookie, intr_cpu_addr); + } + } + + spin_unlock_irqrestore(&p_axon_sms->lock_send, flags); + + } else { + dbg_err("Unable to encode SMS message \n"); + } + + return ret; + + +} + +int +axon_sms_create(struct axon_t *p_axon, + struct axon_pio_t *p_pio, + struct axon_mbox_t *p_mbox_self, + struct axon_sms_t **pp_axon_sms) +{ + int ret = 0; + struct axon_sms_t *p_axon_sms; + int i_channel; + + p_axon_sms = kzalloc(sizeof(struct axon_sms_t), GFP_KERNEL); + if (p_axon_sms == NULL) { + dbg_err("Unable to allocate SMS object \n"); + ret = -ENOMEM; + goto err_alloc_sms; + } + + p_axon_sms->channel_nr = AXON_SMS_CHANNEL_NR; + p_axon_sms->mbox_msg_size = + p_mbox_self->mbox_msg_max_size_get(p_mbox_self); + + + p_axon_sms->fragment_store_size = + (p_axon_sms->channel_nr) * (p_axon_sms->mbox_msg_size) * + sizeof(*p_axon_sms->p_fragment_store); + + p_axon_sms->p_fragment_store = + kzalloc(p_axon_sms->fragment_store_size, GFP_KERNEL); + if (p_axon_sms->p_fragment_store == NULL) { + dbg_err + ("Unable to allocate storage for fragmented message \n"); + ret = -ENOMEM; + goto err_alloc_fragmented; + } + + p_axon_sms->p_msg_fragments = + kzalloc((p_axon_sms->channel_nr) * + sizeof(struct axon_msg_fragment_t), GFP_KERNEL); + if (p_axon_sms->p_msg_fragments == NULL) { + dbg_err("Unable to allocate fragmented messages \n"); + ret = -ENOMEM; + goto err_alloc_msg_fragments; + } + + + for (i_channel = 0; i_channel < p_axon_sms->channel_nr; + i_channel++) { + p_axon_sms->p_msg_fragments[i_channel].p_data = + p_axon_sms->p_fragment_store + + (i_channel * (p_axon_sms->mbox_msg_size)); + p_axon_sms->p_msg_fragments[i_channel].free_byte = 0; + } + + p_axon_sms->p_pio = p_pio; + if (p_pio->writeq == NULL) { + p_axon_sms->max_atomic_write = 4; + } else { + p_axon_sms->max_atomic_write = 8; + } + + + p_axon_sms->p_mbox_self = p_mbox_self; + p_axon_sms->p_mbox_self->mbox_subscribe(p_axon_sms->p_mbox_self, + sms_mbox_dispatch, + p_axon_sms); + + spin_lock_init(&p_axon_sms->lock_send); + + INIT_LIST_HEAD(&p_axon_sms->subscriber_list); + + + *pp_axon_sms = p_axon_sms; + + return ret; + + err_alloc_msg_fragments: + kfree(p_axon_sms->p_fragment_store); + + err_alloc_fragmented: + kfree(p_axon_sms); + + err_alloc_sms: + + + return ret; +} + + +void +axon_sms_destroy(struct axon_sms_t *p_axon_sms) +{ + if (p_axon_sms) { + p_axon_sms->p_mbox_self->mbox_unsubscribe(p_axon_sms-> + p_mbox_self, + sms_mbox_dispatch); + + if (p_axon_sms->p_msg_fragments) + kfree(p_axon_sms->p_msg_fragments); + + if (p_axon_sms->p_fragment_store) + kfree(p_axon_sms->p_fragment_store); + + kfree(p_axon_sms); + } +} + +void +axon_sms_reset(struct axon_sms_t *p_axon_sms) +{ + p_axon_sms->p_mbox_self->mbox_reset(p_axon_sms->p_mbox_self); +} + + +EXPORT_SYMBOL(axon_sms_subscribe); +EXPORT_SYMBOL(axon_sms_unsubscribe); +EXPORT_SYMBOL(axon_sms_encode); +EXPORT_SYMBOL(axon_sms_send); +EXPORT_SYMBOL(axon_sms_create); +EXPORT_SYMBOL(axon_sms_destroy); +EXPORT_SYMBOL(axon_sms_reset); Index: linux/drivers/axon/common/axon_sys.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/drivers/axon/common/axon_sys.c 2006-12-19 17:53:10.000000000 +0100 @@ -0,0 +1,363 @@ +/****************************************************************** + * Copyright (C) 2006 Mercury Computer Systems, Inc. + * 199 Riverneck Road + * Chelmsford, MA 01824-2820 + * (978) 256-1300 + * webinfo@mc.com + * + * 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, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * http://www.gnu.org/copyleft/gpl.html + ******************************************************************/ + + +#include + +#include +#include +#include +#include +#include +#include +#include + +static int +is_status_up(struct axon_sys_t *p_axon_sys) +{ + dbg_log("%s\n", __FUNCTION__); + + return __raw_readl(p_axon_sys->p_scratchpad + + AXON_SYS_SCHPAD_BOOT) == + be32_to_cpu(AXON_SYS_RUNNING); + +} + +static void +set_status_up(struct axon_sys_t *p_axon_sys) +{ + u32 issr; + + dbg_log("%s\n", __FUNCTION__); + + __raw_writel(cpu_to_be32(AXON_SYS_RUNNING), + p_axon_sys->p_scratchpad + AXON_SYS_SCHPAD_BOOT); + wmb(); + + + issr = be32_set_bit(0x0, AXON_INTR_SYS); + __raw_writel(issr, p_axon_sys->p_regs_utl + UTL_ISSR); + wmb(); + +} + +static void +set_status_down(struct axon_sys_t *p_axon_sys) +{ + dbg_log("%s\n", __FUNCTION__); + + __raw_writel(0, p_axon_sys->p_scratchpad + AXON_SYS_SCHPAD_BOOT); + wmb(); +} + +static void +recv_mbox_addr(struct axon_sys_t *p_axon_sys, struct axon_sms_msg_t *p_msg) +{ + struct addr_xltr_t *p_xltr = + axon_addr_xltr_get(p_axon_sys->p_axon); + u32 mbox_size; + dma_addr_t mbox_base_bus_addr; + + dbg_log("%s\n", __FUNCTION__); + + + memcpy(&p_axon_sys->mbox_base_plb_addr, p_msg->payload + 1, + sizeof(p_axon_sys->mbox_base_plb_addr)); + + + mbox_base_bus_addr = + p_xltr->from_plb(p_xltr, p_axon_sys->mbox_base_plb_addr); + + + memcpy(&mbox_size, p_msg->payload + 9, sizeof(mbox_size)); + + + p_axon_sys->p_peer_mbox->mbox_base_addr_set(p_axon_sys-> + p_peer_mbox, + mbox_base_bus_addr, + be32_to_cpu + (mbox_size)); +} + + +static void +unset_mbox_addr(struct axon_sys_t *p_axon_sys, + struct axon_sms_msg_t *p_msg) +{ + dbg_log("%s\n", __FUNCTION__); + + p_axon_sys->mbox_base_plb_addr = 0; + + + p_axon_sys->p_peer_mbox->mbox_base_addr_set(p_axon_sys-> + p_peer_mbox, 0, 0); +} + +static int +send_mbox_addr(struct axon_sys_t *p_axon_sys) +{ + int ret = 0; + + dbg_log("Sending local mailbox information to the remote \n"); + + + if (is_status_up(p_axon_sys)) { + + struct axon_sms_msg_t msg; + u32 mbox_size; + + + msg.channel = AXON_SMS_CHANNEL_SYSTEM; + msg.payload[0] = AXON_SYS_CHN_MBOX_ADDR_SET; + + memcpy(msg.payload + 1, &p_axon_sys->mbox_base_plb_addr, + sizeof(p_axon_sys->mbox_base_plb_addr)); + + mbox_size = + cpu_to_be32(p_axon_sys->p_axon_sms->p_mbox_self-> + mbox_size_get(p_axon_sys->p_axon_sms-> + p_mbox_self)); + memcpy(msg.payload + 9, &mbox_size, sizeof(mbox_size)); + + + axon_sms_reset(p_axon_sys->p_axon_sms); + + ret = + axon_sms_send(p_axon_sys->p_axon_sms, + p_axon_sys->p_peer_mbox, &msg); + + if (ret < 0) { + dbg_err + ("Unable to send Mbox address in System Service \n"); + } + } else { + dbg_log + ("Mailbox information is deferred as the remote is not up \n"); + } + + return ret; +} + +static int +reset_mbox_addr(struct axon_sys_t *p_axon_sys) +{ + int ret = 0; + + dbg_log("Reseting local mailbox information to the remote \n"); + + + if (is_status_up(p_axon_sys)) { + struct axon_sms_msg_t msg; + + + msg.channel = AXON_SMS_CHANNEL_SYSTEM; + msg.payload[0] = AXON_SYS_CHN_MBOX_ADDR_UNSET; + + ret = + axon_sms_send(p_axon_sys->p_axon_sms, + p_axon_sys->p_peer_mbox, &msg); + + if (ret < 0) { + dbg_err + ("Unable to send Reset address in System Service \n"); + } + } else { + dbg_log + ("Mailbox information reset is deferred as the remote is not up \n"); + } + + return ret; +} + +static irqreturn_t +sys_int_handler(void *data, int irq, void *dev_id, struct pt_regs *regs) +{ + struct axon_sys_t *p_axon_sys = data; + + dbg_log("%s\n", __FUNCTION__); + + + send_mbox_addr(p_axon_sys); + + return IRQ_HANDLED; +} + +static int +sys_sms_handler(void *context, struct axon_sms_msg_t *p_msg) +{ + int ret = 0; + struct axon_sys_t *p_axon_sys = context; + + dbg_log("%s\n", __FUNCTION__); + + switch (p_msg->payload[0]) { + + + case AXON_SYS_CHN_MBOX_ADDR_GET: + send_mbox_addr(p_axon_sys); + break; + + case AXON_SYS_CHN_MBOX_ADDR_UNSET: + unset_mbox_addr(p_axon_sys, p_msg); + break; + + case AXON_SYS_CHN_MBOX_ADDR_SET: + recv_mbox_addr(p_axon_sys, p_msg); + break; + + default: + dbg_err + ("Unexpected message received by System service %d \n", + p_msg->payload[0]); + ret = -EINVAL; + break; + + }; + + return ret; +} + + +int +axon_sys_create(struct axon_t *p_axon, + struct axon_sms_t *p_axon_sms, + plb_addr_t mbox_base_addr, + enum axon_sys_type_t type, + struct axon_mbox_t *p_peer_mbox, + struct axon_sys_t **pp_axon_sys) +{ + int ret = 0; + + struct axon_sys_t *p_axon_sys; + + *pp_axon_sys = NULL; + + dbg_log("%s\n", __FUNCTION__); + + p_axon_sys = kzalloc(sizeof(struct axon_sys_t), GFP_KERNEL); + + if (p_axon_sys != NULL) { + + p_axon_sys->p_axon = p_axon; + p_axon_sys->p_scratchpad = axon_regs_c3po_get(p_axon) + + AXON_SCRATCHPAD_REGS_OFFSET; + + p_axon_sys->p_regs_utl = axon_regs_utl_get(p_axon); + + p_axon_sys->p_axon_sms = p_axon_sms; + + p_axon_sys->mbox_base_plb_addr = mbox_base_addr; + + p_axon_sys->p_peer_mbox = p_peer_mbox; + + p_axon_sys->type = type; + + + ret = axon_sms_subscribe(p_axon_sys->p_axon_sms, + AXON_SMS_CHANNEL_SYSTEM, + sys_sms_handler, p_axon_sys); + + + if (ret < 0) { + dbg_err + ("unable to register for SYS SMS channel \n"); + goto do_kfree; + } else { + + if (type == AXON_SYS_HOST) { + + ret = + axon_register_irq_handler(p_axon_sys-> + p_axon, + AXON_INTR_SYS, + sys_int_handler, + "Axon Sys", + p_axon_sys); + + if (ret >= 0) { + send_mbox_addr(p_axon_sys); + } else { + dbg_err + ("Unable to register System interrupt \n"); + goto do_unsubscribe_sms; + } + + + } else if (type == AXON_SYS_NODE) { + + set_status_up(p_axon_sys); + } else { + dbg_err("Invalid type in sys service \n"); + ret = -EINVAL; + goto do_unsubscribe_sms; + } + + *pp_axon_sys = p_axon_sys; + } + } else { + dbg_err + ("Unable to allocate memory for Axon System service \n"); + ret = -ENOMEM; + } + + return ret; + + do_unsubscribe_sms: + axon_sms_unsubscribe(p_axon_sys->p_axon_sms, + AXON_SMS_CHANNEL_SYSTEM, sys_sms_handler); + + do_kfree: + kfree(p_axon_sys); + + return ret; +} + +void +axon_sys_destroy(struct axon_sys_t *p_axon_sys) +{ + dbg_log("%s\n", __FUNCTION__); + + if (p_axon_sys) { + axon_sms_unsubscribe(p_axon_sys->p_axon_sms, + AXON_SMS_CHANNEL_SYSTEM, + sys_sms_handler); + + if (p_axon_sys->type == AXON_SYS_HOST) { + + reset_mbox_addr(p_axon_sys); + + + + + axon_unregister_irq_handler(p_axon_sys->p_axon, + AXON_INTR_SYS, + sys_int_handler); + } else { + + set_status_down(p_axon_sys); + } + + kfree(p_axon_sys); + } +} Index: linux/drivers/axon/include/axon.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/drivers/axon/include/axon.h 2006-12-19 17:53:10.000000000 +0100 @@ -0,0 +1,96 @@ +/****************************************************************** + * Copyright (C) 2006 Mercury Computer Systems, Inc. + * 199 Riverneck Road + * Chelmsford, MA 01824-2820 + * (978) 256-1300 + * webinfo@mc.com + * + * 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, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * http://www.gnu.org/copyleft/gpl.html + ******************************************************************/ + + +#ifndef AXON_H +#define AXON_H + +#include +#include + +#include +#include +#include + + +struct axon_dmax_t; +struct axon_mbox_t; +struct axon_addr_xltr_t; + + +struct axon_t { + void *context; +}; + + + +typedef irqreturn_t(*axon_irq_handler_t) (void *axon_data, + int irq, void *dev_id, + struct pt_regs * regs); + + +struct device *axon_get_device(struct axon_t *p_axon); + + +int axon_register_irq_handler(struct axon_t *p_axon, + int irq_nr, + axon_irq_handler_t handler, + char *name, void *data); +int axon_unregister_irq_handler(struct axon_t *p_axon, + int irq_nr, + axon_irq_handler_t handler); + + + +volatile u8 *axon_regs_dmax_get(struct axon_t *p_axon); +volatile u8 *axon_regs_dma_aux_get(struct axon_t *p_axon); +volatile u8 *axon_regs_c3po_get(struct axon_t *p_axon); +volatile u8 *axon_regs_mbox_get(struct axon_t *p_axon); +volatile u8 *axon_regs_utl_get(struct axon_t *p_axon); +volatile u8 *axon_regs_dcr_get(struct axon_t *p_axon); +volatile u8 *axon_regs_pci_cfg_get(struct axon_t *p_axon); + + + +int axon_board_count(void); + + +struct axon_t **axon_board_list(void); + + + +struct axon_dmax_t *axon_dmax_get(struct axon_t *p_axon); + + +struct axon_mbox_t *axon_mbox_get(struct axon_t *p_axon); + +struct axon_mbox_t *axon_peer_mbox_get(struct axon_t *p_axon); + +struct addr_xltr_t *axon_addr_xltr_get(struct axon_t *p_axon); + +struct axon_pio_t *axon_pio_get(struct axon_t *p_axon); + +struct axon_sms_t *axon_sms_get(struct axon_t *p_axon); + +#endif Index: linux/drivers/axon/include/axon_addr_xltr.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/drivers/axon/include/axon_addr_xltr.h 2006-12-19 17:53:10.000000000 +0100 @@ -0,0 +1,79 @@ +/****************************************************************** + * Copyright (C) 2006 Mercury Computer Systems, Inc. + * 199 Riverneck Road + * Chelmsford, MA 01824-2820 + * (978) 256-1300 + * webinfo@mc.com + * + * 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, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * http://www.gnu.org/copyleft/gpl.html + ******************************************************************/ + + +#ifndef AXON_ADDR_XLTR_H +#define AXON_ADDR_XLTR_H + +#include + +#include + +struct addr_xltr_t { + + void *context; + + + + + + + + + dma_addr_t(*from_plb) (struct addr_xltr_t * self, + plb_addr_t plb_bus_addr); + + + + + + + plb_addr_t(*to_plb) (struct addr_xltr_t * self, + dma_addr_t cpu_bus_addr); + int (*is_local) (struct addr_xltr_t * self, + plb_addr_t plb_bus_addr); + +}; + +static inline dma_addr_t +axon_addr_xltr_from_plb(struct addr_xltr_t *self, plb_addr_t plb_bus_addr) +{ + return self->from_plb(self, plb_bus_addr); + +} + +static inline plb_addr_t +axon_addr_xltr_to_plb(struct addr_xltr_t *self, dma_addr_t cpu_bus_addr) +{ + return self->to_plb(self, cpu_bus_addr); + +} + +static inline int +axon_addr_xltr_is_local(struct addr_xltr_t *self, plb_addr_t plb_bus_addr) +{ + return self->is_local(self, plb_bus_addr); +} + +#endif Index: linux/drivers/axon/include/axon_bitops.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/drivers/axon/include/axon_bitops.h 2006-12-19 17:53:10.000000000 +0100 @@ -0,0 +1,108 @@ +/****************************************************************** + * Copyright (C) 2006 Mercury Computer Systems, Inc. + * 199 Riverneck Road + * Chelmsford, MA 01824-2820 + * (978) 256-1300 + * webinfo@mc.com + * + * 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, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * http://www.gnu.org/copyleft/gpl.html + ******************************************************************/ + + +#ifndef AXON_BITOPS_H +#define AXON_BITOPS_H + +#include + + + + +#if defined( __powerpc__) + +# define BE_HI32_FROM_BE64(x) ((__u32)( (x) >> 32)) +# define BE_LO32_FROM_BE64(x) ((__u32)( (x) & ((1ULL<<32)-1) )) +# define LE_HI32_FROM_LE64(x) ((__u32)( (x) & ((1ULL<<32)-1) )) +# define LE_LO32_FROM_LE64(x) ((__u32)( (x) >> 32)) +# define GET_BIT_MASK_FROM_IBM_DOC(nr,type) (1ULL << ( (sizeof(type)*8 - 1) - nr )) + +#elif defined(__i386__) || defined(__x86_64__) + +# define LE_HI32_FROM_LE64(x) ((__u32)( (x) >> 32)) +# define LE_LO32_FROM_LE64(x) ((__u32)( (x) & ((1ULL<<32)-1) )) +# define BE_HI32_FROM_BE64(x) ((__u32)( (x) & ((1ULL<<32)-1) )) +# define BE_LO32_FROM_BE64(x) ((__u32)( (x) >> 32)) +# define GET_BIT_MASK_FROM_IBM_DOC(nr,type) (1ULL << ( (~((nr) & 0x7) & 0x7) + (nr & ~0x7)) ) + +#else +# error "Unsupported platform" +#endif + + +#define BExx_clr_bit(size) \ +static inline u##size \ +be##size##_clr_bit(u##size reg##size,int nr) \ +{ \ + reg##size = reg##size & ~(GET_BIT_MASK_FROM_IBM_DOC(nr,u##size)); \ + return reg##size; \ +} + +BExx_clr_bit(64) BExx_clr_bit(32) BExx_clr_bit(16) BExx_clr_bit(8) +#define BExx_set_bit(size) \ +static inline u##size \ +be##size##_set_bit(u##size reg##size,int nr) \ +{ \ + reg##size = reg##size | GET_BIT_MASK_FROM_IBM_DOC(nr,u##size); \ + return reg##size; \ +} + BExx_set_bit(64) BExx_set_bit(32) BExx_set_bit(16) BExx_set_bit(8) +#define BExx_isset_bit(size) \ +static inline u##size \ +be##size##_isset_bit(u##size reg##size,int nr) \ +{ \ + return reg##size & GET_BIT_MASK_FROM_IBM_DOC(nr,u##size); \ +} + BExx_isset_bit(64) + BExx_isset_bit(32) BExx_isset_bit(16) BExx_isset_bit(8) +#define BExx_set_bit_range(size) \ +static inline u##size \ +be##size##_set_bit_range(u##size reg##size,int ibm_start, int ibm_end, u##size value) \ +{\ + int i_bit;\ + if ( ibm_start > ibm_end ) { \ + dbg_err("Invalid limit for set bit range operation\n"); \ + return reg##size; \ + } \ + \ + for ( i_bit = ibm_end; i_bit >= ibm_start; i_bit--) { \ +\ + \ + if (value & 0x1) {\ + \ + reg##size = be##size##_set_bit(reg##size, i_bit); \ + } else {\ + \ + reg##size = be##size##_clr_bit(reg##size, i_bit); \ + }\ +\ + \ + value = value >> 1;\ + }\ + return reg##size; \ +} + BExx_set_bit_range(64) + BExx_set_bit_range(32) BExx_set_bit_range(16) BExx_set_bit_range(8) +#endif Index: linux/drivers/axon/include/axon_class.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/drivers/axon/include/axon_class.h 2006-12-19 17:53:10.000000000 +0100 @@ -0,0 +1,37 @@ +/****************************************************************** + * Copyright (C) 2006 Mercury Computer Systems, Inc. + * 199 Riverneck Road + * Chelmsford, MA 01824-2820 + * (978) 256-1300 + * webinfo@mc.com + * + * 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, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * http://www.gnu.org/copyleft/gpl.html + ******************************************************************/ + + +#ifndef AXON_CLASS_H +#define AXON_CLASS_H + +#include + +int axon_create_class(void); + +int axon_destroy_class(void); + +void *axon_get_class(void); + +#endif Index: linux/drivers/axon/include/axon_dbg.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/drivers/axon/include/axon_dbg.h 2006-12-19 17:53:10.000000000 +0100 @@ -0,0 +1,44 @@ +/****************************************************************** + * Copyright (C) 2006 Mercury Computer Systems, Inc. + * 199 Riverneck Road + * Chelmsford, MA 01824-2820 + * (978) 256-1300 + * webinfo@mc.com + * + * 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, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * http://www.gnu.org/copyleft/gpl.html + ******************************************************************/ + + +#ifndef AXON_DBG_H +#define AXON_DBG_H + +#include + +#define AXON_DRIVER_NAME "Axon" + + +#if defined(AXON_DEBUG_MODULE) || defined(AXON_DEBUG) +#define dbg_log(...) printk(KERN_INFO AXON_DRIVER_NAME "=>" __VA_ARGS__ ) +#else +#define dbg_log(...) do { } while(0) +#endif + +#define dbg_inf(...) printk(KERN_INFO AXON_DRIVER_NAME "=>" __VA_ARGS__ ) + +#define dbg_err(...) printk(KERN_EMERG AXON_DRIVER_NAME "=>" __VA_ARGS__ ) + +#endif Index: linux/drivers/axon/include/axon_defs.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/drivers/axon/include/axon_defs.h 2006-12-19 17:53:10.000000000 +0100 @@ -0,0 +1,392 @@ +/****************************************************************** + * Copyright (C) 2006 Mercury Computer Systems, Inc. + * 199 Riverneck Road + * Chelmsford, MA 01824-2820 + * (978) 256-1300 + * webinfo@mc.com + * + * 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, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * http://www.gnu.org/copyleft/gpl.html + ******************************************************************/ + + +#ifndef AXON_DEFS_H +#define AXON_DEFS_H + + +#define AXON_PLB_XDR_CHAN0_OFFSET 0x6000006000000000ULL +#define AXON_PLB_XDR_CHAN0_MASK 0xFFFFFFF000000000ULL + + +#define AXON_PLB_MASK_FROM_BE 0x000000FFFFFFFFFFULL +#define AXON_PLB_OFFSET_FROM_BE 0x0000010000000000ULL + +#define AXON_PLB_NIBBLE_MASK 0x000000F000000000ULL +#define AXON_PLB_NIBBLE_SHIFT 24 + +#define AXON_MPCI_INTR_COUNT 128 + + +#define AXON_BEI_INTR_COUNT (AXON_MPCI_INTR_COUNT + 128) +#define AXON_BEI_INTR_MBOX_DIRECT 136 +#define AXON_BEI_INTR_MBOX_INDIRECT 116 +#define AXON_BEI_INTR_MBOX_OVERFLOW 117 +#define AXON_BEI_INTR_AUX_DMA_CH0_ERR 12 +#define AXON_BEI_INTR_AUX_DMA_CH1_ERR 13 +#define AXON_BEI_INTR_AUX_DMA_CH2_ERR 14 +#define AXON_BEI_INTR_AUX_DMA_CH3_ERR 15 +#define AXON_BEI_INTR_DMAX_CH0 119 +#define AXON_BEI_INTR_DMAX_CH1 120 +#define AXON_BEI_INTR_DMAX_CH2 121 +#define AXON_BEI_INTR_DMAX_CH3 122 +#define AXON_BEI_INTR_DMAX_CH0_ERR 123 +#define AXON_BEI_INTR_DMAX_CH1_ERR 124 +#define AXON_BEI_INTR_DMAX_CH2_ERR 125 +#define AXON_BEI_INTR_DMAX_CH3_ERR 126 +#define AXON_BEI_INTR_DMAX_SLAVE_ERR 127 + + + + +#define AXON_C3PO_REGS_OFFSET 0x0000 +#define AXON_C3PO_SCRATCHPAD_OFFSET 0xC00 +#define AXON_DMAX_REGS_OFFSET 0x1000 +#define AXON_MBOX_REGS_OFFSET 0x2000 +#define AXON_SCRATCHPAD_REGS_OFFSET 0xC00 + +#define AXON_PLB_DDR_OFFSET 0x0000000000000000ULL +#define AXON_PLB_DDR_SIZE 0x0000001000000000ULL + +#define AXON_PLB_UTL_REGS_OFFSET 0xA00000A000004000ULL +#define AXON_PLB_UTL_REGS_SIZE 0x1000 + +#define AXON_PLB_CFG_REGS_OFFSET 0xA00000A000005000ULL +#define AXON_PLB_CFG_REGS_SIZE 0x1000 + +#define AXON_PLB_DCR_REGS_OFFSET 0x8000008000000000ULL +#define AXON_PLB_DCR_REGS_SIZE (0x240 * 4) +#define AXON_PLB_PCIE_OFFSET 0xC00000C000000000ULL +#define AXON_PLB_PCIE_MASK 0x00000007FFFFFFFFULL + +#define AXON_PLB_REGS_SLV_OFFSET 0x4000004400000000ULL +#define AXON_PLB_REGS_SLV_SIZE 0x5000 + +#define AXON_PLB_PCIE_REGS_OFFSET 0xA00000A000000000ULL + +#define AXON_DCR_STEP 0x10 + + + +#define AXON_PLB_MBOX_MESSAGE_ADDRESS 0x4000004400002000ULL + +#define AXON_MBOX_ACCESS_REGION_ADDR_HI (0x4E * AXON_DCR_STEP) +#define AXON_MBOX_ACCESS_REGION_ADDR_LO (0x4F * AXON_DCR_STEP) +#define AXON_MBOX_ACCESS_REGION_MASK_HI (0x50 * AXON_DCR_STEP) +#define AXON_MBOX_ACCESS_REGION_MASK_LO (0x51 * AXON_DCR_STEP) + +#define AXON_MBOX_DEFAULT_ACCESS_REGION_ADDR_HI 0x40000044 +#define AXON_MBOX_DEFAULT_ACCESS_REGION_ADDR_LO 0x00002000 +#define AXON_MBOX_DEFAULT_ACCESS_REGION_MASK_HI 0x7FFFFFFF +#define AXON_MBOX_DEFAULT_ACCESS_REGION_MASK_LO 0xFFFFF005 +#define AXON_MBOX_DISABLE_ACCESS_REGION_MASK_LO 0xFFFFF004 + +#define AXON_MBOX_PARK_ACCESS_REGION_ADDR_HI 0x80000080 + +#define AXON_MBOX_CR (0x68 * AXON_DCR_STEP) +#define AXON_MBOX_MESSAGE_ADDR_HI (0x69 * AXON_DCR_STEP) +#define AXON_MBOX_MESSAGE_ADDR_LO (0x6A * AXON_DCR_STEP) +#define AXON_MBOX_BASE_ADDR_HI (0x6B * AXON_DCR_STEP) +#define AXON_MBOX_BASE_ADDR_LO (0x6C * AXON_DCR_STEP) +#define AXON_MBOX_READ_OFFSET (0x6D * AXON_DCR_STEP) +#define AXON_MBOX_WRITE_OFFSET (0x6E * AXON_DCR_STEP) + +#define AXON_MBOX_CR_SIZE_32K (0) +#define AXON_MBOX_CR_SIZE_64K (1) +#define AXON_MBOX_CR_SIZE_128K (2) +#define AXON_MBOX_CR_SIZE_256K (3) + +#define AXON_MBOX_CR_SIZE_hi (22) +#define AXON_MBOX_CR_SIZE_lo (23) +#define AXON_MBOX_CR_STOP_INC (27) +#define AXON_MBOX_CR_INTR_INDIRECT (28) +#define AXON_MBOX_CR_INTR_DIRECT (29) +#define AXON_MBOX_CR_INTR_FULL (30) +#define AXON_MBOX_CR_EN (31) + + + +#define PCI_DEVICE_BOARD_NAME "CAB board" + + +#define PCI_DEVICE_ID_IBM_AXON 0x032d + +#define PCICx_REVID 0x08 +#define AXON_REVISION_ID_1 0x0b400000 + +#define AXON_PCIE_PIM01_BAR 0x0 +#define AXON_PCIE_REGS_BAR 0x2 +#define AXON_PCIE_PIM34_BAR 0x4 + + +#define AXON_UTL_INTR_COUNT 8 + + +#define AXON_BAR2_PCIE_OFFSET 0x4000 +#define AXON_PCIE_UTL_REGS_OFFSET (0x0000 + AXON_BAR2_PCIE_OFFSET) +#define AXON_PCIE_CFG_REGS_OFFSET (0x1000 + AXON_BAR2_PCIE_OFFSET) + + +#define PCIe_PIM0_LOWER 0x340 +#define PCIe_PIM0_UPPER 0x344 + +#define PCIe_PIM1_LOWER 0x348 +#define PCIe_PIM1_UPPER 0x34C +#define PCIe_PIM1_SIZE_LOWER 0x350 +#define PCIe_PIM1_SIZE_UPPER 0x354 + +#define PCIe_PIM2_LOWER 0x358 +#define PCIe_PIM2_UPPER 0x35C + +#define PCIe_PIM3_LOWER 0x360 +#define PCIe_PIM3_UPPER 0x364 + +#define PCIe_PIM4_LOWER 0x368 +#define PCIe_PIM4_UPPER 0x36C +#define PCIe_PIM34_SIZE_LOWER 0x370 +#define PCIe_PIM34_SIZE_UPPER 0x374 + +#define PCIe_PIM6_LOWER 0x3C0 +#define PCIe_PIM6_UPPER 0x3C4 +#define PCIe_PIM26_SIZE 0x3C8 + +#define PCIe_PIM5_LOWER 0x378 +#define PCIe_PIM5_UPPER 0x37C + + + +#define PCIe_POM0_LOWER 0x380 +#define PCIe_POM0_HIGHER 0x384 + +#define PCIe_POM1_LOWER 0x388 +#define PCIe_POM1_HIGHER 0x38C + +#define PCIe_POM2_LOWER 0x390 +#define PCIe_POM2_HIGHER 0x394 + + +#define PCIe_OUTBOUND_MEM0_PORT_SELECT0_hi 0 +#define PCIe_OUTBOUND_MEM0_PORT_SELECT0_lo 3 +#define PCIe_OUTBOUND_MEM0_PORT_SELECT1_hi 24 +#define PCIe_OUTBOUND_MEM0_PORT_SELECT1_lo 27 +#define PCIe_OUTBOUND_MEM0_PORT0 0xC +#define PCIe_OUTBOUND_MEM0_PORT1 0xD +#define PCIe_OUTBOUND_MEM0_TC 28 + +#define PCIe_OUTBOUND_MEM1_PORT_SELECT_hi 0 +#define PCIe_OUTBOUND_MEM1_PORT_SELECT_lo 3 +#define PCIe_OUTBOUND_MEM1_PORT0 0xE +#define PCIe_OUTBOUND_MEM1_PORT1 0xF +#define PCIe_OUTBOUND_MEM1_TC 4 + + +#define UTL_ISSR 0x14 +#define UTL_ISCR 0x18 +#define UTL_MISR 0x1C +#define UTL_MISR_AEM0 0x0 +#define UTL_MISR_AEM1 0x1 +#define UTL_MISR_AEM2 0x2 +#define UTL_MISR_AEM3 0x3 +#define UTL_MISR_AEM4 0x4 +#define UTL_MISR_AEM5 0x5 +#define UTL_MISR_AEM6 0x6 +#define UTL_MISR_AEM7 0x7 + +#define AXON_INTR_MBOX_DMA ( UTL_MISR_AEM0) +#define AXON_INTR_MBOX_BE ( UTL_MISR_AEM1) +#define AXON_INTR_SYS ( UTL_MISR_AEM7) + + + + +#define AuxDMA_DESC_STEP 0x4 + +#define AuxDMA_Base (AXON_DCR_STEP * 0x100) +#define AuxDMA_Len ((AXON_DCR_STEP * 0x140) - AuxDMA_Base) + +#define AuxDMA_CRn (AuxDMA_DESC_STEP * 0x00) +#define AuxDMA_CTCn (AuxDMA_DESC_STEP * 0x01) +#define AuxDMA_SAHn (AuxDMA_DESC_STEP * 0x02) +#define AuxDMA_SALn (AuxDMA_DESC_STEP * 0x03) +#define AuxDMA_DAHn (AuxDMA_DESC_STEP * 0x04) +#define AuxDMA_DALn (AuxDMA_DESC_STEP * 0x05) +#define AuxDMA_SGHn (AuxDMA_DESC_STEP * 0x06) +#define AuxDMA_SGLn (AuxDMA_DESC_STEP * 0x07) + +#define AuxDMA_SGH (AXON_DCR_STEP * 0x06) +#define AuxDMA_SGL (AXON_DCR_STEP * 0x07) + +#define AuxDMA_CR0 (AXON_DCR_STEP * 0x00) +#define AuxDMA_CR1 (AXON_DCR_STEP * 0x08) +#define AuxDMA_CR2 (AXON_DCR_STEP * 0x10) +#define AuxDMA_CR3 (AXON_DCR_STEP * 0x18) + +#define AuxDMA_SR (AXON_DCR_STEP * 0x20) +#define AuxDMA_SGC (AXON_DCR_STEP * 0x23) +#define AuxDMA_SLP (AXON_DCR_STEP * 0x25) +#define AuxDMA_POL (AXON_DCR_STEP * 0x26) + +#define AuxDMA_CTCn_TCIE (2) +#define AuxDMA_CTCn_ETIE (3) +#define AuxDMA_CTCn_EIE (4) +#define AuxDMA_CTCn_LK (0) + +#define AuxDMA_CRn_PW_hi (4) +#define AuxDMA_CRn_PW_lo (6) +#define AuxDMA_CRn_PL (3) +#define AuxDMA_CRn_CIE (1) +#define AuxDMA_CRn_CE (0) +#define AuxDMA_CRn_DEC (29) +#define AuxDMA_CRn_DAI (7) +#define AuxDMA_CRn_SAI (8) +#define AuxDMA_CRn_BEN (9) +#define AuxDMA_CRn_ETD (23) +#define AuxDMA_CRn_TCE (24) +#define AuxDMA_CRn_TM_hi (10) +#define AuxDMA_CRn_TM_lo (11) +#define AuxDMA_CRn_CP_hi (25) +#define AuxDMA_CRn_CP_lo (26) + +#define AuxDMA_CRn_TM_SW_INITIATED (2) + +#define AuxDMA_CRn_CP_HIGH_PRIORITY (3) + +#define AuxDMA_SGC_EMn (16) +#define AuxDMA_SGC_SGLn (4) +#define AuxDMA_SGC_SSGn (0) + + + +#define DMAx_CRn 0x000 +#define DMAx_CTCn 0x004 +#define DMAx_DSTRn 0x008 +#define DMAx_SAHn 0x010 +#define DMAx_SALn 0x014 +#define DMAx_DAHn 0x018 +#define DMAx_DALn 0x01c +#define DMAx_SGHn 0x020 +#define DMAx_SGLn 0x024 +#define DMAx_SGCn 0x040 +#define DMAx_CHRESn 0x050 +#define DMAx_CHLOCKn 0x060 +#define DMAx_SGCAn 0x070 + + +#define DMAx_CR0 0x000 +#define DMAx_CTC0 0x004 +#define DMAx_DSTR0 0x008 +#define DMAx_SAH0 0x010 +#define DMAx_SAL0 0x014 +#define DMAx_DAH0 0x018 +#define DMAx_DAL0 0x01c +#define DMAx_SGH0 0x020 +#define DMAx_SGL0 0x024 +#define DMAx_SGC0 0x040 +#define DMAx_CHRES0 0x050 +#define DMAx_CHLOCK0 0x060 +#define DMAx_SGCA0 0x070 +#define DMAx_CR1 0x080 +#define DMAx_CTC1 0x084 +#define DMAx_DSTR1 0x088 +#define DMAx_SAH1 0x090 +#define DMAx_SAL1 0x094 +#define DMAx_DAH1 0x098 +#define DMAx_DAL1 0x09c +#define DMAx_SGH1 0x0a0 +#define DMAx_SGL1 0x0a4 +#define DMAx_SGC1 0x0c0 +#define DMAx_CHRES1 0x0d0 +#define DMAx_CHLOCK1 0x0e0 +#define DMAx_SGCA1 0x0f0 +#define DMAx_CR2 0x100 +#define DMAx_CTC2 0x104 +#define DMAx_DSTR2 0x108 +#define DMAx_SAH2 0x110 +#define DMAx_SAL2 0x114 +#define DMAx_DAH2 0x118 +#define DMAx_DAL2 0x11c +#define DMAx_SGH2 0x120 +#define DMAx_SGL2 0x124 +#define DMAx_SGC2 0x140 +#define DMAx_CHRES2 0x150 +#define DMAx_CHLOCK2 0x160 +#define DMAx_SGCA2 0x170 +#define DMAx_CR3 0x180 +#define DMAx_CTC3 0x184 +#define DMAx_DSTR3 0x188 +#define DMAx_SAH3 0x190 +#define DMAx_SAL3 0x194 +#define DMAx_DAH3 0x198 +#define DMAx_DAL3 0x19c +#define DMAx_SGH3 0x1a0 +#define DMAx_SGL3 0x1a4 +#define DMAx_SGC3 0x1c0 +#define DMAx_CHRES3 0x1d0 +#define DMAx_CHLOCK3 0x1e0 +#define DMAx_SGCA3 0x1f0 +#define DMAx_SR 0x200 +#define DMAx_PMEAH 0x208 +#define DMAx_PMEAL 0x20c +#define DMAx_PSE 0x220 +#define DMAx_PSEAH 0x228 +#define DMAx_PSEAL 0x22c +#define DMAx_CRS 0x230 +#define DMAx_REVID 0x240 +#define DMAx_PLBARB 0x260 +#define DMAx_OPTIONS 0x270 + +#define DMAx_OPTIONS_ENABLE_PIPELINING (1 << 0) +#define DMAx_OPTIONS_ENABLE_POWER_SAVING (1 << 1) +#define DMAx_OPTIONS_ENABLE_CHANNEL_LOCKING (1 << 2) +#define DMAx_OPTIONS_ENABLE_OUT_OF_ORDER_READ (1 << 3) +#define DMAx_OPTIONS_ENABLE_OUT_OF_ORDER_READ (1 << 3) + + +#define DMAx_PLBARB_ENABLE_ROUND_ROBIN (1 << 0) + +#define DMAx_CRn_PW_hi (5) +#define DMAx_CRn_PW_lo (7) +#define DMAx_CRn_CE (0) +#define DMAx_CRn_BIE (1) +#define DMAx_CRn_CIM (4) +#define DMAx_CRn_BAR (31) +#define DMAx_CRn_SSC (18) +#define DMAx_CRn_DSC (19) + +#define DMAx_CTCn_LK (0) + +#define DMAx_SGCn_SSG (0) + +#define DMAx_CHRESn_CHR (0) + + + +#define DMAx_DESCRIPTOR_ALIGNEMENT 64 + + +#define DMAx_DESCRIPTOR_SIZE (16 * 4) + + +#endif Index: linux/drivers/axon/include/axon_dma_ops.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/drivers/axon/include/axon_dma_ops.h 2006-12-19 17:53:10.000000000 +0100 @@ -0,0 +1,165 @@ +/****************************************************************** + * Copyright (C) 2006 Mercury Computer Systems, Inc. + * 199 Riverneck Road + * Chelmsford, MA 01824-2820 + * (978) 256-1300 + * webinfo@mc.com + * + * 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, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * http://www.gnu.org/copyleft/gpl.html + ******************************************************************/ + + +#ifndef AXON_DMA_OPS_H +#define AXON_DMA_OPS_H + +#include + + +typedef enum { + AXON_DMA_CHANNEL_INVALID, + AXON_DMA_CHANNEL_0, + AXON_DMA_CHANNEL_1, + AXON_DMA_CHANNEL_2, + AXON_DMA_CHANNEL_3, + +} axon_dma_channel_t; + + +typedef enum { + AXON_WIDTH_BYTE = 0, + AXON_WIDTH_HALFWORD, + AXON_WIDTH_WORD, + AXON_WIDTH_DOUBLEWORD, + AXON_WIDTH_QUADWORD +} axon_dma_xfer_width; + + +typedef enum { + + DMA_NO_INTR, + + + DMA_INTR_WAIT, + + + DMA_INTR_NOWAIT +} axon_dma_intr_t; + + +struct axon_dma_cmd_t { + + + u64 dst_addr; + + + u64 src_addr; + + + u32 byte_count; + + + axon_dma_intr_t intr; + +}; + + +struct axon_dma_pkt_t { + + + void *addr; + + + dma_addr_t cpu_bus_addr; + + + plb_addr_t plb_bus_addr; +}; + + +struct axon_dma_ops_t { + + void *context; + + + + + + + + + u32(*format) (struct axon_dma_ops_t * dma_ops, + struct axon_dma_cmd_t * p_dma_cmd, + struct axon_dma_pkt_t * p_dma_pkt, + struct axon_dma_pkt_t * p_dma_pkt_prev); + + void (*queue) (struct axon_dma_ops_t * dma_ops, + struct axon_dma_pkt_t * p_dma_pkt); + + void (*start) (struct axon_dma_ops_t * dma_ops, + struct axon_dma_pkt_t * p_dma_pkt); + + void (*resume) (struct axon_dma_ops_t * dma_ops, + struct axon_dma_pkt_t * p_dma_pkt); + + void (*link) (struct axon_dma_ops_t * dma_ops, + struct axon_dma_pkt_t * p_dma_pkt_prev, + struct axon_dma_pkt_t * p_dma_pkt); + + void (*reset) (struct axon_dma_ops_t * dma_ops); + + void (*mbox) (struct axon_dma_ops_t * dma_ops, + struct axon_mbox_t * p_mbox, + u8 * mbox_data, + struct axon_dma_pkt_t * p_dma_pkt, + struct axon_dma_pkt_t * p_dma_pkt_prev); + + void (*destroy) (struct axon_dma_ops_t * dma_ops); +}; + +static inline axon_dma_xfer_width +dma_ops_get_best_align_width(plb_addr_t addr, axon_size_bus_t size) +{ + axon_dma_xfer_width best_xfer_width; + + + u64 cpu_addr = __be64_to_cpu(addr); + if ((cpu_addr & 0xF) == 0 && (size >= 16)) { + + best_xfer_width = AXON_WIDTH_QUADWORD; + + } else if ((cpu_addr & 0x7) == 0 && (size >= 8)) { + + best_xfer_width = AXON_WIDTH_DOUBLEWORD; + + } else if ((cpu_addr & 0x3) == 0 && (size >= 4)) { + + best_xfer_width = AXON_WIDTH_WORD; + + } else if ((cpu_addr & 0x1) == 0 && (size >= 2)) { + + best_xfer_width = AXON_WIDTH_HALFWORD; + + } else { + + best_xfer_width = AXON_WIDTH_BYTE; + + } + + return best_xfer_width; +} + +#endif Index: linux/drivers/axon/include/axon_dma_ops_dma_aux.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/drivers/axon/include/axon_dma_ops_dma_aux.h 2006-12-19 17:53:10.000000000 +0100 @@ -0,0 +1,81 @@ +/****************************************************************** + * Copyright (C) 2006 Mercury Computer Systems, Inc. + * 199 Riverneck Road + * Chelmsford, MA 01824-2820 + * (978) 256-1300 + * webinfo@mc.com + * + * 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, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * http://www.gnu.org/copyleft/gpl.html + ******************************************************************/ + + +#ifndef AXON_DMA_OPS_DMA_AUX_H +#define AXON_DMA_OPS_DMA_AUX_H + +#include + +#include +#include +#include + + +struct axon_dma_ops_dma_aux_t { + + + volatile u8 *p_dma_channel; + + volatile u8 *p_regs; + + + axon_dma_channel_t channel; + + + int channel_id; + + spinlock_t lock; + + struct axon_t *p_axon; +}; + + +static inline void +dma_aux_write(struct axon_dma_ops_dma_aux_t *p_axon_dma_ops_dma_aux, + u32 reg, u32 value) +{ + axon_writel(value, p_axon_dma_ops_dma_aux->p_regs + reg); + wmb(); +} + +static inline u32 +dma_aux_read(struct axon_dma_ops_dma_aux_t *p_axon_dma_ops_dma_aux, + u32 reg) +{ + return axon_readl(p_axon_dma_ops_dma_aux->p_regs + reg); +} + + +int + axon_dma_ops_dma_aux_create(struct axon_t *p_axon, + axon_dma_channel_t channel, + struct axon_dma_ops_t + **pp_dma_ops); + +void axon_dma_ops_dma_aux_destroy(struct axon_dma_ops_t + *p_dma_ops); + + +#endif Index: linux/drivers/axon/include/axon_dma_ops_dma_soft.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/drivers/axon/include/axon_dma_ops_dma_soft.h 2006-12-19 17:53:10.000000000 +0100 @@ -0,0 +1,92 @@ +/****************************************************************** + * Copyright (C) 2006 Mercury Computer Systems, Inc. + * 199 Riverneck Road + * Chelmsford, MA 01824-2820 + * (978) 256-1300 + * webinfo@mc.com + * + * 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, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * http://www.gnu.org/copyleft/gpl.html + ******************************************************************/ + + +#ifndef AXON_DMA_OPS_DMA_SOFT_H +#define AXON_DMA_OPS_DMA_SOFT_H + +#include +#include + +#include +#include +#include +#include +#include + +enum axon_dma_soft_direction_t { + AXON_DMA_SOFT_DIRECTION_INVALID, + AXON_DMA_SOFT_DIRECTION_FROM_CPU, + AXON_DMA_SOFT_DIRECTION_TO_CPU, +}; + + + +struct axon_dma_soft_cmd_t { + + plb_addr_t plb_addr; + void *cpu_addr; + enum axon_dma_soft_direction_t direction; + + unsigned int xfer_size; + struct axon_dma_soft_cmd_t *next; + struct axon_mbox_t *p_mbox; + u8 mbox[AXON_SMS_SIZE]; + +}; + +struct axon_dma_ops_dma_soft_t { + + spinlock_t lock; + + + struct work_struct dma_engine_task; + + + struct axon_dma_soft_cmd_t *p_first_cmd; + + struct axon_sms_t *p_sms; + + struct axon_pio_t *p_pio; + + struct addr_xltr_t *p_addr_xltr; +}; + + + +int + axon_dma_ops_dma_soft_create(struct axon_t *p_axon, + struct addr_xltr_t + *p_addr_xltr, + axon_dma_channel_t channel, + struct axon_sms_t *p_sms, + struct axon_pio_t *p_pio, + struct axon_dma_ops_t + **pp_dma_ops); + +void axon_dma_ops_dma_soft_destroy(struct axon_dma_ops_t + *p_dma_ops); + + +#endif Index: linux/drivers/axon/include/axon_dma_ops_dmax.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/drivers/axon/include/axon_dma_ops_dmax.h 2006-12-19 17:53:10.000000000 +0100 @@ -0,0 +1,77 @@ +/****************************************************************** + * Copyright (C) 2006 Mercury Computer Systems, Inc. + * 199 Riverneck Road + * Chelmsford, MA 01824-2820 + * (978) 256-1300 + * webinfo@mc.com + * + * 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, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * http://www.gnu.org/copyleft/gpl.html + ******************************************************************/ + + +#ifndef AXON_DMA_OPS_DMAX_H +#define AXON_DMA_OPS_DMAX_H + +#include +#include +#include +#include + + +struct axon_dma_ops_dmax_t { + + + volatile u8 *p_dma_channel; + + volatile u8 *p_regs; + + + int channel_id; + + enum axon_sys_type_t type; + + struct axon_t *p_axon; +}; + + +static inline void +dmax_write(struct axon_dma_ops_dmax_t *p_axon_dma_ops_dmax, u32 reg, + u32 value) +{ + axon_writel(value, p_axon_dma_ops_dmax->p_regs + reg); + wmb(); +} + +static inline u32 +dmax_read(struct axon_dma_ops_dmax_t *p_axon_dma_ops_dmax, u32 reg) +{ + return axon_readl(p_axon_dma_ops_dmax->p_regs + reg); +} + + +int + axon_dma_ops_dmax_create(struct axon_t *p_axon, + axon_dma_channel_t channel, + enum axon_sys_type_t type, + struct axon_dma_ops_t + **pp_dma_ops); + +void axon_dma_ops_dmax_destroy(struct axon_dma_ops_t + *p_dma_ops); + + +#endif Index: linux/drivers/axon/include/axon_dmax.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/drivers/axon/include/axon_dmax.h 2006-12-19 17:53:10.000000000 +0100 @@ -0,0 +1,158 @@ +/****************************************************************** + * Copyright (C) 2006 Mercury Computer Systems, Inc. + * 199 Riverneck Road + * Chelmsford, MA 01824-2820 + * (978) 256-1300 + * webinfo@mc.com + * + * 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, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * http://www.gnu.org/copyleft/gpl.html + ******************************************************************/ + + +#ifndef AXON_DMAX_H +#define AXON_DMAX_H +#include +#include +#include +#include +#include +#include + +typedef unsigned long axon_dma_target_t; + + +#define AXON_DMA_TARGET_SELF 0xFEF +#define AXON_DMA_TARGET_PEER 0xADC +#define AXON_DMA_TARGET_INVALID 0x0 + + +struct axon_dma_req_mbox_t { + + + + + struct axon_mbox_t *p_dst_mbox; + + + axon_dma_target_t dst_id; + + + void *msg; + + + size_t msg_size; + + +}; +#define AXON_DMA_REQ_MBOX_INIT (struct axon_dma_req_mbox_t) { NULL, AXON_DMA_TARGET_INVALID, NULL, 0 } + + +struct axon_dma_req_xfer_t { + + + plb_addr_t src; + + + plb_addr_t dst; + + + axon_size_bus_t size; + + + axon_dma_intr_t intr; + +}; + +#define AXON_DMA_REQ_XFER_INIT (struct axon_dma_req_xfer_t) { 0x0ULL, 0x0ULL, 0x0ULL, DMA_NO_INTR } + + +struct axon_dma_req_u32_t { + + + u32 data; + + + plb_addr_t dst; + + + axon_dma_intr_t intr; + +}; + +#define AXON_DMA_REQ_U32_INIT (struct axon_dma_req_u32_t) { 0, 0x0ULL, DMA_NO_INTR } + + + + + +struct axon_dma_t; + +struct axon_dma_req_t; + +typedef void (*axon_dma_completion_handler_t) (struct axon_dmax_t * + p_axon_dmax, + struct axon_dma_req_t * + p_dma_req, + void *context); + + +void axon_dma_destroy(struct axon_dmax_t *p_axon_dmax); + +int axon_dma_create(struct axon_t *p_axon, + struct axon_mbox_t *p_axon_mbox_self, + struct axon_mbox_t *p_axon_mbox_peer, + struct axon_sms_t *p_axon_sms, + struct addr_xltr_t *p_addr_xltr, + struct axon_dma_ops_t *p_dma_ops, + struct axon_dmax_t **pp_axon_dmax); + +void axon_dma_request_destroy(struct axon_dma_req_t *p_dma_req); +void axon_dma_request_clear(struct axon_dma_req_t *p_dma_req); + + + +int axon_dma_request_push_mbox(struct axon_dma_req_t + *p_dma_req, + struct axon_dma_req_mbox_t + *p_dma_req_mbox); + + + +int + axon_dma_request_push_u32(struct axon_dma_req_t *p_dma_req, + struct axon_dma_req_u32_t + *p_dma_req_u32); + + +int + axon_dma_request_push_xfer(struct axon_dma_req_t *p_dma_req, + struct axon_dma_req_xfer_t + *p_dma_req_xfer); + + +int + axon_dma_request_create(struct axon_dmax_t *p_axon_dmax, + struct axon_dma_req_t **pp_dma_req, + int nb_max_cmd_pkts); + + +int + axon_dma_request_queue(struct axon_dma_req_t *p_dma_req, + axon_dma_completion_handler_t + completion_handler, void *context); + +#endif Index: linux/drivers/axon/include/axon_io.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/drivers/axon/include/axon_io.h 2006-12-19 17:53:10.000000000 +0100 @@ -0,0 +1,104 @@ +/****************************************************************** + * Copyright (C) 2006 Mercury Computer Systems, Inc. + * 199 Riverneck Road + * Chelmsford, MA 01824-2820 + * (978) 256-1300 + * webinfo@mc.com + * + * 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, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * http://www.gnu.org/copyleft/gpl.html + ******************************************************************/ + + +#ifndef AXON_IO_H +#define AXON_IO_H + +#include + + +#if defined(__x86_64__) || defined(__powerpc64__) +static inline void +axon_writeq(u64 q, volatile void __iomem * addr) +{ + __raw_writeq(q, addr); + +} + +#define AXON_HAS_WRITEQ 1 +#else +#undef AXON_HAS_WRITEQ +#endif + +static inline void +axon_writel(u32 l, volatile void __iomem * addr) +{ + __raw_writel(l, addr); + +} +static inline void +axon_writew(u16 w, volatile void __iomem * addr) +{ + __raw_writew(w, addr); + +} +static inline void +axon_writeb(u8 b, volatile void __iomem * addr) +{ + __raw_writeb(b, addr); + +} + + +#if defined(__x86_64__) || defined(__powerpc64__) +static inline u64 +axon_readq(const volatile void __iomem * addr) +{ + return __raw_readq(addr); + +} + +#define AXON_HAS_READQ 1 +#else +#undef AXON_HAS_READQ +#endif + +static inline u32 +axon_readl(const volatile void __iomem * addr) +{ + return __raw_readl(addr); + +} +static inline u16 +axon_readw(const volatile void __iomem * addr) +{ + return __raw_readw(addr); + +} +static inline u8 +axon_readb(const volatile void __iomem * addr) +{ + return __raw_readb(addr); + +} + +#ifndef __powerpc__ +#define axon_virt_to_bus(x) virt_to_bus( (x) ) +#else +#define axon_virt_to_bus(x) virt_to_phys( (x) ) +#endif + + +#endif Index: linux/drivers/axon/include/axon_mbox.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/drivers/axon/include/axon_mbox.h 2006-12-19 17:53:10.000000000 +0100 @@ -0,0 +1,104 @@ +/****************************************************************** + * Copyright (C) 2006 Mercury Computer Systems, Inc. + * 199 Riverneck Road + * Chelmsford, MA 01824-2820 + * (978) 256-1300 + * webinfo@mc.com + * + * 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, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * http://www.gnu.org/copyleft/gpl.html + ******************************************************************/ + + +#ifndef AXON_MBOX_H +#define AXON_MBOX_H + +#include + +#include + +typedef void (*axon_mbox_handler_t) (void *context, u8 * msg, + size_t msg_size); + + +enum axon_mbox_type_t { + AXON_MBOX_INVALID, + AXON_MBOX_SHADOW, + AXON_MBOX_LOCAL +}; + + +struct axon_mbox_subscriber_t { + + struct list_head list; + + axon_mbox_handler_t handler; + + void *context; +}; + +struct axon_mbox_t { + + void *context; + + + + + + + + + + size_t(*mbox_msg_max_size_get) (struct axon_mbox_t * + p_axon_mbox); + + int (*mbox_msg_alloc) (struct axon_mbox_t * + p_axon_mbox, + dma_addr_t * bus_addr, + volatile void **cpu_addr); + + + + int (*mbox_int_alloc) (struct axon_mbox_t * + p_axon_mbox, + plb_addr_t * plb_addr, + volatile void **p_cpu_addr, + u32 * cookie); + + int (*mbox_unsubscribe) (struct axon_mbox_t * + p_axon_mbox, + axon_mbox_handler_t handler); + + int (*mbox_subscribe) (struct axon_mbox_t * + p_axon_mbox, + axon_mbox_handler_t handler, + void *context); + + void (*mbox_base_addr_set) (struct axon_mbox_t * + p_axon_mbox, + dma_addr_t mbox_base_addr, + u32 mbox_size); + + void (*mbox_reset) (struct axon_mbox_t * p_axon_mbox); + + + + u32(*mbox_size_get) (struct axon_mbox_t * p_axon_mbox); + +}; + + +#endif Index: linux/drivers/axon/include/axon_mbox_hw.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/drivers/axon/include/axon_mbox_hw.h 2006-12-19 17:53:10.000000000 +0100 @@ -0,0 +1,73 @@ +/****************************************************************** + * Copyright (C) 2006 Mercury Computer Systems, Inc. + * 199 Riverneck Road + * Chelmsford, MA 01824-2820 + * (978) 256-1300 + * webinfo@mc.com + * + * 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, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * http://www.gnu.org/copyleft/gpl.html + ******************************************************************/ + + +#ifndef AXON_MBOX_HW_H +#define AXON_MBOX_HW_H + +#include +#include +#include + +#include +#include +#include +#include +#include + +struct axon_mbox_hw_t { + + struct axon_t *p_axon; + + struct addr_xltr_t *p_addr_xltr; + + + struct tasklet_struct mbox_task; + + struct list_head subscriber_list; + + struct axon_ring_t *p_ring; + + size_t ring_msg_size; + + volatile u8 *p_regs; + + dma_addr_t mbox_bus_addr; + + int int_number; + + struct workqueue_struct *irq_poller_wq; + struct work_struct irq_poller; +}; + +int axon_mbox_hw_create(struct axon_t *p_axon, + struct addr_xltr_t *p_addr_xltr, + size_t size_order, + dma_addr_t mbox_bus_addr, + struct axon_mbox_t *p_axon_mbox); + + +void axon_mbox_hw_destroy(struct axon_mbox_t *p_axon_mbox); + +#endif Index: linux/drivers/axon/include/axon_mbox_sw.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/drivers/axon/include/axon_mbox_sw.h 2006-12-19 17:53:10.000000000 +0100 @@ -0,0 +1,86 @@ +/****************************************************************** + * Copyright (C) 2006 Mercury Computer Systems, Inc. + * 199 Riverneck Road + * Chelmsford, MA 01824-2820 + * (978) 256-1300 + * webinfo@mc.com + * + * 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, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * http://www.gnu.org/copyleft/gpl.html + ******************************************************************/ + + +#ifndef AXON_MBOX_SW_H +#define AXON_MBOX_SW_H + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +struct axon_mbox_sw_t { + + struct axon_t *p_axon; + + + int channel_size; + + struct addr_xltr_t *p_addr_xltr; + + + struct tasklet_struct mbox_dma_task; + + struct list_head subscriber_list; + + struct axon_ring_t *p_ring_self; + struct axon_ring_t *p_ring_remote; + + size_t ring_msg_size; + + size_t mbox_size; + dma_addr_t mbox_base_addr; + dma_addr_t mbox_next_addr; + volatile void *mbox_base_cpu; + + enum axon_mbox_type_t type; + + + struct work_struct mbox_mapper; + + atomic_t mbox_up; + + spinlock_t lock; + +}; + +int axon_mbox_sw_create(struct axon_t *p_axon, + enum axon_mbox_type_t type, + struct addr_xltr_t *p_addr_xltr, + size_t size_order, + struct axon_mbox_t *p_axon_mbox); + +void axon_mbox_sw_destroy(struct axon_mbox_t *p_axon_mbox); + +dma_addr_t mbox_sw_base_addr_get(struct axon_mbox_t *p_axon_mbox); + +#endif Index: linux/drivers/axon/include/axon_pim.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/drivers/axon/include/axon_pim.h 2006-12-19 17:53:10.000000000 +0100 @@ -0,0 +1,77 @@ +/****************************************************************** + * Copyright (C) 2006 Mercury Computer Systems, Inc. + * 199 Riverneck Road + * Chelmsford, MA 01824-2820 + * (978) 256-1300 + * webinfo@mc.com + * + * 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, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * http://www.gnu.org/copyleft/gpl.html + ******************************************************************/ + + +#ifndef AXON_PIM_H +#define AXON_PIM_H + +#include +#include + +#include +#include +#include + +#define AXON_MAX_PIM_REG 4 + +struct axon_pim_reg_t { + + u64 mask; + u64 base; + int users; + u32 reg; + + u32 bar_id; + u32 bar_len; +}; + +struct axon_pim_t { + + struct axon_t *p_axon; + + volatile u8 *p_pci_cfg_regs; + + struct axon_pim_reg_t pims[AXON_MAX_PIM_REG]; + int pim_count; + + spinlock_t lock; + + struct addr_xltr_t *p_addr_xlatr; + + struct pci_dev *pci_dev; +}; + +int axon_pim_create(struct axon_t *p_axon, + struct pci_dev *pci_dev, + struct addr_xltr_t *p_addr_xlatr, + struct axon_pim_t **pp_pim); + +void axon_pim_destroy(struct axon_pim_t *p_pim); + +int axon_pim_map(struct axon_pim_t *p_pim, plb_addr_t plb_addr, + size_t size); + +void axon_pim_unmap(struct axon_pim_t *p_pim, plb_addr_t addr); + +#endif Index: linux/drivers/axon/include/axon_pio.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/drivers/axon/include/axon_pio.h 2006-12-19 17:53:10.000000000 +0100 @@ -0,0 +1,62 @@ +/****************************************************************** + * Copyright (C) 2006 Mercury Computer Systems, Inc. + * 199 Riverneck Road + * Chelmsford, MA 01824-2820 + * (978) 256-1300 + * webinfo@mc.com + * + * 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, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * http://www.gnu.org/copyleft/gpl.html + ******************************************************************/ + + +#ifndef AXON_PIO_H +#define AXON_PIO_H + +#include + +struct axon_pio_t { + + void *context; + + int (*writeb) (struct axon_pio_t * p_axon_pio, + plb_addr_t dst, u8 data); + int (*writes) (struct axon_pio_t * p_axon_pio, + plb_addr_t dst, u16 data); + int (*writel) (struct axon_pio_t * p_axon_pio, + plb_addr_t dst, u32 data); + int (*writeq) (struct axon_pio_t * p_axon_pio, + plb_addr_t dst, u64 data); + + int (*readb) (struct axon_pio_t * p_axon_pio, + plb_addr_t dst, u8 * data); + int (*reads) (struct axon_pio_t * p_axon_pio, + plb_addr_t dst, u16 * data); + int (*readl) (struct axon_pio_t * p_axon_pio, + plb_addr_t dst, u32 * data); + int (*readq) (struct axon_pio_t * p_axon_pio, + plb_addr_t dst, u64 * data); + + int (*copy_toio) (struct axon_pio_t * p_axon_pio, + plb_addr_t dst, void *src, + size_t size); + int (*copy_fromio) (struct axon_pio_t * p_axon_pio, + void *dst, plb_addr_t src, + size_t size); +}; + + +#endif Index: linux/drivers/axon/include/axon_pio_pci.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/drivers/axon/include/axon_pio_pci.h 2006-12-19 17:53:10.000000000 +0100 @@ -0,0 +1,49 @@ +/****************************************************************** + * Copyright (C) 2006 Mercury Computer Systems, Inc. + * 199 Riverneck Road + * Chelmsford, MA 01824-2820 + * (978) 256-1300 + * webinfo@mc.com + * + * 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, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * http://www.gnu.org/copyleft/gpl.html + ******************************************************************/ + + +#ifndef AXON_PIO_PCI_H +#define AXON_PIO_PCI_H + +#include +#include +#include + +struct axon_pio_pci_t { + + struct axon_t *p_axon; + + struct addr_xltr_t *p_addr_xltr; + + struct axon_pim_t *p_pim; + +}; + + +int axon_pio_pci_create(struct axon_t *p_axon, + struct axon_pim_t *p_pim, + struct axon_pio_t **pp_axon_pio); +void axon_pio_pci_destroy(struct axon_pio_t *p_axon_pio); + +#endif Index: linux/drivers/axon/include/axon_ring.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/drivers/axon/include/axon_ring.h 2006-12-19 17:53:10.000000000 +0100 @@ -0,0 +1,73 @@ +/****************************************************************** + * Copyright (C) 2006 Mercury Computer Systems, Inc. + * 199 Riverneck Road + * Chelmsford, MA 01824-2820 + * (978) 256-1300 + * webinfo@mc.com + * + * 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, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * http://www.gnu.org/copyleft/gpl.html + ******************************************************************/ + + +#ifndef AXON_RING_H +#define AXON_RING_H + + +#include + +#include + +struct axon_ring_t; + + +void axon_ring_msg_alloc(struct axon_ring_t *p_axon_ring, + dma_addr_t * p_bus_addr, + void **pp_cpu_addr); + + + +size_t axon_ring_msg_max_size_get(struct axon_ring_t + *p_axon_ring); + + + + +int axon_ring_msg_pop(struct axon_ring_t *p_axon_ring, + void *msg, size_t msg_size); + + + +dma_addr_t axon_ring_base_get(struct axon_ring_t *p_axon_ring); + + + +u32 axon_ring_offset_get(struct axon_ring_t *p_axon_ring); + + + +int axon_ring_create(struct axon_t *p_axon, size_t size_order, + size_t look_ahead_window, + struct axon_ring_t **pp_axon_ring); + +void axon_ring_destroy(struct axon_ring_t *p_axon_ring); + +void axon_ring_reset(struct axon_ring_t *p_axon_ring); + +int axon_ring_has_msg(struct axon_ring_t *p_axon_ring, + int *found_idx); + +#endif Index: linux/drivers/axon/include/axon_sms.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/drivers/axon/include/axon_sms.h 2006-12-19 17:53:10.000000000 +0100 @@ -0,0 +1,183 @@ +/****************************************************************** + * Copyright (C) 2006 Mercury Computer Systems, Inc. + * 199 Riverneck Road + * Chelmsford, MA 01824-2820 + * (978) 256-1300 + * webinfo@mc.com + * + * 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, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * http://www.gnu.org/copyleft/gpl.html + ******************************************************************/ + + +#ifndef AXON_SMS_H +#define AXON_SMS_H + +#include +#include +#include + +#include +#include + + + + +#define AXON_SMS_FRAGMENTED_BIT 0x80 + + +#define AXON_SMS_FRAGMENT_PAYLOAD_SIZE_MASK 0x7 + + + +#define AXON_SMS_CHANNEL_MASK 0x7F + + +#define AXON_SMS_CHANNEL_BYTE 0x0 + + +#define AXON_SMS_FRAGMENT_BYTE 0x1 + + +#define AXON_SMS_FRAGMENT_END 0x80 + + +#define AXON_SMS_FRAGMENT_HEADER_SIZE 2 + + +#define AXON_SMS_CHANNEL_SIZE 1 + +#define AXON_SMS_CHANNEL_FRAGMENTED ((u8)0xFF) + + +#define AXON_SMS_FRAGMENTED_PAYLOAD_BYTE 0x2 +#define AXON_SMS_PAYLOAD_BYTE 0x1 + + +#define AXON_SMS_PAYLOAD_SIZE 15 + + +#define AXON_SMS_SIZE 16 + + +#define AXON_SMS_CHANNEL_NR 0x80 + + +struct axon_msg_fragment_t { + + u8 *p_data; + + + u8 free_byte; +}; + + +struct axon_sms_msg_t { + + u8 payload[AXON_SMS_PAYLOAD_SIZE]; + + + u8 channel; +}; + + +typedef int (*axon_sms_handler_t) (void *context, + struct axon_sms_msg_t * p_msg); + + +struct axon_sms_subscriber_t { + + struct list_head list; + + axon_sms_handler_t handler; + + void *context; + + int channel; +}; + +struct axon_sms_t { + + + size_t mbox_msg_size; + + + int channel_nr; + + + struct axon_msg_fragment_t *p_msg_fragments; + + + u8 *p_fragment_store; + int fragment_store_size; + + + struct axon_pio_t *p_pio; + + spinlock_t lock_send; + + + int max_atomic_write; + + struct list_head subscriber_list; + + + struct axon_mbox_t *p_mbox_self; + +}; + +#define AXON_SMS_MAX_ATOMIC_TYPE unsigned long + +#if BITS_PER_LONG > 32 + +#define AXON_SMS_MAX_ATOMIC_WRITE(value, addr) axon_writeq(value, addr) + +#else + +#define AXON_SMS_MAX_ATOMIC_WRITE(value, addr) axon_writel(value, addr) + +#endif + +int + axon_sms_encode(struct axon_sms_t *p_axon_sms, + struct axon_sms_msg_t *p_msg, + u8 * p_fragments, u8 nb_fragments, + u8 size_fragments); + +int + axon_sms_send(struct axon_sms_t *p_sms, struct axon_mbox_t *p_mbox_dst, + struct axon_sms_msg_t *p_msg); + +int + axon_sms_create(struct axon_t *p_axon, + struct axon_pio_t *p_pio, + struct axon_mbox_t *p_mbox_self, + struct axon_sms_t **pp_sms); +void axon_sms_destroy(struct axon_sms_t *p_sms); + +int + axon_sms_subscribe(struct axon_sms_t *p_axon_sms, int channel, + axon_sms_handler_t handler, + void *context); + +int + axon_sms_unsubscribe(struct axon_sms_t *p_axon_sms, int channel, + axon_sms_handler_t handler); + +void axon_sms_reset(struct axon_sms_t *p_axon_sms); + + +#endif Index: linux/drivers/axon/include/axon_sms_channels.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/drivers/axon/include/axon_sms_channels.h 2006-12-19 17:53:10.000000000 +0100 @@ -0,0 +1,55 @@ +/****************************************************************** + * Copyright (C) 2006 Mercury Computer Systems, Inc. + * 199 Riverneck Road + * Chelmsford, MA 01824-2820 + * (978) 256-1300 + * webinfo@mc.com + * + * 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, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * http://www.gnu.org/copyleft/gpl.html + ******************************************************************/ + + +#ifndef AXON_SMS_CHANNEL_H +#define AXON_SMS_CHANNEL_H + +enum axon_sms_channel_type_t { + + AXON_SMS_CHANNEL_RESERVED = 0, + + + AXON_SMS_CHANNEL_SYSTEM, + + + + AXON_SMS_CHANNEL_DMA_CPL, + + + AXON_SMS_CHANNEL_NIC, + + + AXON_SMS_CHANNEL_USR_MBX, + + + AXON_SMS_CHANNEL_USR_BUFFER, + + + AXON_SMS_CHANNEL_INVALID = 0xff, +}; + + + +#endif Index: linux/drivers/axon/include/axon_sys.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/drivers/axon/include/axon_sys.h 2006-12-19 17:53:10.000000000 +0100 @@ -0,0 +1,79 @@ +/****************************************************************** + * Copyright (C) 2006 Mercury Computer Systems, Inc. + * 199 Riverneck Road + * Chelmsford, MA 01824-2820 + * (978) 256-1300 + * webinfo@mc.com + * + * 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, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * http://www.gnu.org/copyleft/gpl.html + ******************************************************************/ + + +#ifndef AXON_SYS_H +#define AXON_SYS_H + +#include +#include +#include +#include +#include + +enum axon_sys_type_t { + AXON_SYS_INVALID, + AXON_SYS_HOST, + AXON_SYS_NODE +}; + +struct axon_sys_t { + + struct axon_t *p_axon; + + struct axon_sms_t *p_axon_sms; + + struct axon_mbox_t *p_peer_mbox; + + + plb_addr_t mbox_base_plb_addr; + + volatile u8 *p_scratchpad; + volatile u8 *p_regs_utl; + + enum axon_sys_type_t type; + + +}; + +#define AXON_SYS_SCHPAD_BOOT 0x70 + +#define AXON_SYS_RUNNING 0xfd05DEAD + +#define AXON_SYS_CHN_MBOX_ADDR_GET (u8)(0x3) +#define AXON_SYS_CHN_MBOX_ADDR_UNSET (u8)(0x4) +#define AXON_SYS_CHN_MBOX_ADDR_SET (u8)(0x5) + +int + axon_sys_create(struct axon_t *p_axon, + struct axon_sms_t *p_axon_sms, + plb_addr_t mbox_base_addr, + enum axon_sys_type_t type, + struct axon_mbox_t *p_peer_mbox, + struct axon_sys_t **pp_axon_sys); + + +void axon_sys_destroy(struct axon_sys_t *p_axon_sys); + +#endif Index: linux/drivers/axon/include/axon_types.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/drivers/axon/include/axon_types.h 2006-12-19 17:53:10.000000000 +0100 @@ -0,0 +1,81 @@ +/****************************************************************** + * Copyright (C) 2006 Mercury Computer Systems, Inc. + * 199 Riverneck Road + * Chelmsford, MA 01824-2820 + * (978) 256-1300 + * webinfo@mc.com + * + * 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, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * http://www.gnu.org/copyleft/gpl.html + ******************************************************************/ + + +#ifndef AXON_TYPES_H +#define AXON_TYPES_H + +#ifdef __KERNEL__ + +#include + +typedef u64 plb_addr_t; +typedef u64 axon_size_bus_t; + +#if defined(__x86_64__) || defined(__powerpc64__) +typedef u64 axon_addr_ptr_t; +typedef u64 axon_size_t; +#elif defined(__i386__) || ( defined(__powerpc__) && !defined(__powerpc64__) ) + +typedef u32 axon_addr_ptr_t; +typedef u32 axon_size_t; + +#else + +#error "Unsupported platform. Please add the right type mapping" + +#endif + + +#else + +#include + +typedef uint64_t plb_addr_t; +typedef uint64_t axon_size_bus_t; + + +#if defined(__x86_64__) || defined(__powerpc64__) + +typedef uint64_t axon_addr_ptr_t; +typedef uint64_t axon_size_t; + +#elif defined(__i386__) || ( defined(__powerpc__) && !defined(__powerpc64__) ) + +typedef uint32_t axon_addr_ptr_t; +typedef uint32_t axon_size_t; + +#else + +#error "Unsupported platform. Please add the right type mapping" + +#endif + +#endif + +#define AXON_INVALID_PLB_ADDR 0xFFFFFFFFFFFFFFFFULL +#define AXON_INVALID_BUS_ADDR 0xFFFFFFFFUL + + +#endif Index: linux/drivers/axon/include/axon_utils.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/drivers/axon/include/axon_utils.h 2006-12-19 17:53:10.000000000 +0100 @@ -0,0 +1,57 @@ +/****************************************************************** + * Copyright (C) 2006 Mercury Computer Systems, Inc. + * 199 Riverneck Road + * Chelmsford, MA 01824-2820 + * (978) 256-1300 + * webinfo@mc.com + * + * 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, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * http://www.gnu.org/copyleft/gpl.html + ******************************************************************/ + + +#ifndef AXON_UTILS_H +#define AXON_UTILS_H + + +#define MIN(i,j) ((i) < (j) ? (i) : (j)) + + + +#if defined(__i386__) && !defined(__x86_64__) +# define AXON_PLB_ADDR_FMT_T "llx" +# define AXON_PADDR_FMT_T "x" +# define AXON_VADDR_FMT_T "x" +# define AXON_DMA_ADDR_FMT_T "x" +# define AXON_U64_FMT_T "llx" +#elif defined(__powerpc64__) +# define AXON_PLB_ADDR_FMT_T "lx" +# define AXON_PADDR_FMT_T "lx" +# define AXON_VADDR_FMT_T "lx" +# define AXON_DMA_ADDR_FMT_T "lx" +# define AXON_U64_FMT_T "lx" +#elif defined(__x86_64__) +# define AXON_PLB_ADDR_FMT_T "llx" +# define AXON_PADDR_FMT_T "llx" +# define AXON_VADDR_FMT_T "llx" +# define AXON_DMA_ADDR_FMT_T "llx" +# define AXON_U64_FMT_T "llx" +#else +# error "Unsupported platform" +#endif + + +#endif --