mirror of https://gitee.com/openkylin/qemu.git
221 lines
5.5 KiB
C
221 lines
5.5 KiB
C
/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
|
* Copyright 2021 IBM Corp.
|
|
*/
|
|
|
|
#ifndef __PAU_H
|
|
#define __PAU_H
|
|
|
|
#include <io.h>
|
|
#include <pci.h>
|
|
#include <xscom.h>
|
|
#include <phb4.h>
|
|
#include <pau-regs.h>
|
|
|
|
#define PAU_NBR 6
|
|
#define PAU_LINKS_OPENCAPI_PER_PAU 2
|
|
|
|
enum pau_dev_type {
|
|
PAU_DEV_TYPE_UNKNOWN = 0,
|
|
PAU_DEV_TYPE_OPENCAPI,
|
|
PAU_DEV_TYPE_ANY = INT_MAX
|
|
};
|
|
|
|
/* Used to expose a hardware BAR (or logical slice of it) outside skiboot */
|
|
struct pau_bar {
|
|
bool enable;
|
|
uint64_t addr;
|
|
uint64_t size;
|
|
uint64_t cfg;
|
|
};
|
|
|
|
struct phy_proc_state {
|
|
struct lock lock; /* protect any change to this structure */
|
|
unsigned long timeout;
|
|
uint16_t step;
|
|
};
|
|
|
|
struct pau_dev {
|
|
enum pau_dev_type type;
|
|
uint32_t index;
|
|
struct dt_node *dn;
|
|
struct phb phb;
|
|
uint32_t status;
|
|
unsigned long train_start;
|
|
unsigned long train_timeout;
|
|
|
|
struct pau_bar ntl_bar;
|
|
struct pau_bar genid_bar;
|
|
struct pau_bar memory_bar;
|
|
|
|
/* Associated I2C information */
|
|
uint8_t i2c_bus_id;
|
|
|
|
/* Associated PHY information */
|
|
uint32_t pau_unit; /* 0,3,4,5,6,7 */
|
|
uint32_t odl_index;
|
|
uint32_t op_unit; /* 0 -> 7 */
|
|
uint32_t phy_lane_mask;
|
|
|
|
struct pau *pau;
|
|
};
|
|
|
|
struct pau {
|
|
uint32_t index;
|
|
struct dt_node *dt_node;
|
|
uint32_t chip_id;
|
|
uint32_t op_chiplet; /* from pervasive: 0x10 -> 0x13 */
|
|
uint64_t xscom_base;
|
|
|
|
/* Global MMIO window (all PAU regs) */
|
|
uint64_t regs[2];
|
|
bool mmio_access;
|
|
|
|
uint32_t irq_base;
|
|
struct lock lock;
|
|
|
|
uint32_t links;
|
|
struct pau_dev devices[PAU_LINKS_OPENCAPI_PER_PAU];
|
|
struct phy_proc_state procedure_state;
|
|
};
|
|
|
|
#define PAUDBG(pau, fmt, a...) PAULOG(PR_DEBUG, pau, fmt, ##a)
|
|
#define PAUINF(pau, fmt, a...) PAULOG(PR_INFO, pau, fmt, ##a)
|
|
#define PAUERR(pau, fmt, a...) PAULOG(PR_ERR, pau, fmt, ##a)
|
|
|
|
#define PAUDEVDBG(dev, fmt, a...) PAUDEVLOG(PR_DEBUG, dev, fmt, ##a)
|
|
#define PAUDEVINF(dev, fmt, a...) PAUDEVLOG(PR_INFO, dev, fmt, ##a)
|
|
#define PAUDEVERR(dev, fmt, a...) PAUDEVLOG(PR_ERR, dev, fmt, ##a)
|
|
|
|
#define PAULOG(l, pau, fmt, a...) \
|
|
prlog(l, "PAU[%d:%d]: " fmt, (pau)->chip_id, (pau)->index, ##a)
|
|
|
|
#define PAUDEVLOG(l, dev, fmt, a...) \
|
|
prlog(l, "PAU[%d:%d:%d]: " fmt, \
|
|
(dev)->pau->chip_id, \
|
|
(dev)->pau->index, \
|
|
(dev)->index, ##a)
|
|
|
|
|
|
/* pau-scope index of the link */
|
|
static inline uint32_t pau_dev_index(struct pau_dev *dev, int links)
|
|
{
|
|
return dev->pau->index * links + dev->index;
|
|
}
|
|
|
|
static inline struct pau_dev *pau_phb_to_opencapi_dev(struct phb *phb)
|
|
{
|
|
assert(phb->phb_type == phb_type_pau_opencapi);
|
|
return container_of(phb, struct pau_dev, phb);
|
|
}
|
|
|
|
struct pau_dev *pau_next_dev(struct pau *pau, struct pau_dev *dev,
|
|
enum pau_dev_type type);
|
|
|
|
#define pau_for_each_dev_type(dev, pau, type) \
|
|
for (dev = NULL; (dev = pau_next_dev(pau, dev, type));)
|
|
|
|
#define pau_for_each_opencapi_dev(dev, pau) \
|
|
pau_for_each_dev_type(dev, pau, PAU_DEV_TYPE_OPENCAPI)
|
|
|
|
#define pau_for_each_dev(dev, pau) \
|
|
pau_for_each_dev_type(dev, pau, PAU_DEV_TYPE_ANY)
|
|
|
|
#define PAU_PHB_INDEX_BASE 6 /* immediately after real PHBs */
|
|
static inline int pau_get_phb_index(unsigned int pau_index,
|
|
unsigned int link_index)
|
|
{
|
|
return PAU_PHB_INDEX_BASE + pau_index * 2 + link_index;
|
|
}
|
|
|
|
static inline int pau_get_opal_id(unsigned int chip_id, unsigned int index)
|
|
{
|
|
return phb4_get_opal_id(chip_id, index);
|
|
}
|
|
|
|
/*
|
|
* We use the indirect method because it uses the same addresses as
|
|
* the MMIO offsets (PAU RING)
|
|
*/
|
|
static inline void pau_scom_sel(struct pau *pau, uint64_t reg,
|
|
uint64_t size)
|
|
{
|
|
uint64_t val;
|
|
|
|
val = SETFIELD(PAU_MISC_DA_ADDR, 0ull, reg);
|
|
val = SETFIELD(PAU_MISC_DA_LEN, val, size);
|
|
xscom_write(pau->chip_id,
|
|
pau->xscom_base + PAU_MISC_SCOM_IND_SCOM_ADDR,
|
|
val);
|
|
}
|
|
|
|
static inline void pau_scom_write(struct pau *pau, uint64_t reg,
|
|
uint64_t size,
|
|
uint64_t val)
|
|
{
|
|
pau_scom_sel(pau, reg, size);
|
|
xscom_write(pau->chip_id,
|
|
pau->xscom_base + PAU_MISC_SCOM_IND_SCOM_DATA,
|
|
val);
|
|
}
|
|
|
|
static inline uint64_t pau_scom_read(struct pau *pau, uint64_t reg,
|
|
uint64_t size)
|
|
{
|
|
uint64_t val;
|
|
|
|
pau_scom_sel(pau, reg, size);
|
|
xscom_read(pau->chip_id,
|
|
pau->xscom_base + PAU_MISC_SCOM_IND_SCOM_DATA,
|
|
&val);
|
|
|
|
return val;
|
|
}
|
|
|
|
static inline void pau_write(struct pau *pau, uint64_t reg,
|
|
uint64_t val)
|
|
{
|
|
void *mmio = (void *)pau->regs[0];
|
|
|
|
if (pau->mmio_access)
|
|
out_be64(mmio + reg, val);
|
|
else
|
|
pau_scom_write(pau, reg, PAU_MISC_DA_LEN_8B, val);
|
|
|
|
/* CQ_SM writes should be mirrored in all four blocks */
|
|
if (PAU_REG_BLOCK(reg) != PAU_BLOCK_CQ_SM(0))
|
|
return;
|
|
|
|
for (uint32_t i = 1; i < 4; i++)
|
|
pau_write(pau, PAU_BLOCK_CQ_SM(i) + PAU_REG_OFFSET(reg),
|
|
val);
|
|
}
|
|
|
|
static inline uint64_t pau_read(struct pau *pau, uint64_t reg)
|
|
{
|
|
void *mmio = (void *)pau->regs[0];
|
|
|
|
if (pau->mmio_access)
|
|
return in_be64(mmio + reg);
|
|
|
|
return pau_scom_read(pau, reg, PAU_MISC_DA_LEN_8B);
|
|
}
|
|
|
|
void pau_opencapi_dump_scoms(struct pau *pau);
|
|
int64_t pau_opencapi_map_atsd_lpar(struct phb *phb, uint64_t __unused bdf,
|
|
uint64_t lparid, uint64_t __unused lpcr);
|
|
int64_t pau_opencapi_spa_setup(struct phb *phb, uint32_t __unused bdfn,
|
|
uint64_t addr, uint64_t PE_mask);
|
|
int64_t pau_opencapi_spa_clear_cache(struct phb *phb,
|
|
uint32_t __unused bdfn,
|
|
uint64_t PE_handle);
|
|
int64_t pau_opencapi_tl_set(struct phb *phb, uint32_t __unused bdfn,
|
|
long capabilities, char *rate_buf);
|
|
int64_t pau_opencapi_mem_alloc(struct phb *phb, uint32_t __unused bdfn,
|
|
uint64_t size, uint64_t *bar);
|
|
int64_t pau_opencapi_mem_release(struct phb *phb, uint32_t __unused bdfn);
|
|
|
|
/* PHY */
|
|
int pau_dev_phy_reset(struct pau_dev *dev);
|
|
|
|
#endif /* __PAU_H */
|