From: Jean-Christophe DUBOIS This is the PCI specific adaptation required for the host to use the Axon driver. Signed-off-by: Jean-Christophe DUBOIS --- Index: linux/drivers/axon/pci/axon_addr_xltr_pci.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/drivers/axon/pci/axon_addr_xltr_pci.c 2006-12-19 17:55:15.000000000 +0100 @@ -0,0 +1,415 @@ +/****************************************************************** + * 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 u64 +dma_xlate_pcie_2_plb_addr_mem1(u64 pcie_addr, axon_pcie_tc_t tc, + axon_pcie_port_t port) +{ + u64 plb_addr; + + + + plb_addr = __cpu_to_be64(pcie_addr); + + dbg_log("PLB is 0x%016" AXON_PLB_ADDR_FMT_T "\n", plb_addr); + + plb_addr = be64_set_bit_range(plb_addr, + PCIe_OUTBOUND_MEM1_PORT_SELECT_hi, + PCIe_OUTBOUND_MEM1_PORT_SELECT_lo, + (port == + AXON_PCIE_PORT0) ? + PCIe_OUTBOUND_MEM1_PORT0 : + PCIe_OUTBOUND_MEM1_PORT1); + dbg_log("PLB is 0x%016" AXON_PLB_ADDR_FMT_T "\n", plb_addr); + + + if (tc == AXON_PCIE_TC0) { + plb_addr = be64_clr_bit(plb_addr, PCIe_OUTBOUND_MEM1_TC); + } else { + plb_addr = be64_set_bit(plb_addr, PCIe_OUTBOUND_MEM1_TC); + } + dbg_log("PLB is 0x%016" AXON_PLB_ADDR_FMT_T "\n", plb_addr); + + return plb_addr; + + + +} + +static u64 +dma_xlate_pcie_2_plb_addr_mem0(u64 pcie_addr, axon_pcie_tc_t tc, + axon_pcie_port_t port) +{ + u64 plb_addr; + + + + plb_addr = __cpu_to_be64(pcie_addr); + + dbg_log("1-MEM0 PLB is 0x%016" AXON_PLB_ADDR_FMT_T "\n", plb_addr); + + + plb_addr = be64_set_bit_range(plb_addr, + PCIe_OUTBOUND_MEM0_PORT_SELECT0_hi, + PCIe_OUTBOUND_MEM0_PORT_SELECT0_lo, + (port == + AXON_PCIE_PORT0) ? + PCIe_OUTBOUND_MEM0_PORT0 : + PCIe_OUTBOUND_MEM0_PORT1); + + dbg_log("2-MEM0 PLB is 0x%016" AXON_PLB_ADDR_FMT_T "\n", plb_addr); + plb_addr = be64_set_bit_range(plb_addr, + PCIe_OUTBOUND_MEM0_PORT_SELECT1_hi, + PCIe_OUTBOUND_MEM0_PORT_SELECT1_lo, + (port == + AXON_PCIE_PORT0) ? + PCIe_OUTBOUND_MEM0_PORT0 : + PCIe_OUTBOUND_MEM0_PORT1); + dbg_log("3-MEM0 PLB is 0x%016" AXON_PLB_ADDR_FMT_T "\n", plb_addr); + + if (tc == AXON_PCIE_TC0) { + plb_addr = be64_clr_bit(plb_addr, PCIe_OUTBOUND_MEM0_TC); + } else { + plb_addr = be64_set_bit(plb_addr, PCIe_OUTBOUND_MEM0_TC); + } + + dbg_log("4-MEM0 PLB is 0x%016" AXON_PLB_ADDR_FMT_T "\n", plb_addr); + + return plb_addr; + +} + +static u64 +dma_xlate_pcie_2_plb_addr(u64 pcie_addr, axon_pcie_mem_t mem, + axon_pcie_tc_t tc, axon_pcie_port_t port) +{ + if (mem == AXON_PCIE_MEM0) { + return dma_xlate_pcie_2_plb_addr_mem0(pcie_addr, tc, port); + } else { + return dma_xlate_pcie_2_plb_addr_mem1(pcie_addr, tc, port); + } + + +} + +static dma_addr_t +addr_xltr_pcie_from_plb(struct addr_xltr_t *self, plb_addr_t plb_bus_addr) +{ + + struct axon_addr_xltr_pcie_t *p_addr_xltr_pcie = self->context; + + dma_addr_t addr = AXON_INVALID_BUS_ADDR; + + + plb_bus_addr = __be64_to_cpu(plb_bus_addr); + + + + + + if ((p_addr_xltr_pcie->pim_0_base <= plb_bus_addr) + && (plb_bus_addr < p_addr_xltr_pcie->pim_0_limit)) { + + + addr = + p_addr_xltr_pcie->pim01_bar_base + (plb_bus_addr - + p_addr_xltr_pcie-> + pim_0_base); + + } else if ((p_addr_xltr_pcie->pim_1_base <= plb_bus_addr) + && (plb_bus_addr < p_addr_xltr_pcie->pim_1_limit)) { + + + addr = + p_addr_xltr_pcie->pim01_bar_base + + p_addr_xltr_pcie->pim_0_size + (plb_bus_addr - + p_addr_xltr_pcie-> + pim_1_base); + + } else if ((p_addr_xltr_pcie->pim_2_base <= plb_bus_addr) + && (plb_bus_addr < p_addr_xltr_pcie->pim_2_limit)) { + + addr = + p_addr_xltr_pcie->pim26_bar_base + (plb_bus_addr - + p_addr_xltr_pcie-> + pim_2_base); + + } else if ((p_addr_xltr_pcie->pim_6_base <= plb_bus_addr) + && (plb_bus_addr < p_addr_xltr_pcie->pim_6_limit)) { + + addr = + p_addr_xltr_pcie->pim26_bar_base + + p_addr_xltr_pcie->pim_2_size + (plb_bus_addr - + p_addr_xltr_pcie-> + pim_6_base); + + } else if ((p_addr_xltr_pcie->pim_3_base <= plb_bus_addr) + && (plb_bus_addr < p_addr_xltr_pcie->pim_3_limit)) { + + addr = + p_addr_xltr_pcie->pim34_bar_base + (plb_bus_addr - + p_addr_xltr_pcie-> + pim_3_base); + + } else if ((p_addr_xltr_pcie->pim_4_base <= plb_bus_addr) + && (plb_bus_addr < p_addr_xltr_pcie->pim_4_limit)) { + + addr = + p_addr_xltr_pcie->pim34_bar_base + + p_addr_xltr_pcie->pim_3_size + (plb_bus_addr - + p_addr_xltr_pcie-> + pim_4_base); + + } else if (AXON_PLB_PCIE_OFFSET <= plb_bus_addr) { + + addr = (dma_addr_t) (plb_bus_addr & AXON_PLB_PCIE_MASK); + } + + return addr; + +} + +static plb_addr_t +addr_xltr_pcie_to_plb(struct addr_xltr_t *self, dma_addr_t cpu_bus_addr) +{ + struct axon_addr_xltr_pcie_t *p_addr_xltr_pcie = self->context; + + plb_addr_t addr; + + + if (p_addr_xltr_pcie->pim01_bar_base <= cpu_bus_addr + && cpu_bus_addr < + (p_addr_xltr_pcie->pim01_bar_base + + p_addr_xltr_pcie->pim01_bar_size)) { + + addr = + cpu_to_be64(p_addr_xltr_pcie->pim_0_base + + (cpu_bus_addr - + p_addr_xltr_pcie->pim01_bar_base)); + + } else if (p_addr_xltr_pcie->pim26_bar_base <= cpu_bus_addr + && cpu_bus_addr < + (p_addr_xltr_pcie->pim26_bar_base + + p_addr_xltr_pcie->pim26_bar_size)) { + + addr = + cpu_to_be64(p_addr_xltr_pcie->pim_2_base + + (cpu_bus_addr - + p_addr_xltr_pcie->pim26_bar_base)); + + } else if (p_addr_xltr_pcie->pim34_bar_base <= cpu_bus_addr + && cpu_bus_addr < + (p_addr_xltr_pcie->pim26_bar_base + + p_addr_xltr_pcie->pim34_bar_size)) { + + addr = + cpu_to_be64(p_addr_xltr_pcie->pim_3_base + + (cpu_bus_addr - + p_addr_xltr_pcie->pim34_bar_base)); + + } else { + addr = dma_xlate_pcie_2_plb_addr(cpu_bus_addr, + + AXON_PCIE_MEM0, + AXON_PCIE_TC0, + AXON_PCIE_PORT0); + } + + return addr; +} + +static int +addr_xltr_pcie_is_local(struct addr_xltr_t *self, plb_addr_t plb_bus_addr) +{ + + plb_bus_addr = __be64_to_cpu(plb_bus_addr); + + if (AXON_PLB_PCIE_OFFSET <= plb_bus_addr) + return 1; + else + return 0; +} + + +int +axon_addr_xltr_pcie_create(struct addr_xltr_t **pp_addr_xlatr) +{ + int ret = 0; + + struct addr_xltr_t *p_addr_xlatr; + struct axon_addr_xltr_pcie_t *p_addr_xltr_pcie; + + p_addr_xlatr = kzalloc(sizeof(struct addr_xltr_t), GFP_KERNEL); + + if (p_addr_xlatr != NULL) { + + p_addr_xltr_pcie = + kzalloc(sizeof(struct axon_addr_xltr_pcie_t), + GFP_KERNEL); + + if (p_addr_xltr_pcie != NULL) { + p_addr_xlatr->context = p_addr_xltr_pcie; + + p_addr_xlatr->from_plb = addr_xltr_pcie_from_plb; + p_addr_xlatr->to_plb = addr_xltr_pcie_to_plb; + p_addr_xlatr->is_local = addr_xltr_pcie_is_local; + + } else { + ret = -ENOMEM; + kfree(p_addr_xlatr); + p_addr_xlatr = NULL; + dbg_log("Unable to allocate xlatr_pcie object \n"); + } + + + } else { + ret = -ENOMEM; + dbg_log("Unable to allocate xlatr object \n"); + + } + + *pp_addr_xlatr = p_addr_xlatr; + + + return ret; + +} + +int +axon_addr_xltr_pcie_update_pim(struct addr_xltr_t *p_addr_xlatr, + axon_pcie_pim_t pim, u64 size, u64 base_lo, + u64 size_lo, u64 base_hi) +{ + int ret = 0; + + struct axon_addr_xltr_pcie_t *p_addr_xltr_pcie = + p_addr_xlatr->context; + + switch (pim) { + + case AXON_PCIE_PIM01: + + p_addr_xltr_pcie->pim_0_base = base_lo; + p_addr_xltr_pcie->pim_0_limit = base_lo + size_lo; + p_addr_xltr_pcie->pim_0_size = size_lo; + + p_addr_xltr_pcie->pim_1_base = base_hi; + p_addr_xltr_pcie->pim_1_limit = base_hi + (size - size_lo); + break; + + case AXON_PCIE_PIM26: + + p_addr_xltr_pcie->pim_2_base = base_lo; + p_addr_xltr_pcie->pim_2_limit = base_lo + size_lo; + p_addr_xltr_pcie->pim_2_size = size_lo; + + p_addr_xltr_pcie->pim_6_base = base_hi; + p_addr_xltr_pcie->pim_6_limit = base_hi + (size - size_lo); + break; + + case AXON_PCIE_PIM34: + + p_addr_xltr_pcie->pim_3_base = base_lo; + p_addr_xltr_pcie->pim_3_limit = base_lo + size_lo; + p_addr_xltr_pcie->pim_3_size = size_lo; + + p_addr_xltr_pcie->pim_4_base = base_hi; + p_addr_xltr_pcie->pim_4_limit = base_hi + (size - size_lo); + break; + default: + dbg_err("Unsupported PIM update has been requested \n"); + ret = -EINVAL; + break; + } + + return ret; +} + +int +axon_addr_xltr_pcie_update_bar(struct addr_xltr_t *p_addr_xlatr, + axon_pcie_pim_t pim, u64 base, u64 size) +{ + int ret = 0; + + struct axon_addr_xltr_pcie_t *p_addr_xltr_pcie = + p_addr_xlatr->context; + +#if 1 + if (base >= AXON_PLB_PCIE_OFFSET) { + dbg_err("setting a PIM %d to PCI addr 0x%016" + AXON_PLB_ADDR_FMT_T "\n", pim, base); + } +#endif + + switch (pim) { + + case AXON_PCIE_PIM01: + + p_addr_xltr_pcie->pim01_bar_base = base; + p_addr_xltr_pcie->pim01_bar_size = size; + break; + + case AXON_PCIE_PIM26: + + p_addr_xltr_pcie->pim26_bar_base = base; + p_addr_xltr_pcie->pim26_bar_size = size; + break; + + + case AXON_PCIE_PIM34: + + p_addr_xltr_pcie->pim34_bar_base = base; + p_addr_xltr_pcie->pim34_bar_size = size; + break; + default: + dbg_err("Unsupported PIM update has been requested \n"); + ret = -EINVAL; + break; + } + + return ret; +} + +void +axon_addr_xltr_pcie_destroy(struct addr_xltr_t *p_addr_xlatr) +{ + if (p_addr_xlatr) { + if (p_addr_xlatr->context) + kfree(p_addr_xlatr->context); + + kfree(p_addr_xlatr); + } +} Index: linux/drivers/axon/pci/axon_addr_xltr_pci.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/drivers/axon/pci/axon_addr_xltr_pci.h 2006-12-19 17:55:15.000000000 +0100 @@ -0,0 +1,109 @@ +/****************************************************************** + * 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_PCIE_H +#define AXON_ADDR_XLTR_PCIE_H + +#include + +typedef enum { + AXON_PCIE_TC0, + AXON_PCIE_TC1 +} axon_pcie_tc_t; + +typedef enum { + AXON_PCIE_PORT0, + AXON_PCIE_PORT1 +} axon_pcie_port_t; + +typedef enum { + AXON_PCIE_MEM0, + AXON_PCIE_MEM1 +} axon_pcie_mem_t; + + +typedef enum { + + AXON_PCIE_PIM_INVALID, + AXON_PCIE_PIM01, + AXON_PCIE_PIM26, + AXON_PCIE_PIM34, + +} axon_pcie_pim_t; + +struct axon_addr_xltr_pcie_t { + + u64 pim_0_base; + u64 pim_0_limit; + u64 pim_0_size; + + u64 pim_1_base; + u64 pim_1_limit; + + u64 pim_2_base; + u64 pim_2_limit; + u64 pim_2_size; + + u64 pim_6_base; + u64 pim_6_limit; + + u64 pim_3_base; + u64 pim_3_limit; + u64 pim_3_size; + + u64 pim_4_base; + u64 pim_4_limit; + + u64 pim01_bar_base; + u64 pim01_bar_size; + + u64 pim26_bar_base; + u64 pim26_bar_size; + + u64 pim34_bar_base; + u64 pim34_bar_size; +}; + + + +int axon_addr_xltr_pcie_create(struct addr_xltr_t + **pp_addr_xltr); + +void axon_addr_xltr_pcie_destroy(struct addr_xltr_t + *p_addr_xltr); + +int + axon_addr_xltr_pcie_update_pim(struct addr_xltr_t *p_addr_xlatr, + axon_pcie_pim_t pim, + u64 size, u64 base_lo, + u64 size_lo, u64 base_hi); + +int + axon_addr_xltr_pcie_update_bar(struct addr_xltr_t *p_addr_xlatr, + axon_pcie_pim_t pim, + u64 base, u64 size); + + +#endif Index: linux/drivers/axon/pci/axon_pci.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/drivers/axon/pci/axon_pci.h 2006-12-19 17:55:15.000000000 +0100 @@ -0,0 +1,101 @@ +/****************************************************************** + * 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_PCI_H +#define AXON_PCI_H + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MC_AXON_PROCFS_NAME "axon" + + +typedef struct { + + int irq_nr; + + + axon_irq_handler_t handler; + + + void *context; + +} irq_handler_t; + +typedef struct { + + + struct proc_dir_entry *p_proc_dir_entry; + + char *p_cfg_base_addr; + + char *p_pcie_utl_regs; + char *p_pcie_cfg_regs; + char *p_c3po_regs; + char *p_dmax_regs; + char *p_mbox_regs; + char *p_dma_aux_regs; + + struct pci_dev *pci_dev; + + struct axon_mbox_t axon_mbox_self; + struct axon_mbox_t axon_mbox_peer; + + struct axon_dmax_t *p_axon_dmax; + + struct addr_xltr_t *p_addr_xltr; + + struct axon_pio_t *p_pio; + + struct axon_sms_t *p_sms; + + irq_handler_t irq_handlers[AXON_UTL_INTR_COUNT]; + + struct axon_t axon; + + struct axon_dma_ops_t *p_dma_ops; + + + dma_addr_t mbox_bus_addr; + + struct axon_sys_t *p_sys; + + struct axon_pim_t *p_pim; + +} axon_priv_t; + + + +#endif Index: linux/drivers/axon/pci/axon_pci_main.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/drivers/axon/pci/axon_pci_main.c 2006-12-19 17:55:15.000000000 +0100 @@ -0,0 +1,828 @@ +/****************************************************************** + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION("PCIE CAB AXON Driver"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("Arnaud Samama (asamama@mc.com)"); + +static int local_mbx_size; + +module_param(local_mbx_size, int, 0644); + +static inline void +pcie_cfg_write(axon_priv_t * p_axon_priv, u32 reg, u32 value) +{ + writel(value, p_axon_priv->p_pcie_cfg_regs + reg); + wmb(); +} + +static inline u32 +pcie_cfg_read(axon_priv_t * p_axon_priv, u32 reg) +{ + return readl(p_axon_priv->p_pcie_cfg_regs + reg); +} + +static inline void +pcie_utl_write(axon_priv_t * p_axon_priv, u32 reg, u32 value) +{ + writel(value, p_axon_priv->p_pcie_utl_regs + reg); + wmb(); +} + +static inline u32 +pcie_utl_read(axon_priv_t * p_axon_priv, u32 reg) +{ + return readl(p_axon_priv->p_pcie_utl_regs + reg); +} + +struct device * +axon_get_device(struct axon_t *p_axon) +{ + + axon_priv_t *p_axon_priv = p_axon->context; + + return &p_axon_priv->pci_dev->dev; +} + +volatile u8 * +axon_regs_dmax_get(struct axon_t *p_axon) +{ + axon_priv_t *p_axon_priv = p_axon->context; + + return p_axon_priv->p_dmax_regs; +} + +volatile u8 * +axon_regs_dma_aux_get(struct axon_t *p_axon) +{ + axon_priv_t *p_axon_priv = p_axon->context; + (void) p_axon_priv; + + return p_axon_priv->p_dma_aux_regs; +} + + +struct addr_xltr_t * +axon_addr_xltr_get(struct axon_t *p_axon) +{ + axon_priv_t *p_axon_priv = p_axon->context; + + return p_axon_priv->p_addr_xltr; +} + +struct axon_pio_t * +axon_pio_get(struct axon_t *p_axon) +{ + axon_priv_t *p_axon_priv = p_axon->context; + + return p_axon_priv->p_pio; +} + + +volatile u8 * +axon_regs_c3po_get(struct axon_t *p_axon) +{ + axon_priv_t *p_axon_priv = p_axon->context; + + return p_axon_priv->p_c3po_regs; +} + +volatile u8 * +axon_regs_dcr_get(struct axon_t *p_axon) +{ + axon_priv_t *p_axon_priv = p_axon->context; + (void) p_axon_priv; + + + return 0x0; +} + +volatile u8 * +axon_regs_mbox_get(struct axon_t *p_axon) +{ + axon_priv_t *p_axon_priv = p_axon->context; + + return p_axon_priv->p_mbox_regs; +} + +volatile u8 * +axon_regs_utl_get(struct axon_t *p_axon) +{ + axon_priv_t *p_axon_priv = p_axon->context; + + return p_axon_priv->p_pcie_utl_regs; +} + +volatile u8 * +axon_regs_pci_cfg_get(struct axon_t *p_axon) +{ + axon_priv_t *p_axon_priv = p_axon->context; + + return p_axon_priv->p_pcie_cfg_regs; +} + +static struct axon_t *p_my_axon = NULL; + +static void +axon_board_register(struct axon_t *p_axon) +{ + + p_my_axon = p_axon; +} + +static void +axon_board_unregister(struct axon_t *p_axon) +{ + p_my_axon = NULL; +} + +int +axon_board_count() +{ + if (p_my_axon == NULL) { + return 0; + } else { + return 1; + } +} + +struct axon_t ** +axon_board_list() +{ + return &p_my_axon; +} + + +struct axon_dmax_t * +axon_dmax_get(struct axon_t *p_axon) +{ + axon_priv_t *p_axon_priv = p_axon->context; + return p_axon_priv->p_axon_dmax; +} + +struct axon_mbox_t * +axon_mbox_get(struct axon_t *p_axon) +{ + axon_priv_t *p_axon_priv = p_axon->context; + return &p_axon_priv->axon_mbox_self; +} + +struct axon_mbox_t * +axon_peer_mbox_get(struct axon_t *p_axon) +{ + axon_priv_t *p_axon_priv = p_axon->context; + return &p_axon_priv->axon_mbox_peer; +} + + +struct axon_sms_t * +axon_sms_get(struct axon_t *p_axon) +{ + axon_priv_t *p_axon_priv = p_axon->context; + return p_axon_priv->p_sms; +} + + +int +axon_register_irq_handler(struct axon_t *p_axon, int irq_nr, + axon_irq_handler_t handler, char *name, + void *data) +{ + int ret = 0; + + axon_priv_t *p_axon_priv = p_axon->context; + + if (irq_nr < AXON_UTL_INTR_COUNT) { + + if (p_axon_priv->irq_handlers[irq_nr].handler == NULL) { + + u32 misr; + + p_axon_priv->irq_handlers[irq_nr].handler = + handler; + p_axon_priv->irq_handlers[irq_nr].irq_nr = irq_nr; + p_axon_priv->irq_handlers[irq_nr].context = data; + + + misr = pcie_utl_read(p_axon_priv, UTL_MISR); + + + misr = be32_set_bit(misr, irq_nr); + pcie_utl_write(p_axon_priv, UTL_MISR, misr); + + + } else { + dbg_err + ("Trying to register and irq handler for an already managed handler\n"); + ret = -EINVAL; + } + } else { + dbg_err + ("Trying to register and irq handler for an invalid interrupt level\n"); + ret = -EINVAL; + } + + return ret; +} + + +int +axon_unregister_irq_handler(struct axon_t *p_axon, int irq_nr, + axon_irq_handler_t handler) +{ + int ret = 0; + + axon_priv_t *p_axon_priv = p_axon->context; + + if (irq_nr < AXON_UTL_INTR_COUNT) { + + if (p_axon_priv->irq_handlers[irq_nr].handler == handler) { + + u32 misr; + + p_axon_priv->irq_handlers[irq_nr].handler = NULL; + p_axon_priv->irq_handlers[irq_nr].irq_nr = 0; + p_axon_priv->irq_handlers[irq_nr].context = NULL; + + + misr = pcie_utl_read(p_axon_priv, UTL_MISR); + + + misr = be32_clr_bit(misr, irq_nr); + pcie_utl_write(p_axon_priv, UTL_MISR, misr); + + } else { + dbg_err + ("Trying to unregister and irq handler from and invalid caller\n"); + ret = -EINVAL; + } + } else { + dbg_err + ("Trying to unregister and irq handler for an invalid interrupt level\n"); + ret = -EINVAL; + } + + return ret; +} + + +static irqreturn_t +axon_interrupt_handler(int irq, void *dev_id, struct pt_regs *regs) +{ +#define AXON_MAX_IRQ_COUNT 6 + irqreturn_t ret = IRQ_NONE; + int irq_nr; + int irq_count = 0; + + axon_priv_t *p_axon_priv = dev_id; + u32 issr; + + + while ((issr = pcie_utl_read(p_axon_priv, UTL_ISSR)) + && (irq_count < AXON_MAX_IRQ_COUNT)) { + +#if 1 + + + if (issr == 0xffffffff) { + static int is_dead = 0; + if (!is_dead) + dbg_err + ("The FCAB seems to be dead as it doesn't reply to read requests.\n"); + is_dead = 1; + return ret; + break; + + } +#endif + + + pcie_utl_write(p_axon_priv, UTL_ISCR, issr); + + + for (irq_nr = 0; irq_nr < AXON_UTL_INTR_COUNT; irq_nr++) { + + + if (be32_isset_bit(issr, irq_nr) && + p_axon_priv->irq_handlers[irq_nr].handler != + NULL) { + + + + p_axon_priv->irq_handlers[irq_nr]. + handler(p_axon_priv-> + irq_handlers[irq_nr].context, + irq, dev_id, regs); + + + issr = be32_clr_bit(issr, irq_nr); + + + ret = IRQ_HANDLED; + } + } + + irq_count++; + + } + + if (irq_count >= AXON_MAX_IRQ_COUNT) { + dbg_err + ("Too many interrupt loop. Aborting to avoid deadlock \n"); + } + + + + if (issr != 0x0) { + dbg_err + ("Unsupported interrupt has been generated by the Axon \n"); + } + + return ret; + +} + + +static int +axon_map_regs(axon_priv_t * p_axon_priv) +{ + int ret = 0; + + + p_axon_priv->mbox_bus_addr = + pci_resource_start(p_axon_priv->pci_dev, + AXON_PCIE_REGS_BAR) + AXON_MBOX_REGS_OFFSET; + + + p_axon_priv->p_cfg_base_addr = + ioremap_nocache(pci_resource_start + (p_axon_priv->pci_dev, AXON_PCIE_REGS_BAR), + pci_resource_len(p_axon_priv->pci_dev, + AXON_PCIE_REGS_BAR)); + + if (p_axon_priv->p_cfg_base_addr != NULL) { + + + p_axon_priv->p_pcie_utl_regs = + p_axon_priv->p_cfg_base_addr + + AXON_PCIE_UTL_REGS_OFFSET; + p_axon_priv->p_pcie_cfg_regs = + p_axon_priv->p_cfg_base_addr + + AXON_PCIE_CFG_REGS_OFFSET; + + p_axon_priv->p_c3po_regs = + p_axon_priv->p_cfg_base_addr + AXON_C3PO_REGS_OFFSET; + p_axon_priv->p_dmax_regs = + p_axon_priv->p_cfg_base_addr + AXON_DMAX_REGS_OFFSET; + p_axon_priv->p_mbox_regs = + p_axon_priv->p_cfg_base_addr + AXON_MBOX_REGS_OFFSET; + + } else { + dbg_err("Unable to map Configuration register \n"); + ret = -EINVAL; + goto err_map_cfg; + } + + dbg_log("PCIE_REGS BAR is starting at 0x%lx (len=0x%lx) \n", + pci_resource_start(p_axon_priv->pci_dev, + AXON_PCIE_REGS_BAR), + pci_resource_len(p_axon_priv->pci_dev, + AXON_PCIE_REGS_BAR)); + + dbg_log("PCIE UTL REGS mapped in 0x%p (bus=0x%lx)\n", + p_axon_priv->p_pcie_utl_regs, + virt_to_bus(p_axon_priv->p_pcie_utl_regs)); + dbg_log("PCIE CFG REGS mapped in 0x%p (bus=0x%lx)\n", + p_axon_priv->p_pcie_cfg_regs, + virt_to_bus(p_axon_priv->p_pcie_cfg_regs)); + dbg_log("AXON C3PO REGS mapped in 0x%p (bus=0x%lx)\n", + p_axon_priv->p_c3po_regs, + virt_to_bus(p_axon_priv->p_pcie_cfg_regs)); + dbg_log("AXON DMAX REGS mapped in 0x%p (bus=0x%lx)\n", + p_axon_priv->p_dmax_regs, + virt_to_bus(p_axon_priv->p_pcie_cfg_regs)); + dbg_log("AXON MBOX REGS mapped in 0x%p (bus=0x%lx)\n", + p_axon_priv->p_mbox_regs, + virt_to_bus(p_axon_priv->p_pcie_cfg_regs)); + + goto no_err; + + err_map_cfg: + + + no_err: + + return ret; + +} + + +static int +axon_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) +{ + int ret = 0; + axon_priv_t *p_axon_priv = NULL; + + u32 revclass; + + p_axon_priv = kzalloc(sizeof(axon_priv_t), GFP_KERNEL); + + if (p_axon_priv != NULL) { + plb_addr_t mbox_base_plb_addr; + dma_addr_t mbox_base_bus_addr; + + p_axon_priv->pci_dev = pci_dev; + + + p_axon_priv->axon.context = p_axon_priv; + + pci_set_drvdata(pci_dev, p_axon_priv); + + ret = pci_enable_device(pci_dev); + if (ret != 0) { + dbg_err("Unable to activate the " + PCI_DEVICE_BOARD_NAME "\n"); + goto err_pci_enable_device; + } + + + pci_set_master(pci_dev); + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) + ret = pci_request_regions(pci_dev, AXON_DRIVER_NAME); + if (ret != 0) { + dbg_err + ("Unable to request memroy region region for" + PCI_DEVICE_BOARD_NAME "\n"); + goto err_pci_request_regions; + } +#endif + + + pci_read_config_dword(pci_dev, PCICx_REVID, &revclass); + if (revclass != AXON_REVISION_ID_1) { + dbg_err("Unexpected bridge revision for " + PCI_DEVICE_BOARD_NAME + " expected=0x%08x, found=0x%08x\n", + AXON_REVISION_ID_1, revclass); + ret = -ENODEV; + goto err_revision_id; + } + + ret = axon_map_regs(p_axon_priv); + if (ret != 0) { + dbg_err + ("Unable to map configuration registers for " + PCI_DEVICE_BOARD_NAME "\n"); + goto err_map_regs; + } + + + request_irq(p_axon_priv->pci_dev->irq, + axon_interrupt_handler, + SA_SHIRQ, AXON_DRIVER_NAME, p_axon_priv); + + + ret = + axon_addr_xltr_pcie_create(&p_axon_priv->p_addr_xltr); + if (ret != 0) { + dbg_err + ("Unable to create address translator for PCIe side\n"); + goto err_create_xltr; + } + + + ret = axon_pim_create(&p_axon_priv->axon, + p_axon_priv->pci_dev, + p_axon_priv->p_addr_xltr, + &p_axon_priv->p_pim); + if (ret != 0) { + dbg_err("Unable to create PIM object\n"); + goto err_create_pim; + } + + + ret = axon_mbox_sw_create(&p_axon_priv->axon, + AXON_MBOX_LOCAL, + p_axon_priv->p_addr_xltr, + 12, + &p_axon_priv->axon_mbox_self); + if (ret != 0) { + dbg_err("Unable to create Mbox object\n"); + goto err_create_mbox_self; + } + + + ret = axon_mbox_hw_create(&p_axon_priv->axon, + p_axon_priv->p_addr_xltr, + 0, p_axon_priv->mbox_bus_addr, + &p_axon_priv->axon_mbox_peer); + if (ret != 0) { + dbg_err("Unable to create Mbox object\n"); + goto err_create_mbox_peer; + } + + ret = + axon_pio_pci_create(&p_axon_priv->axon, + p_axon_priv->p_pim, + &p_axon_priv->p_pio); + if (ret < 0) { + dbg_err("Unable to create PIO Object\n"); + goto err_create_pio; + } + + + ret = + axon_sms_create(&p_axon_priv->axon, p_axon_priv->p_pio, + &p_axon_priv->axon_mbox_self, + &p_axon_priv->p_sms); + if (ret != 0) { + dbg_err("Unable to create SMS object\n"); + goto err_create_sms; + } + + if ((ret = + axon_dma_ops_dmax_create(&p_axon_priv->axon, + AXON_DMA_CHANNEL_0, + AXON_SYS_HOST, + &p_axon_priv->p_dma_ops)) == + 0) { + dbg_log("DMAx ops engine created \n"); + } else if ((ret = + axon_dma_ops_dma_soft_create(&p_axon_priv-> + axon, + p_axon_priv-> + p_addr_xltr, + AXON_DMA_CHANNEL_0, + p_axon_priv-> + p_sms, + p_axon_priv-> + p_pio, + &p_axon_priv-> + p_dma_ops)) == + 0) { + dbg_log("Soft_DMA ops engine created \n"); + } else { + dbg_err("Failed to create any DMA ops engine\n"); + goto err_create_ops_dma; + } + + ret = axon_dma_create(&p_axon_priv->axon, + &p_axon_priv->axon_mbox_self, + &p_axon_priv->axon_mbox_peer, + p_axon_priv->p_sms, + p_axon_priv->p_addr_xltr, + p_axon_priv->p_dma_ops, + &p_axon_priv->p_axon_dmax); + if (ret != 0) { + dbg_err("Unable to create DMAx object\n"); + goto err_create_dmax; + } + + + + mbox_base_bus_addr = + mbox_sw_base_addr_get(&p_axon_priv->axon_mbox_self); + mbox_base_plb_addr = + p_axon_priv->p_addr_xltr->to_plb(p_axon_priv-> + p_addr_xltr, + mbox_base_bus_addr); + ret = + axon_sys_create(&p_axon_priv->axon, p_axon_priv->p_sms, + mbox_base_plb_addr, AXON_SYS_HOST, + &p_axon_priv->axon_mbox_peer, + &p_axon_priv->p_sys); + if (ret < 0) { + dbg_err("Unable to create system service\n"); + goto err_create_sys; + } + + + axon_board_register(&p_axon_priv->axon); + } else { + dbg_err + ("Unable to allocate memory to store private information \n"); + ret = -ENOMEM; + } + + goto no_cleanup; + + err_create_sys: + axon_dma_destroy(p_axon_priv->p_axon_dmax); + + err_create_dmax: + if (p_axon_priv->p_dma_ops) + p_axon_priv->p_dma_ops->destroy(p_axon_priv->p_dma_ops); + + err_create_ops_dma: + axon_sms_destroy(p_axon_priv->p_sms); + + err_create_sms: + axon_pio_pci_destroy(p_axon_priv->p_pio); + + err_create_pio: + axon_mbox_hw_destroy(&p_axon_priv->axon_mbox_peer); + + err_create_mbox_peer: + axon_mbox_sw_destroy(&p_axon_priv->axon_mbox_self); + + err_create_mbox_self: + axon_pim_destroy(p_axon_priv->p_pim); + + err_create_pim: + axon_addr_xltr_pcie_destroy(p_axon_priv->p_addr_xltr); + + err_create_xltr: + free_irq(p_axon_priv->pci_dev->irq, p_axon_priv); + + err_map_regs: + + + err_revision_id: +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) + pci_release_regions(pci_dev); + + err_pci_request_regions: +#endif + pci_disable_device(pci_dev); + + err_pci_enable_device: + kfree(p_axon_priv); + + no_cleanup: + return ret; + +} + + +static void +axon_remove(struct pci_dev *pci_dev) +{ + if (pci_dev) { + axon_priv_t *p_axon_priv; + + p_axon_priv = pci_get_drvdata(pci_dev); + + if (p_axon_priv) { + axon_board_unregister(&p_axon_priv->axon); + + if (p_axon_priv->p_sys) { + axon_sys_destroy(p_axon_priv->p_sys); + p_axon_priv->p_sys = NULL; + } + + if (p_axon_priv->p_axon_dmax != NULL) { + axon_dma_destroy(p_axon_priv->p_axon_dmax); + p_axon_priv->p_axon_dmax = NULL; + } + + if (p_axon_priv->p_dma_ops != NULL) { + p_axon_priv->p_dma_ops-> + destroy(p_axon_priv->p_dma_ops); + p_axon_priv->p_dma_ops = NULL; + } + + if (p_axon_priv->p_sms != NULL) { + axon_sms_destroy(p_axon_priv->p_sms); + p_axon_priv->p_sms = NULL; + } + + if (p_axon_priv->p_pio != NULL) { + axon_pio_pci_destroy(p_axon_priv->p_pio); + p_axon_priv->p_pio = NULL; + } + + axon_mbox_hw_destroy(&p_axon_priv->axon_mbox_peer); + + axon_mbox_sw_destroy(&p_axon_priv->axon_mbox_self); + + if (p_axon_priv->p_pim) { + axon_pim_destroy(p_axon_priv->p_pim); + p_axon_priv->p_pim = NULL; + } + + if (p_axon_priv->p_addr_xltr) { + axon_addr_xltr_pcie_destroy(p_axon_priv-> + p_addr_xltr); + p_axon_priv->p_addr_xltr = NULL; + } + + free_irq(p_axon_priv->pci_dev->irq, p_axon_priv); + + + if (p_axon_priv->p_cfg_base_addr != NULL) { + iounmap(p_axon_priv->p_cfg_base_addr); + p_axon_priv->p_cfg_base_addr = NULL; + } +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) + pci_release_regions(pci_dev); +#endif + + pci_disable_device(pci_dev); + + kfree(p_axon_priv); + } + } +} + +static struct pci_device_id axon_ids[] = { + + {PCI_DEVICE(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_AXON),}, + {0,} +}; + + +static struct pci_driver axon_driver = { + .name = "axon_driver", + .id_table = axon_ids, + .probe = axon_probe, + .remove = axon_remove, +}; + + +static int __init +axon_init(void) +{ + printk(KERN_INFO "Loading Axon driver into %s.\n", UTS_RELEASE); + + if (axon_create_class() == -1) { + dbg_err("Unable to create Axon class\n"); + return -1; + } + + return pci_register_driver(&axon_driver); +} + +static void __exit +axon_exit(void) +{ + printk(KERN_INFO "Unloading Axon driver.\n"); + + pci_unregister_driver(&axon_driver); + + axon_destroy_class(); +} + +module_init(axon_init); +module_exit(axon_exit); + +EXPORT_SYMBOL(axon_unregister_irq_handler); +EXPORT_SYMBOL(axon_register_irq_handler); +EXPORT_SYMBOL(axon_board_count); +EXPORT_SYMBOL(axon_board_list); +EXPORT_SYMBOL(axon_dmax_get); +EXPORT_SYMBOL(axon_mbox_get); +EXPORT_SYMBOL(axon_peer_mbox_get); +EXPORT_SYMBOL(axon_regs_utl_get); +EXPORT_SYMBOL(axon_regs_mbox_get); +EXPORT_SYMBOL(axon_addr_xltr_get); +EXPORT_SYMBOL(axon_pio_get); +EXPORT_SYMBOL(axon_sms_get); Index: linux/drivers/axon/pci/axon_pim_pci.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/drivers/axon/pci/axon_pim_pci.c 2006-12-19 17:55:15.000000000 +0100 @@ -0,0 +1,458 @@ +/****************************************************************** + * 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 + + +static inline unsigned long +axon_pim_pci_resource_start(struct pci_dev *dev, u32 bar) +{ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) + return pci_resource_start(dev, bar); +#else + u32 ret = 0xffffffff; + + switch (bar) { + case AXON_PCIE_PIM01_BAR: + pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &ret); + break; + case AXON_PCIE_PIM34_BAR: + pci_read_config_dword(dev, PCI_BASE_ADDRESS_4, &ret); + break; + default: + break; + } + + return (unsigned long) (ret & 0xfffffff0); +#endif +} + +static inline unsigned long +axon_pim_pci_resource_len(struct pci_dev *dev, u32 bar) +{ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) + return pci_resource_len(dev, bar); +#else + return 128 * 1024 * 1024; +#endif +} + +u32 +axon_pim_read(struct axon_pim_t * p_pim, u32 reg) +{ + return axon_readl(p_pim->p_pci_cfg_regs + reg); + +} + +void +axon_pim_write(struct axon_pim_t *p_pim, u32 reg, u32 value) +{ + + u32 dummy; + + axon_writel(value, p_pim->p_pci_cfg_regs + reg); + dummy = axon_readl(p_pim->p_pci_cfg_regs + reg); + +} + +void +axon_pim_unmap(struct axon_pim_t *p_pim, plb_addr_t plb_addr) +{ + + int found = 0; + + unsigned long flags; + int i_pim; + + + u64 addr = __be64_to_cpu(plb_addr); + + dbg_log("Unmap request for 0x%016" AXON_PLB_ADDR_FMT_T " \n", + addr); + + spin_lock_irqsave(&p_pim->lock, flags); + + + for (i_pim = 0; !found && i_pim < p_pim->pim_count; i_pim++) { + + u64 base_addr = addr & p_pim->pims[i_pim].mask; + + if (p_pim->pims[i_pim].base == base_addr) { + + p_pim->pims[i_pim].users--; + + found = 1; + + } + } + + spin_unlock_irqrestore(&p_pim->lock, flags); + + if (!found) { + dbg_err("Unable to unmap request for 0x%016" + AXON_PLB_ADDR_FMT_T " \n", addr); + } +} + +int +axon_pim_map(struct axon_pim_t *p_pim, plb_addr_t plb_addr, size_t size) +{ + int ret = -ENOMEM; + + int i_pim; + unsigned long flags; + int found = 0; + + + u64 addr = __be64_to_cpu(plb_addr); + + dbg_log("Processing mapping request for 0x%016" AXON_PLB_ADDR_FMT_T + "(0x%016zx bytes) \n", addr, size); + + spin_lock_irqsave(&p_pim->lock, flags); + + + for (i_pim = 0; !found && i_pim < p_pim->pim_count; i_pim++) { + + if (((addr & p_pim->pims[i_pim].mask) == + p_pim->pims[i_pim].base) + && (((addr + size) & p_pim->pims[i_pim].mask) == + p_pim->pims[i_pim].base)) { + + dbg_log + ("Found PIM #%d is matching requested mapping \n", + i_pim); + p_pim->pims[i_pim].users++; + found = 1; + } + } + + for (i_pim = 0; !found && i_pim < p_pim->pim_count; i_pim++) { + + + if (p_pim->pims[i_pim].users == 0) { + + + + + u64 base_addr = + addr & p_pim->pims[i_pim].mask; + + dbg_log("Found free PIM #%d\n", i_pim); + + + if (((addr + size) & p_pim->pims[i_pim].mask) == + base_addr) { + + axon_pim_write(p_pim, + p_pim->pims[i_pim].reg, + LE_LO32_FROM_LE64 + (base_addr)); + axon_pim_write(p_pim, + p_pim->pims[i_pim].reg + 4, + LE_HI32_FROM_LE64 + (base_addr)); + + p_pim->pims[i_pim].users++; + p_pim->pims[i_pim].base = base_addr; + + dbg_log("PIM%d lower is set to 0x%08x \n", + i_pim, + LE_LO32_FROM_LE64(base_addr)); + dbg_log("PIM%d upper is set to 0x%08x \n", + i_pim, + LE_HI32_FROM_LE64(base_addr)); + + axon_addr_xltr_pcie_update_pim(p_pim-> + p_addr_xlatr, + p_pim-> + pims[i_pim]. + bar_id, + p_pim-> + pims[i_pim]. + bar_len, + p_pim-> + pims[i_pim]. + base, + p_pim-> + pims[i_pim]. + bar_len, + 0x0ULL); + + ret = 0; + found = 1;; + + } else { + dbg_log + ("Unable to map using PIM #%d, size is too small (mask=0x%016" + AXON_U64_FMT_T ")\n", i_pim, + p_pim->pims[i_pim].mask); + + } + } + } + + spin_unlock_irqrestore(&p_pim->lock, flags); + + return ret; + +} + + +static int +axon_pim_init(struct axon_pim_t *p_pim, struct addr_xltr_t *p_addr_xlatr) +{ + u64 xdr_plb_offset; + u64 ddr_plb_offset; + u32 xdr_mapped_size; + u32 ddr_mapped_size; + + + + p_pim->pim_count = 0; + + + axon_pim_write(p_pim, PCIe_POM1_LOWER, 0x0); + axon_pim_write(p_pim, PCIe_POM1_HIGHER, 0x0); + + + dbg_log("PIM0 Upper was set to 0x%08x \n", + axon_pim_read(p_pim, PCIe_PIM0_UPPER)); + dbg_log("PIM0 Lower was set to 0x%08x \n", + axon_pim_read(p_pim, PCIe_PIM0_LOWER)); + dbg_log("PIM1 Upper was set to 0x%08x \n", + axon_pim_read(p_pim, PCIe_PIM1_UPPER)); + dbg_log("PIM1 Lower was set to 0x%08x \n", + axon_pim_read(p_pim, PCIe_PIM1_LOWER)); + dbg_log("PIM1 Size Upper was set to 0x%08x \n", + axon_pim_read(p_pim, PCIe_PIM1_SIZE_UPPER)); + dbg_log("PIM1 Size Lower was set to 0x%08x \n", + axon_pim_read(p_pim, PCIe_PIM1_SIZE_LOWER)); + + xdr_plb_offset = AXON_PLB_XDR_CHAN0_OFFSET; + axon_pim_write(p_pim, PCIe_PIM0_UPPER, + LE_HI32_FROM_LE64(xdr_plb_offset)); + axon_pim_write(p_pim, PCIe_PIM0_LOWER, + LE_LO32_FROM_LE64(xdr_plb_offset)); + + + xdr_mapped_size = + axon_pim_pci_resource_len(p_pim->pci_dev, AXON_PCIE_PIM01_BAR); + axon_pim_write(p_pim, PCIe_PIM1_SIZE_LOWER, + ~(xdr_mapped_size - 1)); + axon_pim_write(p_pim, PCIe_PIM1_SIZE_UPPER, 0xFFFFFFFF); + + p_pim->pims[p_pim->pim_count].mask = + ~(((u64) xdr_mapped_size) - 1); + p_pim->pims[p_pim->pim_count].base = xdr_plb_offset; + p_pim->pims[p_pim->pim_count].users = 0; + p_pim->pims[p_pim->pim_count].reg = PCIe_PIM0_LOWER; + p_pim->pims[p_pim->pim_count].bar_id = AXON_PCIE_PIM01; + p_pim->pims[p_pim->pim_count].bar_len = + axon_pim_pci_resource_len(p_pim->pci_dev, AXON_PCIE_PIM01_BAR); + p_pim->pim_count++; + + + + axon_addr_xltr_pcie_update_pim(p_addr_xlatr, + AXON_PCIE_PIM01, + axon_pim_pci_resource_len(p_pim-> + pci_dev, + AXON_PCIE_PIM01_BAR), + xdr_plb_offset, + axon_pim_pci_resource_len(p_pim-> + pci_dev, + AXON_PCIE_PIM01_BAR), + 0x0ULL); + + + axon_addr_xltr_pcie_update_bar(p_addr_xlatr, + AXON_PCIE_PIM01, + axon_pim_pci_resource_start(p_pim-> + pci_dev, + AXON_PCIE_PIM01_BAR), + axon_pim_pci_resource_len(p_pim-> + pci_dev, + AXON_PCIE_PIM01_BAR)); + + dbg_log("PIM0 Upper is now set to 0x%08x \n", + axon_pim_read(p_pim, PCIe_PIM0_UPPER)); + dbg_log("PIM0 Lower is now set to 0x%08x \n", + axon_pim_read(p_pim, PCIe_PIM0_LOWER)); + dbg_log("PIM1 Upper is now set to 0x%08x \n", + axon_pim_read(p_pim, PCIe_PIM1_UPPER)); + dbg_log("PIM1 Lower is now set to 0x%08x \n", + axon_pim_read(p_pim, PCIe_PIM1_LOWER)); + dbg_log("PIM1 Size Upper is now set to 0x%08x \n", + axon_pim_read(p_pim, PCIe_PIM1_SIZE_UPPER)); + dbg_log("PIM1 Size Lower is now set to 0x%08x \n", + axon_pim_read(p_pim, PCIe_PIM1_SIZE_LOWER)); + + + dbg_log("PIM3 Upper was set to 0x%08x \n", + axon_pim_read(p_pim, PCIe_PIM3_UPPER)); + dbg_log("PIM3 Lower was set to 0x%08x \n", + axon_pim_read(p_pim, PCIe_PIM3_LOWER)); + dbg_log("PIM4 Upper was set to 0x%08x \n", + axon_pim_read(p_pim, PCIe_PIM4_UPPER)); + dbg_log("PIM4 Lower was set to 0x%08x \n", + axon_pim_read(p_pim, PCIe_PIM4_LOWER)); + dbg_log("PIM34 Size Upper was set to 0x%08x \n", + axon_pim_read(p_pim, PCIe_PIM34_SIZE_UPPER)); + dbg_log("PIM34 Size Lower was set to 0x%08x \n", + axon_pim_read(p_pim, PCIe_PIM34_SIZE_LOWER)); + + + ddr_plb_offset = AXON_PLB_DDR_OFFSET; + axon_pim_write(p_pim, PCIe_PIM3_UPPER, + LE_HI32_FROM_LE64(ddr_plb_offset)); + axon_pim_write(p_pim, PCIe_PIM3_LOWER, + LE_LO32_FROM_LE64(ddr_plb_offset)); + + + ddr_mapped_size = + axon_pim_pci_resource_len(p_pim->pci_dev, AXON_PCIE_PIM34_BAR); + axon_pim_write(p_pim, PCIe_PIM34_SIZE_LOWER, + ~(ddr_mapped_size - 1)); + axon_pim_write(p_pim, PCIe_PIM34_SIZE_UPPER, 0xFFFFFFFF); + + p_pim->pims[p_pim->pim_count].mask = + ~(((u64) ddr_mapped_size) - 1); + p_pim->pims[p_pim->pim_count].base = AXON_PLB_DDR_OFFSET; + p_pim->pims[p_pim->pim_count].users = 0; + p_pim->pims[p_pim->pim_count].reg = PCIe_PIM3_LOWER; + p_pim->pims[p_pim->pim_count].bar_id = AXON_PCIE_PIM34; + p_pim->pims[p_pim->pim_count].bar_len = + axon_pim_pci_resource_len(p_pim->pci_dev, AXON_PCIE_PIM34_BAR); + p_pim->pim_count++; + + + + axon_addr_xltr_pcie_update_pim(p_addr_xlatr, + AXON_PCIE_PIM34, + axon_pim_pci_resource_len(p_pim-> + pci_dev, + AXON_PCIE_PIM34_BAR), + ddr_plb_offset, + axon_pim_pci_resource_len(p_pim-> + pci_dev, + AXON_PCIE_PIM34_BAR), + 0x0ULL); + + + axon_addr_xltr_pcie_update_bar(p_addr_xlatr, + AXON_PCIE_PIM34, + axon_pim_pci_resource_start(p_pim-> + pci_dev, + AXON_PCIE_PIM34_BAR), + axon_pim_pci_resource_len(p_pim-> + pci_dev, + AXON_PCIE_PIM34_BAR)); + + + dbg_log("PIM3 Upper is now set to 0x%08x \n", + axon_pim_read(p_pim, PCIe_PIM3_UPPER)); + dbg_log("PIM3 Lower is now set to 0x%08x \n", + axon_pim_read(p_pim, PCIe_PIM3_LOWER)); + dbg_log("PIM4 Upper is now set to 0x%08x \n", + axon_pim_read(p_pim, PCIe_PIM4_UPPER)); + dbg_log("PIM4 Lower is now set to 0x%08x \n", + axon_pim_read(p_pim, PCIe_PIM4_LOWER)); + dbg_log("PIM34 Size Upper is now set to 0x%08x \n", + axon_pim_read(p_pim, PCIe_PIM34_SIZE_UPPER)); + dbg_log("PIM34 Size Lower is now set to 0x%08x \n", + axon_pim_read(p_pim, PCIe_PIM34_SIZE_LOWER)); + + + axon_addr_xltr_pcie_update_pim(p_addr_xlatr, AXON_PCIE_PIM26, 0x4000, + AXON_PLB_REGS_SLV_OFFSET, 0x4000, + AXON_PLB_PCIE_REGS_OFFSET); + + + axon_addr_xltr_pcie_update_bar(p_addr_xlatr, + AXON_PCIE_PIM26, + pci_resource_start(p_pim->pci_dev, + AXON_PCIE_REGS_BAR), + pci_resource_len(p_pim->pci_dev, + AXON_PCIE_REGS_BAR)); + + + return 0; + +} + +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) +{ + + int ret = 0; + + struct axon_pim_t *p_pim; + + p_pim = kzalloc(sizeof(struct axon_pim_t), GFP_KERNEL); + if (p_pim != NULL) { + p_pim->p_axon = p_axon; + + p_pim->p_pci_cfg_regs = axon_regs_pci_cfg_get(p_axon); + + p_pim->p_addr_xlatr = p_addr_xlatr; + + p_pim->pci_dev = pci_dev; + + spin_lock_init(&p_pim->lock); + + axon_pim_init(p_pim, p_pim->p_addr_xlatr); + + *pp_pim = p_pim; + + } else { + dbg_err("Unable to allocate PIM object \n"); + ret = -ENOMEM; + } + + return ret; +} + +void +axon_pim_destroy(struct axon_pim_t *p_pim) +{ + if (p_pim) + kfree(p_pim); +} --