Commit e8635b48 authored by David Daney's avatar David Daney Committed by Ralf Baechle

MIPS: Add Cavium OCTEON PCI support.

This patch adds support for PCI and PCIe to the base Cavium OCTEON
processor support.
Signed-off-by: default avatarDavid Daney <ddaney@caviumnetworks.com>
Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
parent 8860fb82
...@@ -618,6 +618,8 @@ config CAVIUM_OCTEON_REFERENCE_BOARD ...@@ -618,6 +618,8 @@ config CAVIUM_OCTEON_REFERENCE_BOARD
select SYS_HAS_EARLY_PRINTK select SYS_HAS_EARLY_PRINTK
select SYS_HAS_CPU_CAVIUM_OCTEON select SYS_HAS_CPU_CAVIUM_OCTEON
select SWAP_IO_SPACE select SWAP_IO_SPACE
select HW_HAS_PCI
select ARCH_SUPPORTS_MSI
help help
This option supports all of the Octeon reference boards from Cavium This option supports all of the Octeon reference boards from Cavium
Networks. It builds a kernel that dynamically determines the Octeon Networks. It builds a kernel that dynamically determines the Octeon
......
...@@ -14,5 +14,9 @@ obj-y += dma-octeon.o flash_setup.o ...@@ -14,5 +14,9 @@ obj-y += dma-octeon.o flash_setup.o
obj-y += octeon-memcpy.o obj-y += octeon-memcpy.o
obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_PCI) += pci-common.o
obj-$(CONFIG_PCI) += pci.o
obj-$(CONFIG_PCI) += pcie.o
obj-$(CONFIG_PCI_MSI) += msi.o
EXTRA_CFLAGS += -Werror EXTRA_CFLAGS += -Werror
This diff is collapsed.
...@@ -11,3 +11,4 @@ ...@@ -11,3 +11,4 @@
obj-y += cvmx-bootmem.o cvmx-l2c.o cvmx-sysinfo.o octeon-model.o obj-y += cvmx-bootmem.o cvmx-l2c.o cvmx-sysinfo.o octeon-model.o
obj-$(CONFIG_PCI) += cvmx-helper-errata.o cvmx-helper-jtag.o
/***********************license start***************
* Author: Cavium Networks
*
* Contact: support@caviumnetworks.com
* This file is part of the OCTEON SDK
*
* Copyright (c) 2003-2008 Cavium Networks
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, Version 2, as
* published by the Free Software Foundation.
*
* This file is distributed in the hope that it will be useful, but
* AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
* NONINFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
* or visit http://www.gnu.org/licenses/.
*
* This file may also be available under a different license from Cavium.
* Contact Cavium Networks for more information
***********************license end**************************************/
/**
*
* Fixes and workaround for Octeon chip errata. This file
* contains functions called by cvmx-helper to workaround known
* chip errata. For the most part, code doesn't need to call
* these functions directly.
*
*/
#include <asm/octeon/octeon.h>
#include <asm/octeon/cvmx-helper-jtag.h>
/**
* Due to errata G-720, the 2nd order CDR circuit on CN52XX pass
* 1 doesn't work properly. The following code disables 2nd order
* CDR for the specified QLM.
*
* @qlm: QLM to disable 2nd order CDR for.
*/
void __cvmx_helper_errata_qlm_disable_2nd_order_cdr(int qlm)
{
int lane;
cvmx_helper_qlm_jtag_init();
/* We need to load all four lanes of the QLM, a total of 1072 bits */
for (lane = 0; lane < 4; lane++) {
/*
* Each lane has 268 bits. We need to set
* cfg_cdr_incx<67:64> = 3 and cfg_cdr_secord<77> =
* 1. All other bits are zero. Bits go in LSB first,
* so start off with the zeros for bits <63:0>.
*/
cvmx_helper_qlm_jtag_shift_zeros(qlm, 63 - 0 + 1);
/* cfg_cdr_incx<67:64>=3 */
cvmx_helper_qlm_jtag_shift(qlm, 67 - 64 + 1, 3);
/* Zeros for bits <76:68> */
cvmx_helper_qlm_jtag_shift_zeros(qlm, 76 - 68 + 1);
/* cfg_cdr_secord<77>=1 */
cvmx_helper_qlm_jtag_shift(qlm, 77 - 77 + 1, 1);
/* Zeros for bits <267:78> */
cvmx_helper_qlm_jtag_shift_zeros(qlm, 267 - 78 + 1);
}
cvmx_helper_qlm_jtag_update(qlm);
}
/***********************license start***************
* Author: Cavium Networks
*
* Contact: support@caviumnetworks.com
* This file is part of the OCTEON SDK
*
* Copyright (c) 2003-2008 Cavium Networks
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, Version 2, as
* published by the Free Software Foundation.
*
* This file is distributed in the hope that it will be useful, but
* AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
* NONINFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
* or visit http://www.gnu.org/licenses/.
*
* This file may also be available under a different license from Cavium.
* Contact Cavium Networks for more information
***********************license end**************************************/
/**
*
* Helper utilities for qlm_jtag.
*
*/
#include <asm/octeon/octeon.h>
#include <asm/octeon/cvmx-helper-jtag.h>
/**
* Initialize the internal QLM JTAG logic to allow programming
* of the JTAG chain by the cvmx_helper_qlm_jtag_*() functions.
* These functions should only be used at the direction of Cavium
* Networks. Programming incorrect values into the JTAG chain
* can cause chip damage.
*/
void cvmx_helper_qlm_jtag_init(void)
{
union cvmx_ciu_qlm_jtgc jtgc;
uint32_t clock_div = 0;
uint32_t divisor = cvmx_sysinfo_get()->cpu_clock_hz / (25 * 1000000);
divisor = (divisor - 1) >> 2;
/* Convert the divisor into a power of 2 shift */
while (divisor) {
clock_div++;
divisor = divisor >> 1;
}
/*
* Clock divider for QLM JTAG operations. eclk is divided by
* 2^(CLK_DIV + 2)
*/
jtgc.u64 = 0;
jtgc.s.clk_div = clock_div;
jtgc.s.mux_sel = 0;
if (OCTEON_IS_MODEL(OCTEON_CN52XX))
jtgc.s.bypass = 0x3;
else
jtgc.s.bypass = 0xf;
cvmx_write_csr(CVMX_CIU_QLM_JTGC, jtgc.u64);
cvmx_read_csr(CVMX_CIU_QLM_JTGC);
}
/**
* Write up to 32bits into the QLM jtag chain. Bits are shifted
* into the MSB and out the LSB, so you should shift in the low
* order bits followed by the high order bits. The JTAG chain is
* 4 * 268 bits long, or 1072.
*
* @qlm: QLM to shift value into
* @bits: Number of bits to shift in (1-32).
* @data: Data to shift in. Bit 0 enters the chain first, followed by
* bit 1, etc.
*
* Returns The low order bits of the JTAG chain that shifted out of the
* circle.
*/
uint32_t cvmx_helper_qlm_jtag_shift(int qlm, int bits, uint32_t data)
{
union cvmx_ciu_qlm_jtgd jtgd;
jtgd.u64 = 0;
jtgd.s.shift = 1;
jtgd.s.shft_cnt = bits - 1;
jtgd.s.shft_reg = data;
if (!OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X))
jtgd.s.select = 1 << qlm;
cvmx_write_csr(CVMX_CIU_QLM_JTGD, jtgd.u64);
do {
jtgd.u64 = cvmx_read_csr(CVMX_CIU_QLM_JTGD);
} while (jtgd.s.shift);
return jtgd.s.shft_reg >> (32 - bits);
}
/**
* Shift long sequences of zeros into the QLM JTAG chain. It is
* common to need to shift more than 32 bits of zeros into the
* chain. This function is a convience wrapper around
* cvmx_helper_qlm_jtag_shift() to shift more than 32 bits of
* zeros at a time.
*
* @qlm: QLM to shift zeros into
* @bits:
*/
void cvmx_helper_qlm_jtag_shift_zeros(int qlm, int bits)
{
while (bits > 0) {
int n = bits;
if (n > 32)
n = 32;
cvmx_helper_qlm_jtag_shift(qlm, n, 0);
bits -= n;
}
}
/**
* Program the QLM JTAG chain into all lanes of the QLM. You must
* have already shifted in 268*4, or 1072 bits into the JTAG
* chain. Updating invalid values can possibly cause chip damage.
*
* @qlm: QLM to program
*/
void cvmx_helper_qlm_jtag_update(int qlm)
{
union cvmx_ciu_qlm_jtgd jtgd;
/* Update the new data */
jtgd.u64 = 0;
jtgd.s.update = 1;
if (!OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X))
jtgd.s.select = 1 << qlm;
cvmx_write_csr(CVMX_CIU_QLM_JTGD, jtgd.u64);
do {
jtgd.u64 = cvmx_read_csr(CVMX_CIU_QLM_JTGD);
} while (jtgd.s.update);
}
/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 2005-2007 Cavium Networks
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/msi.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <asm/octeon/octeon.h>
#include <asm/octeon/cvmx-npi-defs.h>
#include <asm/octeon/cvmx-pci-defs.h>
#include <asm/octeon/cvmx-npei-defs.h>
#include <asm/octeon/cvmx-pexp-defs.h>
#include "pci-common.h"
/*
* Each bit in msi_free_irq_bitmask represents a MSI interrupt that is
* in use.
*/
static uint64_t msi_free_irq_bitmask;
/*
* Each bit in msi_multiple_irq_bitmask tells that the device using
* this bit in msi_free_irq_bitmask is also using the next bit. This
* is used so we can disable all of the MSI interrupts when a device
* uses multiple.
*/
static uint64_t msi_multiple_irq_bitmask;
/*
* This lock controls updates to msi_free_irq_bitmask and
* msi_multiple_irq_bitmask.
*/
static DEFINE_SPINLOCK(msi_free_irq_bitmask_lock);
/**
* Called when a driver request MSI interrupts instead of the
* legacy INT A-D. This routine will allocate multiple interrupts
* for MSI devices that support them. A device can override this by
* programming the MSI control bits [6:4] before calling
* pci_enable_msi().
*
* @param dev Device requesting MSI interrupts
* @param desc MSI descriptor
*
* Returns 0 on success.
*/
int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
{
struct msi_msg msg;
uint16_t control;
int configured_private_bits;
int request_private_bits;
int irq;
int irq_step;
uint64_t search_mask;
/*
* Read the MSI config to figure out how many IRQs this device
* wants. Most devices only want 1, which will give
* configured_private_bits and request_private_bits equal 0.
*/
pci_read_config_word(dev, desc->msi_attrib.pos + PCI_MSI_FLAGS,
&control);
/*
* If the number of private bits has been configured then use
* that value instead of the requested number. This gives the
* driver the chance to override the number of interrupts
* before calling pci_enable_msi().
*/
configured_private_bits = (control & PCI_MSI_FLAGS_QSIZE) >> 4;
if (configured_private_bits == 0) {
/* Nothing is configured, so use the hardware requested size */
request_private_bits = (control & PCI_MSI_FLAGS_QMASK) >> 1;
} else {
/*
* Use the number of configured bits, assuming the
* driver wanted to override the hardware request
* value.
*/
request_private_bits = configured_private_bits;
}
/*
* The PCI 2.3 spec mandates that there are at most 32
* interrupts. If this device asks for more, only give it one.
*/
if (request_private_bits > 5)
request_private_bits = 0;
try_only_one:
/*
* The IRQs have to be aligned on a power of two based on the
* number being requested.
*/
irq_step = 1 << request_private_bits;
/* Mask with one bit for each IRQ */
search_mask = (1 << irq_step) - 1;
/*
* We're going to search msi_free_irq_bitmask_lock for zero
* bits. This represents an MSI interrupt number that isn't in
* use.
*/
spin_lock(&msi_free_irq_bitmask_lock);
for (irq = 0; irq < 64; irq += irq_step) {
if ((msi_free_irq_bitmask & (search_mask << irq)) == 0) {
msi_free_irq_bitmask |= search_mask << irq;
msi_multiple_irq_bitmask |= (search_mask >> 1) << irq;
break;
}
}
spin_unlock(&msi_free_irq_bitmask_lock);
/* Make sure the search for available interrupts didn't fail */
if (irq >= 64) {
if (request_private_bits) {
pr_err("arch_setup_msi_irq: Unable to find %d free "
"interrupts, trying just one",
1 << request_private_bits);
request_private_bits = 0;
goto try_only_one;
} else
panic("arch_setup_msi_irq: Unable to find a free MSI "
"interrupt");
}
/* MSI interrupts start at logical IRQ OCTEON_IRQ_MSI_BIT0 */
irq += OCTEON_IRQ_MSI_BIT0;
switch (octeon_dma_bar_type) {
case OCTEON_DMA_BAR_TYPE_SMALL:
/* When not using big bar, Bar 0 is based at 128MB */
msg.address_lo =
((128ul << 20) + CVMX_PCI_MSI_RCV) & 0xffffffff;
msg.address_hi = ((128ul << 20) + CVMX_PCI_MSI_RCV) >> 32;
case OCTEON_DMA_BAR_TYPE_BIG:
/* When using big bar, Bar 0 is based at 0 */
msg.address_lo = (0 + CVMX_PCI_MSI_RCV) & 0xffffffff;
msg.address_hi = (0 + CVMX_PCI_MSI_RCV) >> 32;
break;
case OCTEON_DMA_BAR_TYPE_PCIE:
/* When using PCIe, Bar 0 is based at 0 */
/* FIXME CVMX_NPEI_MSI_RCV* other than 0? */
msg.address_lo = (0 + CVMX_NPEI_PCIE_MSI_RCV) & 0xffffffff;
msg.address_hi = (0 + CVMX_NPEI_PCIE_MSI_RCV) >> 32;
break;
default:
panic("arch_setup_msi_irq: Invalid octeon_dma_bar_type\n");
}
msg.data = irq - OCTEON_IRQ_MSI_BIT0;
/* Update the number of IRQs the device has available to it */
control &= ~PCI_MSI_FLAGS_QSIZE;
control |= request_private_bits << 4;
pci_write_config_word(dev, desc->msi_attrib.pos + PCI_MSI_FLAGS,
control);
set_irq_msi(irq, desc);
write_msi_msg(irq, &msg);
return 0;
}
/**
* Called when a device no longer needs its MSI interrupts. All
* MSI interrupts for the device are freed.
*
* @irq: The devices first irq number. There may be multple in sequence.
*/
void arch_teardown_msi_irq(unsigned int irq)
{
int number_irqs;
uint64_t bitmask;
if ((irq < OCTEON_IRQ_MSI_BIT0) || (irq > OCTEON_IRQ_MSI_BIT63))
panic("arch_teardown_msi_irq: Attempted to teardown illegal "
"MSI interrupt (%d)", irq);
irq -= OCTEON_IRQ_MSI_BIT0;
/*
* Count the number of IRQs we need to free by looking at the
* msi_multiple_irq_bitmask. Each bit set means that the next
* IRQ is also owned by this device.
*/
number_irqs = 0;
while ((irq+number_irqs < 64) &&
(msi_multiple_irq_bitmask & (1ull << (irq + number_irqs))))
number_irqs++;
number_irqs++;
/* Mask with one bit for each IRQ */
bitmask = (1 << number_irqs) - 1;
/* Shift the mask to the correct bit location */
bitmask <<= irq;
if ((msi_free_irq_bitmask & bitmask) != bitmask)
panic("arch_teardown_msi_irq: Attempted to teardown MSI "
"interrupt (%d) not in use", irq);
/* Checks are done, update the in use bitmask */
spin_lock(&msi_free_irq_bitmask_lock);
msi_free_irq_bitmask &= ~bitmask;
msi_multiple_irq_bitmask &= ~bitmask;
spin_unlock(&msi_free_irq_bitmask_lock);
}
/**
* Called by the interrupt handling code when an MSI interrupt
* occurs.
*
* @param cpl
* @param dev_id
*
* @return
*/
static irqreturn_t octeon_msi_interrupt(int cpl, void *dev_id)
{
uint64_t msi_bits;
int irq;
if (octeon_dma_bar_type == OCTEON_DMA_BAR_TYPE_PCIE)
msi_bits = cvmx_read_csr(CVMX_PEXP_NPEI_MSI_RCV0);
else
msi_bits = cvmx_read_csr(CVMX_NPI_NPI_MSI_RCV);
irq = fls64(msi_bits);
if (irq) {
irq += OCTEON_IRQ_MSI_BIT0 - 1;
if (irq_desc[irq].action) {
do_IRQ(irq);
return IRQ_HANDLED;
} else {
pr_err("Spurious MSI interrupt %d\n", irq);
if (octeon_has_feature(OCTEON_FEATURE_PCIE)) {
/* These chips have PCIe */
cvmx_write_csr(CVMX_PEXP_NPEI_MSI_RCV0,
1ull << (irq -
OCTEON_IRQ_MSI_BIT0));
} else {
/* These chips have PCI */
cvmx_write_csr(CVMX_NPI_NPI_MSI_RCV,
1ull << (irq -
OCTEON_IRQ_MSI_BIT0));
}
}
}
return IRQ_NONE;
}
/**
* Initializes the MSI interrupt handling code
*
* @return
*/
int octeon_msi_initialize(void)
{
int r;
if (octeon_has_feature(OCTEON_FEATURE_PCIE)) {
r = request_irq(OCTEON_IRQ_PCI_MSI0, octeon_msi_interrupt,
IRQF_SHARED,
"MSI[0:63]", octeon_msi_interrupt);
} else if (octeon_is_pci_host()) {
r = request_irq(OCTEON_IRQ_PCI_MSI0, octeon_msi_interrupt,
IRQF_SHARED,
"MSI[0:15]", octeon_msi_interrupt);
r += request_irq(OCTEON_IRQ_PCI_MSI1, octeon_msi_interrupt,
IRQF_SHARED,
"MSI[16:31]", octeon_msi_interrupt);
r += request_irq(OCTEON_IRQ_PCI_MSI2, octeon_msi_interrupt,
IRQF_SHARED,
"MSI[32:47]", octeon_msi_interrupt);
r += request_irq(OCTEON_IRQ_PCI_MSI3, octeon_msi_interrupt,
IRQF_SHARED,
"MSI[48:63]", octeon_msi_interrupt);
}
return 0;
}
subsys_initcall(octeon_msi_initialize);
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
#include <linux/hardirq.h> #include <linux/hardirq.h>
#include <asm/octeon/octeon.h> #include <asm/octeon/octeon.h>
#include <asm/octeon/cvmx-pexp-defs.h>
#include <asm/octeon/cvmx-npi-defs.h>
DEFINE_RWLOCK(octeon_irq_ciu0_rwlock); DEFINE_RWLOCK(octeon_irq_ciu0_rwlock);
DEFINE_RWLOCK(octeon_irq_ciu1_rwlock); DEFINE_RWLOCK(octeon_irq_ciu1_rwlock);
......
/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 2005-2007 Cavium Networks
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/time.h>
#include <linux/delay.h>
#include "pci-common.h"
typeof(pcibios_map_irq) *octeon_pcibios_map_irq;
enum octeon_dma_bar_type octeon_dma_bar_type = OCTEON_DMA_BAR_TYPE_INVALID;
/**
* Map a PCI device to the appropriate interrupt line
*
* @param dev The Linux PCI device structure for the device to map
* @param slot The slot number for this device on __BUS 0__. Linux
* enumerates through all the bridges and figures out the
* slot on Bus 0 where this device eventually hooks to.
* @param pin The PCI interrupt pin read from the device, then swizzled
* as it goes through each bridge.
* @return Interrupt number for the device
*/
int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
{
if (octeon_pcibios_map_irq)
return octeon_pcibios_map_irq(dev, slot, pin);
else
panic("octeon_pcibios_map_irq doesn't point to a "
"pcibios_map_irq() function");
}
/**
* Called to perform platform specific PCI setup
*
* @param dev
* @return
*/
int pcibios_plat_dev_init(struct pci_dev *dev)
{
uint16_t config;
uint32_t dconfig;
int pos;
/*
* Force the Cache line setting to 64 bytes. The standard
* Linux bus scan doesn't seem to set it. Octeon really has
* 128 byte lines, but Intel bridges get really upset if you
* try and set values above 64 bytes. Value is specified in
* 32bit words.
*/
pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 64 / 4);
/* Set latency timers for all devices */
pci_write_config_byte(dev, PCI_LATENCY_TIMER, 48);
/* Enable reporting System errors and parity errors on all devices */
/* Enable parity checking and error reporting */
pci_read_config_word(dev, PCI_COMMAND, &config);
config |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR;
pci_write_config_word(dev, PCI_COMMAND, config);
if (dev->subordinate) {
/* Set latency timers on sub bridges */
pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 48);
/* More bridge error detection */
pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &config);
config |= PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR;
pci_write_config_word(dev, PCI_BRIDGE_CONTROL, config);
}
/* Enable the PCIe normal error reporting */
pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
if (pos) {
/* Update Device Control */
pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &config);
/* Correctable Error Reporting */
config |= PCI_EXP_DEVCTL_CERE;
/* Non-Fatal Error Reporting */
config |= PCI_EXP_DEVCTL_NFERE;
/* Fatal Error Reporting */
config |= PCI_EXP_DEVCTL_FERE;
/* Unsupported Request */
config |= PCI_EXP_DEVCTL_URRE;
pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, config);
}
/* Find the Advanced Error Reporting capability */
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
if (pos) {
/* Clear Uncorrectable Error Status */
pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS,
&dconfig);
pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS,
dconfig);
/* Enable reporting of all uncorrectable errors */
/* Uncorrectable Error Mask - turned on bits disable errors */
pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, 0);
/*
* Leave severity at HW default. This only controls if
* errors are reported as uncorrectable or
* correctable, not if the error is reported.
*/
/* PCI_ERR_UNCOR_SEVER - Uncorrectable Error Severity */
/* Clear Correctable Error Status */
pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS, &dconfig);
pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS, dconfig);
/* Enable reporting of all correctable errors */
/* Correctable Error Mask - turned on bits disable errors */
pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, 0);
/* Advanced Error Capabilities */
pci_read_config_dword(dev, pos + PCI_ERR_CAP, &dconfig);
/* ECRC Generation Enable */
if (config & PCI_ERR_CAP_ECRC_GENC)
config |= PCI_ERR_CAP_ECRC_GENE;
/* ECRC Check Enable */
if (config & PCI_ERR_CAP_ECRC_CHKC)
config |= PCI_ERR_CAP_ECRC_CHKE;
pci_write_config_dword(dev, pos + PCI_ERR_CAP, dconfig);
/* PCI_ERR_HEADER_LOG - Header Log Register (16 bytes) */
/* Report all errors to the root complex */
pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND,
PCI_ERR_ROOT_CMD_COR_EN |
PCI_ERR_ROOT_CMD_NONFATAL_EN |
PCI_ERR_ROOT_CMD_FATAL_EN);
/* Clear the Root status register */
pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, &dconfig);
pci_write_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, dconfig);
}
return 0;
}
/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 2005-2007 Cavium Networks
*/
#ifndef __OCTEON_PCI_COMMON_H__
#define __OCTEON_PCI_COMMON_H__
#include <linux/pci.h>
/* Some PCI cards require delays when accessing config space. */
#define PCI_CONFIG_SPACE_DELAY 10000
/* pcibios_map_irq() is defined inside pci-common.c. All it does is call the
Octeon specific version pointed to by this variable. This function needs to
change for PCI or PCIe based hosts */
extern typeof(pcibios_map_irq) *octeon_pcibios_map_irq;
/* The following defines are only used when octeon_dma_bar_type =
OCTEON_DMA_BAR_TYPE_BIG */
#define OCTEON_PCI_BAR1_HOLE_BITS 5
#define OCTEON_PCI_BAR1_HOLE_SIZE (1ul<<(OCTEON_PCI_BAR1_HOLE_BITS+3))
enum octeon_dma_bar_type {
OCTEON_DMA_BAR_TYPE_INVALID,
OCTEON_DMA_BAR_TYPE_SMALL,
OCTEON_DMA_BAR_TYPE_BIG,
OCTEON_DMA_BAR_TYPE_PCIE
};
/**
* This is a variable to tell the DMA mapping system in dma-octeon.c
* how to map PCI DMA addresses.
*/
extern enum octeon_dma_bar_type octeon_dma_bar_type;
#endif
This diff is collapsed.
This diff is collapsed.
/***********************license start***************
* Author: Cavium Networks
*
* Contact: support@caviumnetworks.com
* This file is part of the OCTEON SDK
*
* Copyright (c) 2003-2008 Cavium Networks
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, Version 2, as
* published by the Free Software Foundation.
*
* This file is distributed in the hope that it will be useful, but
* AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
* NONINFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
* or visit http://www.gnu.org/licenses/.
*
* This file may also be available under a different license from Cavium.
* Contact Cavium Networks for more information
***********************license end**************************************/
#ifndef __CVMX_HELPER_ERRATA_H__
#define __CVMX_HELPER_ERRATA_H__
extern void __cvmx_helper_errata_qlm_disable_2nd_order_cdr(int qlm);
#endif
/***********************license start***************
* Author: Cavium Networks
*
* Contact: support@caviumnetworks.com
* This file is part of the OCTEON SDK
*
* Copyright (c) 2003-2008 Cavium Networks
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, Version 2, as
* published by the Free Software Foundation.
*
* This file is distributed in the hope that it will be useful, but
* AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
* NONINFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this file; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
* or visit http://www.gnu.org/licenses/.
*
* This file may also be available under a different license from Cavium.
* Contact Cavium Networks for more information
***********************license end**************************************/
/**
* @file
*
* Helper utilities for qlm_jtag.
*
*/
#ifndef __CVMX_HELPER_JTAG_H__
#define __CVMX_HELPER_JTAG_H__
extern void cvmx_helper_qlm_jtag_init(void);
extern uint32_t cvmx_helper_qlm_jtag_shift(int qlm, int bits, uint32_t data);
extern void cvmx_helper_qlm_jtag_shift_zeros(int qlm, int bits);
extern void cvmx_helper_qlm_jtag_update(int qlm);
#endif /* __CVMX_HELPER_JTAG_H__ */
...@@ -375,6 +375,18 @@ static inline uint64_t cvmx_get_cycle(void) ...@@ -375,6 +375,18 @@ static inline uint64_t cvmx_get_cycle(void)
return cycle; return cycle;
} }
/**
* Wait for the specified number of cycle
*
*/
static inline void cvmx_wait(uint64_t cycles)
{
uint64_t done = cvmx_get_cycle() + cycles;
while (cvmx_get_cycle() < done)
; /* Spin */
}
/** /**
* Reads a chip global cycle counter. This counts CPU cycles since * Reads a chip global cycle counter. This counts CPU cycles since
* chip reset. The counter is 64 bit. * chip reset. The counter is 64 bit.
......
...@@ -245,4 +245,6 @@ static inline uint32_t octeon_npi_read32(uint64_t address) ...@@ -245,4 +245,6 @@ static inline uint32_t octeon_npi_read32(uint64_t address)
return cvmx_read64_uint32(address ^ 4); return cvmx_read64_uint32(address ^ 4);
} }
extern struct cvmx_bootinfo *octeon_bootinfo;
#endif /* __ASM_OCTEON_OCTEON_H */ #endif /* __ASM_OCTEON_OCTEON_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment