blob: 96f9209cc5e9b76a7fcad130206735a45d37c409 [file] [log] [blame]
/* Copyright 2013-2014 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __P7IOC_H
#define __P7IOC_H
#include <cec.h>
#include <pci.h>
#include <ccan/container_of/container_of.h>
/*
* Memory windows and BUID assignment
*
* - GX BAR assignment
*
* I don't know of any spec here, so we're going to mimmic what
* OPAL seems to be doing:
*
* - BAR 0 : 32M, disabled. We just leave it alone.
* - BAR 1 : 8G, enabled. Appears to correspond to the MMIO
* space of the IOC itself and the PCI IO space
* - BAR 2: 128G,
* - BAR 3: 128G,
* - BAR 4: 128G, all 3 contiguous, forming a single 368G region
* and is used for M32 and M64 PHB windows.
*
* - Memory map
*
* MWIN1 = BAR1 (8G)
* MWIN2 = BAR2,3,4 (384G)
*
* MWIN2 is divided into 6 * 4G regions for use by M32's (*) and
* 6 * 32G regions for use by M64's.
*
* (*) The M32 will typically be configured to only 2G or so, however
* the OS is in control of that setting, and since we have to reserve
* a power of two, we reserve the whole 4G.
*
* - RGC registers: MWIN1 + 0x00000000
* - PHBn IO space: MWIN1 + 0x01000000 + n * 0x00800000 (8M each)
* - PHBn M32 : MWIN2 + n * 0x1_00000000 (4G each)
* - PHBn M64 : MWIN2 + (n + 1) * 0x8_00000000 (32G each)
*
* - BUID map. The RGC has interrupts, each PHB has then its own
* interrupts (errors etc...), 4 LSIs and 256 LSIs so
* respectively 1 BUID for self, 1 for LSIs and 16 for LSIs
*
* We keep all BUIDs below 0x10 reserved. They will be used for things
* like the PSI controller, the NX unit, etc.. in the P7 chip.
*
* RGC : 0x010
* PHBn LSI : 0x040 + n * 0x40 ( 1 BUID)
* PHBn MSI : 0x060 + n * 0x40 (0x10 BUIDs)
*
* -> For routing, each PHB gets a block of 0x40 BUIDs:
*
* from 0x40 * (n + 1) to 0x7f * (n + 1)
*/
/* Some definitions resulting from the above description
*
* Note: A better approach might be to read the GX BAR content
* and isolate the biggest contiguous windows. From there
* we could divide things algorithmically and thus be
* less sensitive to a change in the memory map by the FSP
*/
#define MWIN1_SIZE 0x200000000ul /* MWIN1 is 8G */
#define MWIN2_SIZE 0x6000000000ul /* MWIN2 is 384G */
#define PHB_IO_OFFSET 0x01000000ul /* Offset of PHB IO space in MWIN1 */
#define PHB_IO_SIZE 0x00800000ul
#define PHB_M32_OFFSET 0x0ul /* Offset of PHB M32 space in MWIN2 */
#define PHB_M32_SIZE 0x100000000ul
#define PHB_M64_OFFSET 0x800000000ul /* Offset of PHB M64 space in MWIN2 */
#define PHB_M64_SIZE 0x800000000ul
#define RGC_BUID_OFFSET 0x10 /* Offset of RGC BUID */
#define PHB_BUID_OFFSET 0x40 /* Offset of PHB BUID blocks */
#define PHB_BUID_SIZE 0x40 /* Size of PHB BUID blocks */
#define PHB_BUID_LSI_OFFSET 0x00 /* Offset of LSI in PHB BUID block */
#define PHB_BUID_MSI_OFFSET 0x20 /* Offset of MSI in PHB BUID block */
#define PHB_BUID_MSI_SIZE 0x10 /* Size of PHB MSI BUID block */
#define PHBn_IO_BASE(n) (PHB_IO_OFFSET + (n) * PHB_IO_SIZE)
#define PHBn_M32_BASE(n) (PHB_M32_OFFSET + (n) * PHB_M32_SIZE)
#define PHBn_M64_BASE(n) (PHB_M64_OFFSET + (n) * PHB_M64_SIZE)
#define PHBn_BUID_BASE(n) (PHB_BUID_OFFSET + (n) * PHB_BUID_SIZE)
#define BUID_TO_PHB(buid) (((buid) - PHB_BUID_OFFSET) / PHB_BUID_SIZE)
/* p7ioc has 6 PHBs */
#define P7IOC_NUM_PHBS 6
/* M32 window setting at boot:
*
* To allow for DMA, we need to split the 32-bit PCI address space between
* MMIO and DMA. For now, we use a 2G/2G split with MMIO at the top.
*
* Note: The top 64K of the M32 space are used by MSIs. This is not
* visible here but need to be conveyed to the OS one way or another
*
* Note2: The space reserved in the system address space for M32 is always
* 4G. That we chose to use a smaller portion of it is not relevant to
* the upper levels. To keep things consistent, the offset we apply to
* the window start is also applied on the host side.
*/
#define M32_PCI_START 0x80000000
#define M32_PCI_SIZE 0x80000000
/* PHB registers exist in both a hard coded space and a programmable
* AIB space. We program the latter to the values recommended in the
* documentation:
*
* 0x80000 + n * 0x10000
*/
#define PHBn_ASB_BASE(n) (((n) << 16))
#define PHBn_ASB_SIZE 0x10000ul
#define PHBn_AIB_BASE(n) (0x80000ul + ((n) << 16))
#define PHBn_AIB_SIZE 0x10000ul
/*
* LSI interrupts
*
* The LSI interrupt block supports 8 interrupts. 4 of them are the
* standard PCIe INTA..INTB. The rest is for additional functions
* of the PHB
*/
#define PHB_LSI_PCIE_INTA 0
#define PHB_LSI_PCIE_INTB 1
#define PHB_LSI_PCIE_INTC 2
#define PHB_LSI_PCIE_INTD 3
#define PHB_LSI_PCIE_HOTPLUG 4
#define PHB_LSI_PCIE_PERFCTR 5
#define PHB_LSI_PCIE_UNUSED 6
#define PHB_LSI_PCIE_ERROR 7
/* P7IOC PHB slot states */
#define P7IOC_SLOT_NORMAL PCI_SLOT_STATE_NORMAL
#define P7IOC_SLOT_LINK PCI_SLOT_STATE_LINK
#define P7IOC_SLOT_LINK_START (P7IOC_SLOT_LINK + 1)
#define P7IOC_SLOT_LINK_WAIT (P7IOC_SLOT_LINK + 2)
#define P7IOC_SLOT_HRESET PCI_SLOT_STATE_HRESET
#define P7IOC_SLOT_HRESET_START (P7IOC_SLOT_HRESET + 1)
#define P7IOC_SLOT_HRESET_TRAINING (P7IOC_SLOT_HRESET + 2)
#define P7IOC_SLOT_HRESET_DELAY (P7IOC_SLOT_HRESET + 3)
#define P7IOC_SLOT_HRESET_DELAY2 (P7IOC_SLOT_HRESET + 4)
#define P7IOC_SLOT_FRESET PCI_SLOT_STATE_FRESET
#define P7IOC_SLOT_FRESET_START (P7IOC_SLOT_FRESET + 1)
#define P7IOC_SLOT_FRESET_TRAINING (P7IOC_SLOT_FRESET + 2)
#define P7IOC_SLOT_FRESET_POWER_OFF (P7IOC_SLOT_FRESET + 3)
#define P7IOC_SLOT_FRESET_POWER_ON (P7IOC_SLOT_FRESET + 4)
#define P7IOC_SLOT_FRESET_ASSERT (P7IOC_SLOT_FRESET + 5)
#define P7IOC_SLOT_FRESET_DEASSERT (P7IOC_SLOT_FRESET + 6)
#define P7IOC_SLOT_CRESET PCI_SLOT_STATE_CRESET
#define P7IOC_SLOT_CRESET_START (P7IOC_SLOT_CRESET + 1)
/*
* In order to support error detection and recovery on different
* types of IOCs (e.g. P5IOC, P7IOC, P8IOC), the best bet would
* be make the implementation to be 2 layers: OPAL layer and IOC
* layer. The OPAL layer just handles the general information and
* IOC layer should process much more detailed information, which
* is sensitive to itself.
*/
#define P7IOC_ERR_SRC_NONE 0
#define P7IOC_ERR_SRC_EI 1
#define P7IOC_ERR_SRC_RGC 2
#define P7IOC_ERR_SRC_BI_UP 3
#define P7IOC_ERR_SRC_BI_DOWN 4
#define P7IOC_ERR_SRC_CI_P0 5
#define P7IOC_ERR_SRC_CI_P1 6
#define P7IOC_ERR_SRC_CI_P2 7
#define P7IOC_ERR_SRC_CI_P3 8
#define P7IOC_ERR_SRC_CI_P4 9
#define P7IOC_ERR_SRC_CI_P5 10
#define P7IOC_ERR_SRC_CI_P6 11
#define P7IOC_ERR_SRC_CI_P7 12
#define P7IOC_ERR_SRC_PHB0 13
#define P7IOC_ERR_SRC_PHB1 14
#define P7IOC_ERR_SRC_PHB2 15
#define P7IOC_ERR_SRC_PHB3 16
#define P7IOC_ERR_SRC_PHB4 17
#define P7IOC_ERR_SRC_PHB5 18
#define P7IOC_ERR_SRC_MISC 19
#define P7IOC_ERR_SRC_I2C 20
#define P7IOC_ERR_SRC_LAST 21
#define P7IOC_ERR_CLASS_NONE 0
#define P7IOC_ERR_CLASS_GXE 1
#define P7IOC_ERR_CLASS_PLL 2
#define P7IOC_ERR_CLASS_RGA 3
#define P7IOC_ERR_CLASS_PHB 4
#define P7IOC_ERR_CLASS_ER 5
#define P7IOC_ERR_CLASS_INF 6
#define P7IOC_ERR_CLASS_MAL 7
#define P7IOC_ERR_CLASS_LAST 8
/*
* P7IOC error descriptor. For errors from PHB and PE, they
* will be cached to the corresponding PHBs. However, the
* left errors (e.g. EI, CI Port0/1) will be cached to the
* IOC directly.
*/
struct p7ioc_err {
uint32_t err_src;
uint32_t err_class;
uint32_t err_bit;
};
struct p7ioc;
#define P7IOC_PHB_CFG_USE_ASB 0x00000001 /* ASB to access PCI-CFG */
#define P7IOC_PHB_CFG_BLOCKED 0x00000002 /* PCI-CFG blocked except 0 */
struct p7ioc_phb {
uint8_t index; /* 0..5 index inside p7ioc */
uint8_t gen;
uint32_t flags;
bool broken;
#define P7IOC_REV_DD10 0x00a20001
#define P7IOC_REV_DD11 0x00a20002
uint32_t rev; /* Both major and minor have 2 bytes */
void *regs_asb;
void *regs; /* AIB regs */
uint32_t buid_lsi;
uint32_t buid_msi;
uint64_t io_base;
uint64_t m32_base;
uint64_t m64_base;
int64_t ecap; /* cached PCI-E cap offset */
int64_t aercap; /* cached AER ecap offset */
uint64_t lxive_cache[8];
uint64_t mxive_cache[256];
uint64_t mve_cache[256];
uint64_t peltm_cache[128];
uint64_t peltv_lo_cache[128];
uint64_t peltv_hi_cache[128];
uint64_t tve_lo_cache[128];
uint64_t tve_hi_cache[128];
uint64_t iod_cache[128];
uint64_t m32d_cache[128];
uint64_t m64b_cache[16];
uint64_t m64d_cache[128];
bool err_pending;
struct p7ioc_err err;
struct p7ioc *ioc;
struct phb phb;
};
static inline struct p7ioc_phb *phb_to_p7ioc_phb(struct phb *phb)
{
return container_of(phb, struct p7ioc_phb, phb);
}
static inline bool p7ioc_phb_err_pending(struct p7ioc_phb *p)
{
return p->err_pending;
}
static inline void p7ioc_phb_set_err_pending(struct p7ioc_phb *p, bool pending)
{
if (!pending) {
p->err.err_src = P7IOC_ERR_SRC_NONE;
p->err.err_class = P7IOC_ERR_CLASS_NONE;
p->err.err_bit = -1;
}
p->err_pending = pending;
}
/*
* State structure for P7IOC IO HUB
*/
struct p7ioc {
/* Device node */
struct dt_node *dt_node;
/* MMIO regs */
void *regs;
/* Main MMIO window from GX for registers & PCI IO space */
uint64_t mmio1_win_start;
uint64_t mmio1_win_size;
/* Secondary MMIO window for PCI MMIO space */
uint64_t mmio2_win_start;
uint64_t mmio2_win_size;
/* BUID base for the PHB. This does include the top bits
* (chip, GX bus ID, etc...). This is initialized from the
* SPIRA. It does not contain the offset 0x10 for RGC
* interrupts.
*
* The OPAL-defined "interrupt-base" property will contain
* the RGC BUID, not this base value, since this is the real
* starting point of interrupts for the IOC and we don't want
* to cover the BUID 0..f gap which is reserved for P7 on-chip
* interrupt sources.
*/
uint32_t buid_base;
uint32_t rgc_buid;
/* XIVT cache for RGC interrupts */
uint64_t xive_cache[16];
bool err_pending;
struct p7ioc_err err;
/* PHB array & presence detect */
struct p7ioc_phb phbs[P7IOC_NUM_PHBS];
uint8_t phb_pdt;
struct io_hub hub;
};
static inline struct p7ioc *iohub_to_p7ioc(struct io_hub *hub)
{
return container_of(hub, struct p7ioc, hub);
}
static inline bool p7ioc_err_pending(struct p7ioc *ioc)
{
return ioc->err_pending;
}
static inline void p7ioc_set_err_pending(struct p7ioc *ioc, bool pending)
{
if (!pending) {
ioc->err.err_src = P7IOC_ERR_SRC_NONE;
ioc->err.err_class = P7IOC_ERR_CLASS_NONE;
ioc->err.err_bit = -1;
}
ioc->err_pending = pending;
}
static inline bool p7ioc_phb_enabled(struct p7ioc *ioc, unsigned int phb)
{
return !!(ioc->phb_pdt & (0x80 >> phb));
}
extern int64_t p7ioc_inits(struct p7ioc *ioc);
extern void p7ioc_phb_setup(struct p7ioc *ioc, uint8_t index);
extern int64_t p7ioc_phb_init(struct p7ioc_phb *p);
extern bool p7ioc_check_LEM(struct p7ioc *ioc, uint16_t *pci_error_type,
uint16_t *severity);
extern int64_t p7ioc_phb_get_xive(struct p7ioc_phb *p, uint32_t isn,
uint16_t *server, uint8_t *prio);
extern int64_t p7ioc_phb_set_xive(struct p7ioc_phb *p, uint32_t isn,
uint16_t server, uint8_t prio);
extern void p7ioc_reset(struct io_hub *hub);
extern void p7ioc_phb_reset(struct phb *phb);
#endif /* __P7IOC_H */