diff options
Diffstat (limited to 'include/phb3.h')
-rw-r--r-- | include/phb3.h | 355 |
1 files changed, 355 insertions, 0 deletions
diff --git a/include/phb3.h b/include/phb3.h new file mode 100644 index 0000000..9789336 --- /dev/null +++ b/include/phb3.h @@ -0,0 +1,355 @@ +/* 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 __PHB3_H +#define __PHB3_H + +#include <interrupts.h> + +/* + * Memory map + * + * In addition to the 4K MMIO registers window, the PBCQ will + * forward down one or two large MMIO regions for use by the + * PHB. + * + * We try to use the largest MMIO window for the M64 space and + * the smallest for the M32 space, but we require at least 2G + * of M32, otherwise we carve it out of M64. + */ + +#define M32_PCI_START 0x080000000 /* Offset of the actual M32 window in PCI */ +#define M32_PCI_SIZE 0x80000000ul /* Size for M32 */ + +/* + * Interrupt map. + * + * Each PHB supports 2K interrupt sources, which is shared by + * LSI and MSI. With default configuration, MSI would use range + * [0, 0x7f7] and LSI would use [0x7f8, 0x7ff]. The interrupt + * source should be combined with IRSN to form final hardware + * IRQ. + */ +#define PHB3_MSI_IRQ_MIN 0x000 +#define PHB3_MSI_IRQ_COUNT 0x7F8 +#define PHB3_MSI_IRQ_MAX (PHB3_MSI_IRQ_MIN+PHB3_MSI_IRQ_COUNT-1) +#define PHB3_LSI_IRQ_MIN (PHB3_MSI_IRQ_COUNT) +#define PHB3_LSI_IRQ_COUNT 8 +#define PHB3_LSI_IRQ_MAX (PHB3_LSI_IRQ_MIN+PHB3_LSI_IRQ_COUNT-1) + +#define PHB3_MSI_IRQ_BASE(chip, phb) (P8_CHIP_IRQ_PHB_BASE(chip, phb) | \ + PHB3_MSI_IRQ_MIN) +#define PHB3_LSI_IRQ_BASE(chip, phb) (P8_CHIP_IRQ_PHB_BASE(chip, phb) | \ + PHB3_LSI_IRQ_MIN) +#define PHB3_IRQ_NUM(irq) (irq & 0x7FF) + +/* + * 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 PHB3_LSI_PCIE_INTA 0 +#define PHB3_LSI_PCIE_INTB 1 +#define PHB3_LSI_PCIE_INTC 2 +#define PHB3_LSI_PCIE_INTD 3 +#define PHB3_LSI_PCIE_INF 6 +#define PHB3_LSI_PCIE_ER 7 + +/* + * In-memory tables + * + * PHB3 requires a bunch of tables to be in memory instead of + * arrays inside the chip (unlike previous versions of the + * design). + * + * Some of them (IVT, etc...) will be provided by the OS via an + * OPAL call, not only not all of them, we also need to make sure + * some like PELT-V exist before we do our internal slot probing + * or bad thing would happen on error (the whole PHB would go into + * Fatal error state). + * + * So we maintain a set of tables internally for those mandatory + * ones within our core memory. They are fairly small. They can + * still be replaced by OS provided ones via OPAL APIs (and reset + * to the internal ones) so the OS can provide node local allocation + * for better performances. + * + * All those tables have to be naturally aligned + */ + +/* RTT Table : 128KB - Maps RID to PE# + * + * Entries are 2 bytes indexed by PCIe RID + */ +#define RTT_TABLE_ENTRIES 0x10000 +#define RTT_TABLE_SIZE (RTT_TABLE_ENTRIES * sizeof(struct rtt_entry)) +struct rtt_entry { + uint16_t pe_num; +}; + +/* IVT Table : MSI Interrupt vectors * state. + * + * We're sure that simics has 16-bytes IVE, totally 32KB. + * However the real HW possiblly has 128-bytes IVE, totally 256KB. + */ +#define IVT_TABLE_ENTRIES 0x800 + +/* Default to 128-bytes IVEs, uncomment that to force it back to 16-bytes */ +//#define IVT_TABLE_IVE_16B + +#ifdef IVT_TABLE_IVE_16B +#define IVT_TABLE_SIZE 0x8000 +#define IVT_TABLE_STRIDE 2 /* double-words */ +#else +#define IVT_TABLE_SIZE 0x40000 +#define IVT_TABLE_STRIDE 16 /* double-words */ +#endif + +/* PELT-V Table : 8KB - Maps PE# to PE# dependencies + * + * 256 entries of 256 bits (32 bytes) each + */ +#define PELTV_TABLE_SIZE 0x2000 + +/* PEST Table : 4KB - PE state table + * + * 256 entries of 16 bytes each containing state bits for each PE + * + * AFAIK: This acts as a backup for an on-chip cache and shall be + * accessed via the indirect IODA table access registers only + */ +#define PEST_TABLE_SIZE 0x1000 + +/* RBA Table : 256 bytes - Reject Bit Array + * + * 2048 interrupts, 1 bit each, indiates the reject state of interrupts + */ +#define RBA_TABLE_SIZE 0x100 + +/* + * Maximal supported PE# in PHB3. We probably probe it from EEH + * capability register later. + */ +#define PHB3_MAX_PE_NUM 256 + +/* + * State structure for a PHB + */ + +/* + * (Comment copied from p7ioc.h, please update both when relevant) + * + * The PHB State structure is essentially used during PHB reset + * or recovery operations to indicate that the PHB cannot currently + * be used for normal operations. + * + * Some states involve waiting for the timebase to reach a certain + * value. In which case the field "delay_tgt_tb" is set and the + * state machine will be run from the "state_poll" callback. + * + * At IPL time, we call this repeatedly during the various sequences + * however under OS control, this will require a change in API. + * + * Fortunately, the OPAL API for slot power & reset are not currently + * used by Linux, so changing them isn't going to be an issue. The idea + * here is that some of these APIs will return a positive integer when + * neededing such a delay to proceed. The OS will then be required to + * call a new function opal_poll_phb() after that delay. That function + * will potentially return a new delay, or OPAL_SUCCESS when the original + * operation has completed successfully. If the operation has completed + * with an error, then opal_poll_phb() will return that error. + * + * Note: Should we consider also returning optionally some indication + * of what operation is in progress for OS debug/diag purposes ? + * + * Any attempt at starting a new "asynchronous" operation while one is + * already in progress will result in an error. + * + * Internally, this is represented by the state being P7IOC_PHB_STATE_FUNCTIONAL + * when no operation is in progress, which it reaches at the end of the + * boot time initializations. Any attempt at performing a slot operation + * on a PHB in that state will change the state to the corresponding + * operation state machine. Any attempt while not in that state will + * return an error. + * + * Some operations allow for a certain amount of retries, this is + * provided for by the "retries" structure member for use by the state + * machine as it sees fit. + */ +enum phb3_state { + /* First init state */ + PHB3_STATE_UNINITIALIZED, + + /* During PHB HW inits */ + PHB3_STATE_INITIALIZING, + + /* Set if the PHB is for some reason unusable */ + PHB3_STATE_BROKEN, + + /* PHB fenced */ + PHB3_STATE_FENCED, + + /* Normal PHB functional state */ + PHB3_STATE_FUNCTIONAL, + + /* Hot reset */ + PHB3_STATE_HRESET_DELAY, + PHB3_STATE_HRESET_DELAY2, + + /* Fundamental reset */ + PHB3_STATE_FRESET_ASSERT_DELAY, + PHB3_STATE_FRESET_DEASSERT_DELAY, + + /* Complete reset */ + PHB3_STATE_CRESET_WAIT_CQ, + PHB3_STATE_CRESET_REINIT, + PHB3_STATE_CRESET_FRESET, + + /* Link state machine */ + PHB3_STATE_WAIT_LINK_ELECTRICAL, + PHB3_STATE_WAIT_LINK, +}; + +/* + * PHB3 error descriptor. Errors from all components (PBCQ, PHB) + * will be cached to PHB3 instance. However, PBCQ errors would + * have higher priority than those from PHB + */ +#define PHB3_ERR_SRC_NONE 0 +#define PHB3_ERR_SRC_PBCQ 1 +#define PHB3_ERR_SRC_PHB 2 + +#define PHB3_ERR_CLASS_NONE 0 +#define PHB3_ERR_CLASS_DEAD 1 +#define PHB3_ERR_CLASS_FENCED 2 +#define PHB3_ERR_CLASS_ER 3 +#define PHB3_ERR_CLASS_INF 4 +#define PHB3_ERR_CLASS_LAST 5 + +struct phb3_err { + uint32_t err_src; + uint32_t err_class; + uint32_t err_bit; +}; + +/* Link timeouts, increments of 100ms */ +#define PHB3_LINK_WAIT_RETRIES 20 +#define PHB3_LINK_ELECTRICAL_RETRIES 10 + +/* PHB3 flags */ +#define PHB3_AIB_FENCED 0x00000001 +#define PHB3_CFG_USE_ASB 0x00000002 +#define PHB3_CFG_BLOCKED 0x00000004 + +struct phb3 { + unsigned int index; /* 0..2 index inside P8 */ + unsigned int flags; + unsigned int chip_id; /* Chip ID (== GCID on P8) */ + unsigned int rev; /* 00MMmmmm */ +#define PHB3_REV_MURANO_DD10 0xa30001 +#define PHB3_REV_VENICE_DD10 0xa30002 +#define PHB3_REV_MURANO_DD20 0xa30003 +#define PHB3_REV_MURANO_DD21 0xa30004 +#define PHB3_REV_VENICE_DD20 0xa30005 + void *regs; + uint64_t pe_xscom; /* XSCOM bases */ + uint64_t pci_xscom; + uint64_t spci_xscom; + struct lock lock; + uint64_t mm0_base; /* Full MM window to PHB */ + uint64_t mm0_size; /* '' '' '' */ + uint64_t mm1_base; /* Full MM window to PHB */ + uint64_t mm1_size; /* '' '' '' */ + uint32_t base_msi; + uint32_t base_lsi; + + /* SkiBoot owned in-memory tables */ + uint64_t tbl_rtt; + uint64_t tbl_peltv; + uint64_t tbl_pest; + uint64_t tbl_ivt; + uint64_t tbl_rba; + + bool skip_perst; /* Skip first perst */ + bool has_link; + bool use_ab_detect; + enum phb3_state state; + uint64_t delay_tgt_tb; + uint64_t retries; + int64_t ecap; /* cached PCI-E cap offset */ + int64_t aercap; /* cached AER ecap offset */ + const __be64 *lane_eq; + uint64_t capp_ucode_base; + bool capp_ucode_loaded; + unsigned int max_link_speed; + + uint16_t rte_cache[RTT_TABLE_SIZE/2]; + uint8_t peltv_cache[PELTV_TABLE_SIZE]; + uint64_t lxive_cache[8]; + uint64_t ive_cache[IVT_TABLE_ENTRIES]; + uint64_t tve_cache[512]; + uint64_t m32d_cache[256]; + uint64_t m64b_cache[16]; + uint64_t nfir_cache; /* Used by complete reset */ + bool err_pending; + struct phb3_err err; + + struct phb phb; +}; + +static inline struct phb3 *phb_to_phb3(struct phb *phb) +{ + return container_of(phb, struct phb3, phb); +} + +static inline uint64_t phb3_read_reg_asb(struct phb3 *p, uint64_t offset) +{ + uint64_t val; + + xscom_write(p->chip_id, p->spci_xscom, offset); + xscom_read(p->chip_id, p->spci_xscom + 0x2, &val); + + return val; +} + +static inline void phb3_write_reg_asb(struct phb3 *p, + uint64_t offset, uint64_t val) +{ + xscom_write(p->chip_id, p->spci_xscom, offset); + xscom_write(p->chip_id, p->spci_xscom + 0x2, val); +} + +static inline bool phb3_err_pending(struct phb3 *p) +{ + return p->err_pending; +} + +static inline void phb3_set_err_pending(struct phb3 *p, bool pending) +{ + if (!pending) { + p->err.err_src = PHB3_ERR_SRC_NONE; + p->err.err_class = PHB3_ERR_CLASS_NONE; + p->err.err_bit = -1; + } + + p->err_pending = pending; +} + +#endif /* __PHB3_H */ |