OpenCloudOS-Kernel/drivers/misc/cxl/pci.c

1742 lines
48 KiB
C
Raw Normal View History

/*
* Copyright 2014 IBM Corp.
*
* 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.
*/
#include <linux/pci_regs.h>
#include <linux/pci_ids.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/sort.h>
#include <linux/pci.h>
#include <linux/of.h>
#include <linux/delay.h>
#include <asm/opal.h>
#include <asm/msi_bitmap.h>
#include <asm/pnv-pci.h>
#include <asm/io.h>
#include <asm/reg.h>
#include "cxl.h"
#include <misc/cxl.h>
#define CXL_PCI_VSEC_ID 0x1280
#define CXL_VSEC_MIN_SIZE 0x80
#define CXL_READ_VSEC_LENGTH(dev, vsec, dest) \
{ \
pci_read_config_word(dev, vsec + 0x6, dest); \
*dest >>= 4; \
}
#define CXL_READ_VSEC_NAFUS(dev, vsec, dest) \
pci_read_config_byte(dev, vsec + 0x8, dest)
#define CXL_READ_VSEC_STATUS(dev, vsec, dest) \
pci_read_config_byte(dev, vsec + 0x9, dest)
#define CXL_STATUS_SECOND_PORT 0x80
#define CXL_STATUS_MSI_X_FULL 0x40
#define CXL_STATUS_MSI_X_SINGLE 0x20
#define CXL_STATUS_FLASH_RW 0x08
#define CXL_STATUS_FLASH_RO 0x04
#define CXL_STATUS_LOADABLE_AFU 0x02
#define CXL_STATUS_LOADABLE_PSL 0x01
/* If we see these features we won't try to use the card */
#define CXL_UNSUPPORTED_FEATURES \
(CXL_STATUS_MSI_X_FULL | CXL_STATUS_MSI_X_SINGLE)
#define CXL_READ_VSEC_MODE_CONTROL(dev, vsec, dest) \
pci_read_config_byte(dev, vsec + 0xa, dest)
#define CXL_WRITE_VSEC_MODE_CONTROL(dev, vsec, val) \
pci_write_config_byte(dev, vsec + 0xa, val)
#define CXL_VSEC_PROTOCOL_MASK 0xe0
#define CXL_VSEC_PROTOCOL_1024TB 0x80
#define CXL_VSEC_PROTOCOL_512TB 0x40
#define CXL_VSEC_PROTOCOL_256TB 0x20 /* Power 8 uses this */
#define CXL_VSEC_PROTOCOL_ENABLE 0x01
#define CXL_READ_VSEC_PSL_REVISION(dev, vsec, dest) \
pci_read_config_word(dev, vsec + 0xc, dest)
#define CXL_READ_VSEC_CAIA_MINOR(dev, vsec, dest) \
pci_read_config_byte(dev, vsec + 0xe, dest)
#define CXL_READ_VSEC_CAIA_MAJOR(dev, vsec, dest) \
pci_read_config_byte(dev, vsec + 0xf, dest)
#define CXL_READ_VSEC_BASE_IMAGE(dev, vsec, dest) \
pci_read_config_word(dev, vsec + 0x10, dest)
#define CXL_READ_VSEC_IMAGE_STATE(dev, vsec, dest) \
pci_read_config_byte(dev, vsec + 0x13, dest)
#define CXL_WRITE_VSEC_IMAGE_STATE(dev, vsec, val) \
pci_write_config_byte(dev, vsec + 0x13, val)
#define CXL_VSEC_USER_IMAGE_LOADED 0x80 /* RO */
#define CXL_VSEC_PERST_LOADS_IMAGE 0x20 /* RW */
#define CXL_VSEC_PERST_SELECT_USER 0x10 /* RW */
#define CXL_READ_VSEC_AFU_DESC_OFF(dev, vsec, dest) \
pci_read_config_dword(dev, vsec + 0x20, dest)
#define CXL_READ_VSEC_AFU_DESC_SIZE(dev, vsec, dest) \
pci_read_config_dword(dev, vsec + 0x24, dest)
#define CXL_READ_VSEC_PS_OFF(dev, vsec, dest) \
pci_read_config_dword(dev, vsec + 0x28, dest)
#define CXL_READ_VSEC_PS_SIZE(dev, vsec, dest) \
pci_read_config_dword(dev, vsec + 0x2c, dest)
/* This works a little different than the p1/p2 register accesses to make it
* easier to pull out individual fields */
#define AFUD_READ(afu, off) in_be64(afu->native->afu_desc_mmio + off)
#define AFUD_READ_LE(afu, off) in_le64(afu->native->afu_desc_mmio + off)
#define EXTRACT_PPC_BIT(val, bit) (!!(val & PPC_BIT(bit)))
#define EXTRACT_PPC_BITS(val, bs, be) ((val & PPC_BITMASK(bs, be)) >> PPC_BITLSHIFT(be))
#define AFUD_READ_INFO(afu) AFUD_READ(afu, 0x0)
#define AFUD_NUM_INTS_PER_PROC(val) EXTRACT_PPC_BITS(val, 0, 15)
#define AFUD_NUM_PROCS(val) EXTRACT_PPC_BITS(val, 16, 31)
#define AFUD_NUM_CRS(val) EXTRACT_PPC_BITS(val, 32, 47)
#define AFUD_MULTIMODE(val) EXTRACT_PPC_BIT(val, 48)
#define AFUD_PUSH_BLOCK_TRANSFER(val) EXTRACT_PPC_BIT(val, 55)
#define AFUD_DEDICATED_PROCESS(val) EXTRACT_PPC_BIT(val, 59)
#define AFUD_AFU_DIRECTED(val) EXTRACT_PPC_BIT(val, 61)
#define AFUD_TIME_SLICED(val) EXTRACT_PPC_BIT(val, 63)
#define AFUD_READ_CR(afu) AFUD_READ(afu, 0x20)
#define AFUD_CR_LEN(val) EXTRACT_PPC_BITS(val, 8, 63)
#define AFUD_READ_CR_OFF(afu) AFUD_READ(afu, 0x28)
#define AFUD_READ_PPPSA(afu) AFUD_READ(afu, 0x30)
#define AFUD_PPPSA_PP(val) EXTRACT_PPC_BIT(val, 6)
#define AFUD_PPPSA_PSA(val) EXTRACT_PPC_BIT(val, 7)
#define AFUD_PPPSA_LEN(val) EXTRACT_PPC_BITS(val, 8, 63)
#define AFUD_READ_PPPSA_OFF(afu) AFUD_READ(afu, 0x38)
#define AFUD_READ_EB(afu) AFUD_READ(afu, 0x40)
#define AFUD_EB_LEN(val) EXTRACT_PPC_BITS(val, 8, 63)
#define AFUD_READ_EB_OFF(afu) AFUD_READ(afu, 0x48)
static const struct pci_device_id cxl_pci_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_IBM, 0x0477), },
{ PCI_DEVICE(PCI_VENDOR_ID_IBM, 0x044b), },
{ PCI_DEVICE(PCI_VENDOR_ID_IBM, 0x04cf), },
{ PCI_DEVICE(PCI_VENDOR_ID_IBM, 0x0601), },
{ PCI_DEVICE_CLASS(0x120000, ~0), },
{ }
};
MODULE_DEVICE_TABLE(pci, cxl_pci_tbl);
/*
* Mostly using these wrappers to avoid confusion:
* priv 1 is BAR2, while priv 2 is BAR0
*/
static inline resource_size_t p1_base(struct pci_dev *dev)
{
return pci_resource_start(dev, 2);
}
static inline resource_size_t p1_size(struct pci_dev *dev)
{
return pci_resource_len(dev, 2);
}
static inline resource_size_t p2_base(struct pci_dev *dev)
{
return pci_resource_start(dev, 0);
}
static inline resource_size_t p2_size(struct pci_dev *dev)
{
return pci_resource_len(dev, 0);
}
static int find_cxl_vsec(struct pci_dev *dev)
{
int vsec = 0;
u16 val;
while ((vsec = pci_find_next_ext_capability(dev, vsec, PCI_EXT_CAP_ID_VNDR))) {
pci_read_config_word(dev, vsec + 0x4, &val);
if (val == CXL_PCI_VSEC_ID)
return vsec;
}
return 0;
}
static void dump_cxl_config_space(struct pci_dev *dev)
{
int vsec;
u32 val;
dev_info(&dev->dev, "dump_cxl_config_space\n");
pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &val);
dev_info(&dev->dev, "BAR0: %#.8x\n", val);
pci_read_config_dword(dev, PCI_BASE_ADDRESS_1, &val);
dev_info(&dev->dev, "BAR1: %#.8x\n", val);
pci_read_config_dword(dev, PCI_BASE_ADDRESS_2, &val);
dev_info(&dev->dev, "BAR2: %#.8x\n", val);
pci_read_config_dword(dev, PCI_BASE_ADDRESS_3, &val);
dev_info(&dev->dev, "BAR3: %#.8x\n", val);
pci_read_config_dword(dev, PCI_BASE_ADDRESS_4, &val);
dev_info(&dev->dev, "BAR4: %#.8x\n", val);
pci_read_config_dword(dev, PCI_BASE_ADDRESS_5, &val);
dev_info(&dev->dev, "BAR5: %#.8x\n", val);
dev_info(&dev->dev, "p1 regs: %#llx, len: %#llx\n",
p1_base(dev), p1_size(dev));
dev_info(&dev->dev, "p2 regs: %#llx, len: %#llx\n",
p2_base(dev), p2_size(dev));
dev_info(&dev->dev, "BAR 4/5: %#llx, len: %#llx\n",
pci_resource_start(dev, 4), pci_resource_len(dev, 4));
if (!(vsec = find_cxl_vsec(dev)))
return;
#define show_reg(name, what) \
dev_info(&dev->dev, "cxl vsec: %30s: %#x\n", name, what)
pci_read_config_dword(dev, vsec + 0x0, &val);
show_reg("Cap ID", (val >> 0) & 0xffff);
show_reg("Cap Ver", (val >> 16) & 0xf);
show_reg("Next Cap Ptr", (val >> 20) & 0xfff);
pci_read_config_dword(dev, vsec + 0x4, &val);
show_reg("VSEC ID", (val >> 0) & 0xffff);
show_reg("VSEC Rev", (val >> 16) & 0xf);
show_reg("VSEC Length", (val >> 20) & 0xfff);
pci_read_config_dword(dev, vsec + 0x8, &val);
show_reg("Num AFUs", (val >> 0) & 0xff);
show_reg("Status", (val >> 8) & 0xff);
show_reg("Mode Control", (val >> 16) & 0xff);
show_reg("Reserved", (val >> 24) & 0xff);
pci_read_config_dword(dev, vsec + 0xc, &val);
show_reg("PSL Rev", (val >> 0) & 0xffff);
show_reg("CAIA Ver", (val >> 16) & 0xffff);
pci_read_config_dword(dev, vsec + 0x10, &val);
show_reg("Base Image Rev", (val >> 0) & 0xffff);
show_reg("Reserved", (val >> 16) & 0x0fff);
show_reg("Image Control", (val >> 28) & 0x3);
show_reg("Reserved", (val >> 30) & 0x1);
show_reg("Image Loaded", (val >> 31) & 0x1);
pci_read_config_dword(dev, vsec + 0x14, &val);
show_reg("Reserved", val);
pci_read_config_dword(dev, vsec + 0x18, &val);
show_reg("Reserved", val);
pci_read_config_dword(dev, vsec + 0x1c, &val);
show_reg("Reserved", val);
pci_read_config_dword(dev, vsec + 0x20, &val);
show_reg("AFU Descriptor Offset", val);
pci_read_config_dword(dev, vsec + 0x24, &val);
show_reg("AFU Descriptor Size", val);
pci_read_config_dword(dev, vsec + 0x28, &val);
show_reg("Problem State Offset", val);
pci_read_config_dword(dev, vsec + 0x2c, &val);
show_reg("Problem State Size", val);
pci_read_config_dword(dev, vsec + 0x30, &val);
show_reg("Reserved", val);
pci_read_config_dword(dev, vsec + 0x34, &val);
show_reg("Reserved", val);
pci_read_config_dword(dev, vsec + 0x38, &val);
show_reg("Reserved", val);
pci_read_config_dword(dev, vsec + 0x3c, &val);
show_reg("Reserved", val);
pci_read_config_dword(dev, vsec + 0x40, &val);
show_reg("PSL Programming Port", val);
pci_read_config_dword(dev, vsec + 0x44, &val);
show_reg("PSL Programming Control", val);
pci_read_config_dword(dev, vsec + 0x48, &val);
show_reg("Reserved", val);
pci_read_config_dword(dev, vsec + 0x4c, &val);
show_reg("Reserved", val);
pci_read_config_dword(dev, vsec + 0x50, &val);
show_reg("Flash Address Register", val);
pci_read_config_dword(dev, vsec + 0x54, &val);
show_reg("Flash Size Register", val);
pci_read_config_dword(dev, vsec + 0x58, &val);
show_reg("Flash Status/Control Register", val);
pci_read_config_dword(dev, vsec + 0x58, &val);
show_reg("Flash Data Port", val);
#undef show_reg
}
static void dump_afu_descriptor(struct cxl_afu *afu)
{
u64 val, afu_cr_num, afu_cr_off, afu_cr_len;
int i;
#define show_reg(name, what) \
dev_info(&afu->dev, "afu desc: %30s: %#llx\n", name, what)
val = AFUD_READ_INFO(afu);
show_reg("num_ints_per_process", AFUD_NUM_INTS_PER_PROC(val));
show_reg("num_of_processes", AFUD_NUM_PROCS(val));
show_reg("num_of_afu_CRs", AFUD_NUM_CRS(val));
show_reg("req_prog_mode", val & 0xffffULL);
afu_cr_num = AFUD_NUM_CRS(val);
val = AFUD_READ(afu, 0x8);
show_reg("Reserved", val);
val = AFUD_READ(afu, 0x10);
show_reg("Reserved", val);
val = AFUD_READ(afu, 0x18);
show_reg("Reserved", val);
val = AFUD_READ_CR(afu);
show_reg("Reserved", (val >> (63-7)) & 0xff);
show_reg("AFU_CR_len", AFUD_CR_LEN(val));
afu_cr_len = AFUD_CR_LEN(val) * 256;
val = AFUD_READ_CR_OFF(afu);
afu_cr_off = val;
show_reg("AFU_CR_offset", val);
val = AFUD_READ_PPPSA(afu);
show_reg("PerProcessPSA_control", (val >> (63-7)) & 0xff);
show_reg("PerProcessPSA Length", AFUD_PPPSA_LEN(val));
val = AFUD_READ_PPPSA_OFF(afu);
show_reg("PerProcessPSA_offset", val);
val = AFUD_READ_EB(afu);
show_reg("Reserved", (val >> (63-7)) & 0xff);
show_reg("AFU_EB_len", AFUD_EB_LEN(val));
val = AFUD_READ_EB_OFF(afu);
show_reg("AFU_EB_offset", val);
for (i = 0; i < afu_cr_num; i++) {
val = AFUD_READ_LE(afu, afu_cr_off + i * afu_cr_len);
show_reg("CR Vendor", val & 0xffff);
show_reg("CR Device", (val >> 16) & 0xffff);
}
#undef show_reg
}
#define CAPP_UNIT0_ID 0xBA
#define CAPP_UNIT1_ID 0XBE
static u64 get_capp_unit_id(struct device_node *np)
{
u32 phb_index;
/*
* For chips other than POWER8NVL, we only have CAPP 0,
* irrespective of which PHB is used.
*/
if (!pvr_version_is(PVR_POWER8NVL))
return CAPP_UNIT0_ID;
/*
* For POWER8NVL, assume CAPP 0 is attached to PHB0 and
* CAPP 1 is attached to PHB1.
*/
if (of_property_read_u32(np, "ibm,phb-index", &phb_index))
return 0;
if (phb_index == 0)
return CAPP_UNIT0_ID;
if (phb_index == 1)
return CAPP_UNIT1_ID;
return 0;
}
static int calc_capp_routing(struct pci_dev *dev, u64 *chipid, u64 *capp_unit_id)
{
struct device_node *np;
const __be32 *prop;
cxl: Fix device_node reference counting When unbinding and rebinding the driver on a system with a card in PHB0, this error condition is reached after a few attempts: ERROR: Bad of_node_put() on /pciex@3fffe40000000 CPU: 0 PID: 3040 Comm: bash Not tainted 3.18.0-rc3-12545-g3627ffe #152 Call Trace: [c000000721acb5c0] [c00000000086ef94] .dump_stack+0x84/0xb0 (unreliable) [c000000721acb640] [c00000000073a0a8] .of_node_release+0xd8/0xe0 [c000000721acb6d0] [c00000000044bc44] .kobject_release+0x74/0xe0 [c000000721acb760] [c0000000007394fc] .of_node_put+0x1c/0x30 [c000000721acb7d0] [c000000000545cd8] .cxl_probe+0x1a98/0x1d50 [c000000721acb900] [c0000000004845a0] .local_pci_probe+0x40/0xc0 [c000000721acb980] [c000000000484998] .pci_device_probe+0x128/0x170 [c000000721acba30] [c00000000052400c] .driver_probe_device+0xac/0x2a0 [c000000721acbad0] [c000000000522468] .bind_store+0x108/0x160 [c000000721acbb70] [c000000000521448] .drv_attr_store+0x38/0x60 [c000000721acbbe0] [c000000000293840] .sysfs_kf_write+0x60/0xa0 [c000000721acbc50] [c000000000292500] .kernfs_fop_write+0x140/0x1d0 [c000000721acbcf0] [c000000000208648] .vfs_write+0xd8/0x260 [c000000721acbd90] [c000000000208b18] .SyS_write+0x58/0x100 [c000000721acbe30] [c000000000009258] syscall_exit+0x0/0x98 We are missing a call to of_node_get(). pnv_pci_to_phb_node() should call of_node_get() otherwise np's reference count isn't incremented and it might go away. Rename pnv_pci_to_phb_node() to pnv_pci_get_phb_node() so it's clear it calls of_node_get(). Signed-off-by: Ryan Grimm <grimm@linux.vnet.ibm.com> Acked-by: Ian Munsie <imunsie@au1.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
2015-01-29 10:16:04 +08:00
if (!(np = pnv_pci_get_phb_node(dev)))
return -ENODEV;
while (np && !(prop = of_get_property(np, "ibm,chip-id", NULL)))
np = of_get_next_parent(np);
if (!np)
return -ENODEV;
*chipid = be32_to_cpup(prop);
*capp_unit_id = get_capp_unit_id(np);
of_node_put(np);
if (!*capp_unit_id) {
pr_err("cxl: invalid capp unit id\n");
return -ENODEV;
}
return 0;
}
static int init_implementation_adapter_psl_regs(struct cxl *adapter, struct pci_dev *dev)
{
u64 psl_dsnctl;
u64 chipid;
u64 capp_unit_id;
int rc;
rc = calc_capp_routing(dev, &chipid, &capp_unit_id);
if (rc)
return rc;
psl_dsnctl = 0x0000900000000000ULL; /* pteupd ttype, scdone */
psl_dsnctl |= (0x2ULL << (63-38)); /* MMIO hang pulse: 256 us */
/* Tell PSL where to route data to */
psl_dsnctl |= (chipid << (63-5));
psl_dsnctl |= (capp_unit_id << (63-13));
cxl_p1_write(adapter, CXL_PSL_DSNDCTL, psl_dsnctl);
cxl_p1_write(adapter, CXL_PSL_RESLCKTO, 0x20000000200ULL);
/* snoop write mask */
cxl_p1_write(adapter, CXL_PSL_SNWRALLOC, 0x00000000FFFFFFFFULL);
/* set fir_accum */
cxl_p1_write(adapter, CXL_PSL_FIR_CNTL, 0x0800000000000000ULL);
/* for debugging with trace arrays */
cxl_p1_write(adapter, CXL_PSL_TRACE, 0x0000FF7C00000000ULL);
return 0;
}
static int init_implementation_adapter_xsl_regs(struct cxl *adapter, struct pci_dev *dev)
{
u64 xsl_dsnctl;
u64 chipid;
u64 capp_unit_id;
int rc;
rc = calc_capp_routing(dev, &chipid, &capp_unit_id);
if (rc)
return rc;
/* Tell XSL where to route data to */
xsl_dsnctl = 0x0000600000000000ULL | (chipid << (63-5));
xsl_dsnctl |= (capp_unit_id << (63-13));
cxl_p1_write(adapter, CXL_XSL_DSNCTL, xsl_dsnctl);
return 0;
}
/* PSL & XSL */
#define TBSYNC_CAL(n) (((u64)n & 0x7) << (63-3))
#define TBSYNC_CNT(n) (((u64)n & 0x7) << (63-6))
/* For the PSL this is a multiple for 0 < n <= 7: */
#define PSL_2048_250MHZ_CYCLES 1
static void write_timebase_ctrl_psl(struct cxl *adapter)
{
cxl_p1_write(adapter, CXL_PSL_TB_CTLSTAT,
TBSYNC_CNT(2 * PSL_2048_250MHZ_CYCLES));
}
/* XSL */
#define TBSYNC_ENA (1ULL << 63)
/* For the XSL this is 2**n * 2000 clocks for 0 < n <= 6: */
#define XSL_2000_CLOCKS 1
#define XSL_4000_CLOCKS 2
#define XSL_8000_CLOCKS 3
static void write_timebase_ctrl_xsl(struct cxl *adapter)
{
cxl_p1_write(adapter, CXL_XSL_TB_CTLSTAT,
TBSYNC_ENA |
TBSYNC_CAL(3) |
TBSYNC_CNT(XSL_4000_CLOCKS));
}
static u64 timebase_read_psl(struct cxl *adapter)
{
return cxl_p1_read(adapter, CXL_PSL_Timebase);
}
static u64 timebase_read_xsl(struct cxl *adapter)
{
return cxl_p1_read(adapter, CXL_XSL_Timebase);
}
static void cxl_setup_psl_timebase(struct cxl *adapter, struct pci_dev *dev)
{
u64 psl_tb;
int delta;
unsigned int retry = 0;
struct device_node *np;
adapter->psl_timebase_synced = false;
if (!(np = pnv_pci_get_phb_node(dev)))
return;
/* Do not fail when CAPP timebase sync is not supported by OPAL */
of_node_get(np);
if (! of_get_property(np, "ibm,capp-timebase-sync", NULL)) {
of_node_put(np);
dev_info(&dev->dev, "PSL timebase inactive: OPAL support missing\n");
return;
}
of_node_put(np);
/*
* Setup PSL Timebase Control and Status register
* with the recommended Timebase Sync Count value
*/
adapter->native->sl_ops->write_timebase_ctrl(adapter);
/* Enable PSL Timebase */
cxl_p1_write(adapter, CXL_PSL_Control, 0x0000000000000000);
cxl_p1_write(adapter, CXL_PSL_Control, CXL_PSL_Control_tb);
/* Wait until CORE TB and PSL TB difference <= 16usecs */
do {
msleep(1);
if (retry++ > 5) {
dev_info(&dev->dev, "PSL timebase can't synchronize\n");
return;
}
psl_tb = adapter->native->sl_ops->timebase_read(adapter);
delta = mftb() - psl_tb;
if (delta < 0)
delta = -delta;
} while (tb_to_ns(delta) > 16000);
adapter->psl_timebase_synced = true;
return;
}
static int init_implementation_afu_psl_regs(struct cxl_afu *afu)
{
/* read/write masks for this slice */
cxl_p1n_write(afu, CXL_PSL_APCALLOC_A, 0xFFFFFFFEFEFEFEFEULL);
/* APC read/write masks for this slice */
cxl_p1n_write(afu, CXL_PSL_COALLOC_A, 0xFF000000FEFEFEFEULL);
/* for debugging with trace arrays */
cxl_p1n_write(afu, CXL_PSL_SLICE_TRACE, 0x0000FFFF00000000ULL);
cxl_p1n_write(afu, CXL_PSL_RXCTL_A, CXL_PSL_RXCTL_AFUHP_4S);
return 0;
}
int cxl_pci_setup_irq(struct cxl *adapter, unsigned int hwirq,
unsigned int virq)
{
struct pci_dev *dev = to_pci_dev(adapter->dev.parent);
return pnv_cxl_ioda_msi_setup(dev, hwirq, virq);
}
int cxl_update_image_control(struct cxl *adapter)
{
struct pci_dev *dev = to_pci_dev(adapter->dev.parent);
int rc;
int vsec;
u8 image_state;
if (!(vsec = find_cxl_vsec(dev))) {
dev_err(&dev->dev, "ABORTING: CXL VSEC not found!\n");
return -ENODEV;
}
if ((rc = CXL_READ_VSEC_IMAGE_STATE(dev, vsec, &image_state))) {
dev_err(&dev->dev, "failed to read image state: %i\n", rc);
return rc;
}
if (adapter->perst_loads_image)
image_state |= CXL_VSEC_PERST_LOADS_IMAGE;
else
image_state &= ~CXL_VSEC_PERST_LOADS_IMAGE;
if (adapter->perst_select_user)
image_state |= CXL_VSEC_PERST_SELECT_USER;
else
image_state &= ~CXL_VSEC_PERST_SELECT_USER;
if ((rc = CXL_WRITE_VSEC_IMAGE_STATE(dev, vsec, image_state))) {
dev_err(&dev->dev, "failed to update image control: %i\n", rc);
return rc;
}
return 0;
}
int cxl_pci_alloc_one_irq(struct cxl *adapter)
{
struct pci_dev *dev = to_pci_dev(adapter->dev.parent);
return pnv_cxl_alloc_hwirqs(dev, 1);
}
void cxl_pci_release_one_irq(struct cxl *adapter, int hwirq)
{
struct pci_dev *dev = to_pci_dev(adapter->dev.parent);
return pnv_cxl_release_hwirqs(dev, hwirq, 1);
}
int cxl_pci_alloc_irq_ranges(struct cxl_irq_ranges *irqs,
struct cxl *adapter, unsigned int num)
{
struct pci_dev *dev = to_pci_dev(adapter->dev.parent);
return pnv_cxl_alloc_hwirq_ranges(irqs, dev, num);
}
void cxl_pci_release_irq_ranges(struct cxl_irq_ranges *irqs,
struct cxl *adapter)
{
struct pci_dev *dev = to_pci_dev(adapter->dev.parent);
pnv_cxl_release_hwirq_ranges(irqs, dev);
}
static int setup_cxl_bars(struct pci_dev *dev)
{
/* Safety check in case we get backported to < 3.17 without M64 */
if ((p1_base(dev) < 0x100000000ULL) ||
(p2_base(dev) < 0x100000000ULL)) {
dev_err(&dev->dev, "ABORTING: M32 BAR assignment incompatible with CXL\n");
return -ENODEV;
}
/*
* BAR 4/5 has a special meaning for CXL and must be programmed with a
* special value corresponding to the CXL protocol address range.
* For POWER 8 that means bits 48:49 must be set to 10
*/
pci_write_config_dword(dev, PCI_BASE_ADDRESS_4, 0x00000000);
pci_write_config_dword(dev, PCI_BASE_ADDRESS_5, 0x00020000);
return 0;
}
/* pciex node: ibm,opal-m64-window = <0x3d058 0x0 0x3d058 0x0 0x8 0x0>; */
static int switch_card_to_cxl(struct pci_dev *dev)
{
int vsec;
u8 val;
int rc;
dev_info(&dev->dev, "switch card to CXL\n");
if (!(vsec = find_cxl_vsec(dev))) {
dev_err(&dev->dev, "ABORTING: CXL VSEC not found!\n");
return -ENODEV;
}
if ((rc = CXL_READ_VSEC_MODE_CONTROL(dev, vsec, &val))) {
dev_err(&dev->dev, "failed to read current mode control: %i", rc);
return rc;
}
val &= ~CXL_VSEC_PROTOCOL_MASK;
val |= CXL_VSEC_PROTOCOL_256TB | CXL_VSEC_PROTOCOL_ENABLE;
if ((rc = CXL_WRITE_VSEC_MODE_CONTROL(dev, vsec, val))) {
dev_err(&dev->dev, "failed to enable CXL protocol: %i", rc);
return rc;
}
/*
* The CAIA spec (v0.12 11.6 Bi-modal Device Support) states
* we must wait 100ms after this mode switch before touching
* PCIe config space.
*/
msleep(100);
return 0;
}
static int pci_map_slice_regs(struct cxl_afu *afu, struct cxl *adapter, struct pci_dev *dev)
{
u64 p1n_base, p2n_base, afu_desc;
const u64 p1n_size = 0x100;
const u64 p2n_size = 0x1000;
p1n_base = p1_base(dev) + 0x10000 + (afu->slice * p1n_size);
p2n_base = p2_base(dev) + (afu->slice * p2n_size);
afu->psn_phys = p2_base(dev) + (adapter->native->ps_off + (afu->slice * adapter->ps_size));
afu_desc = p2_base(dev) + adapter->native->afu_desc_off + (afu->slice * adapter->native->afu_desc_size);
if (!(afu->native->p1n_mmio = ioremap(p1n_base, p1n_size)))
goto err;
if (!(afu->p2n_mmio = ioremap(p2n_base, p2n_size)))
goto err1;
if (afu_desc) {
if (!(afu->native->afu_desc_mmio = ioremap(afu_desc, adapter->native->afu_desc_size)))
goto err2;
}
return 0;
err2:
iounmap(afu->p2n_mmio);
err1:
iounmap(afu->native->p1n_mmio);
err:
dev_err(&afu->dev, "Error mapping AFU MMIO regions\n");
return -ENOMEM;
}
static void pci_unmap_slice_regs(struct cxl_afu *afu)
{
if (afu->p2n_mmio) {
iounmap(afu->p2n_mmio);
afu->p2n_mmio = NULL;
}
if (afu->native->p1n_mmio) {
iounmap(afu->native->p1n_mmio);
afu->native->p1n_mmio = NULL;
}
if (afu->native->afu_desc_mmio) {
iounmap(afu->native->afu_desc_mmio);
afu->native->afu_desc_mmio = NULL;
}
}
void cxl_pci_release_afu(struct device *dev)
{
struct cxl_afu *afu = to_cxl_afu(dev);
pr_devel("%s\n", __func__);
idr_destroy(&afu->contexts_idr);
cxl_release_spa(afu);
kfree(afu->native);
kfree(afu);
}
/* Expects AFU struct to have recently been zeroed out */
static int cxl_read_afu_descriptor(struct cxl_afu *afu)
{
u64 val;
val = AFUD_READ_INFO(afu);
afu->pp_irqs = AFUD_NUM_INTS_PER_PROC(val);
afu->max_procs_virtualised = AFUD_NUM_PROCS(val);
afu->crs_num = AFUD_NUM_CRS(val);
if (AFUD_AFU_DIRECTED(val))
afu->modes_supported |= CXL_MODE_DIRECTED;
if (AFUD_DEDICATED_PROCESS(val))
afu->modes_supported |= CXL_MODE_DEDICATED;
if (AFUD_TIME_SLICED(val))
afu->modes_supported |= CXL_MODE_TIME_SLICED;
val = AFUD_READ_PPPSA(afu);
afu->pp_size = AFUD_PPPSA_LEN(val) * 4096;
afu->psa = AFUD_PPPSA_PSA(val);
if ((afu->pp_psa = AFUD_PPPSA_PP(val)))
afu->native->pp_offset = AFUD_READ_PPPSA_OFF(afu);
val = AFUD_READ_CR(afu);
afu->crs_len = AFUD_CR_LEN(val) * 256;
afu->crs_offset = AFUD_READ_CR_OFF(afu);
/* eb_len is in multiple of 4K */
afu->eb_len = AFUD_EB_LEN(AFUD_READ_EB(afu)) * 4096;
afu->eb_offset = AFUD_READ_EB_OFF(afu);
/* eb_off is 4K aligned so lower 12 bits are always zero */
if (EXTRACT_PPC_BITS(afu->eb_offset, 0, 11) != 0) {
dev_warn(&afu->dev,
"Invalid AFU error buffer offset %Lx\n",
afu->eb_offset);
dev_info(&afu->dev,
"Ignoring AFU error buffer in the descriptor\n");
/* indicate that no afu buffer exists */
afu->eb_len = 0;
}
return 0;
}
static int cxl_afu_descriptor_looks_ok(struct cxl_afu *afu)
{
int i, rc;
u32 val;
if (afu->psa && afu->adapter->ps_size <
(afu->native->pp_offset + afu->pp_size*afu->max_procs_virtualised)) {
dev_err(&afu->dev, "per-process PSA can't fit inside the PSA!\n");
return -ENODEV;
}
if (afu->pp_psa && (afu->pp_size < PAGE_SIZE))
dev_warn(&afu->dev, "AFU uses < PAGE_SIZE per-process PSA!");
for (i = 0; i < afu->crs_num; i++) {
rc = cxl_ops->afu_cr_read32(afu, i, 0, &val);
if (rc || val == 0) {
dev_err(&afu->dev, "ABORTING: AFU configuration record %i is invalid\n", i);
return -EINVAL;
}
}
2016-06-29 20:16:25 +08:00
if ((afu->modes_supported & ~CXL_MODE_DEDICATED) && afu->max_procs_virtualised == 0) {
/*
* We could also check this for the dedicated process model
* since the architecture indicates it should be set to 1, but
* in that case we ignore the value and I'd rather not risk
* breaking any existing dedicated process AFUs that left it as
* 0 (not that I'm aware of any). It is clearly an error for an
* AFU directed AFU to set this to 0, and would have previously
* triggered a bug resulting in the maximum not being enforced
* at all since idr_alloc treats 0 as no maximum.
*/
dev_err(&afu->dev, "AFU does not support any processes\n");
return -EINVAL;
}
return 0;
}
static int sanitise_afu_regs(struct cxl_afu *afu)
{
u64 reg;
/*
* Clear out any regs that contain either an IVTE or address or may be
* waiting on an acknowledgement to try to be a bit safer as we bring
* it online
*/
reg = cxl_p2n_read(afu, CXL_AFU_Cntl_An);
if ((reg & CXL_AFU_Cntl_An_ES_MASK) != CXL_AFU_Cntl_An_ES_Disabled) {
dev_warn(&afu->dev, "WARNING: AFU was not disabled: %#016llx\n", reg);
if (cxl_ops->afu_reset(afu))
return -EIO;
if (cxl_afu_disable(afu))
return -EIO;
if (cxl_psl_purge(afu))
return -EIO;
}
cxl_p1n_write(afu, CXL_PSL_SPAP_An, 0x0000000000000000);
cxl_p1n_write(afu, CXL_PSL_IVTE_Limit_An, 0x0000000000000000);
cxl_p1n_write(afu, CXL_PSL_IVTE_Offset_An, 0x0000000000000000);
cxl_p1n_write(afu, CXL_PSL_AMBAR_An, 0x0000000000000000);
cxl_p1n_write(afu, CXL_PSL_SPOffset_An, 0x0000000000000000);
cxl_p1n_write(afu, CXL_HAURP_An, 0x0000000000000000);
cxl_p2n_write(afu, CXL_CSRP_An, 0x0000000000000000);
cxl_p2n_write(afu, CXL_AURP1_An, 0x0000000000000000);
cxl_p2n_write(afu, CXL_AURP0_An, 0x0000000000000000);
cxl_p2n_write(afu, CXL_SSTP1_An, 0x0000000000000000);
cxl_p2n_write(afu, CXL_SSTP0_An, 0x0000000000000000);
reg = cxl_p2n_read(afu, CXL_PSL_DSISR_An);
if (reg) {
dev_warn(&afu->dev, "AFU had pending DSISR: %#016llx\n", reg);
if (reg & CXL_PSL_DSISR_TRANS)
cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_AE);
else
cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_A);
}
if (afu->adapter->native->sl_ops->register_serr_irq) {
reg = cxl_p1n_read(afu, CXL_PSL_SERR_An);
if (reg) {
if (reg & ~0xffff)
dev_warn(&afu->dev, "AFU had pending SERR: %#016llx\n", reg);
cxl_p1n_write(afu, CXL_PSL_SERR_An, reg & ~0xffff);
}
}
reg = cxl_p2n_read(afu, CXL_PSL_ErrStat_An);
if (reg) {
dev_warn(&afu->dev, "AFU had pending error status: %#016llx\n", reg);
cxl_p2n_write(afu, CXL_PSL_ErrStat_An, reg);
}
return 0;
}
#define ERR_BUFF_MAX_COPY_SIZE PAGE_SIZE
/*
* afu_eb_read:
* Called from sysfs and reads the afu error info buffer. The h/w only supports
* 4/8 bytes aligned access. So in case the requested offset/count arent 8 byte
* aligned the function uses a bounce buffer which can be max PAGE_SIZE.
*/
ssize_t cxl_pci_afu_read_err_buffer(struct cxl_afu *afu, char *buf,
loff_t off, size_t count)
{
loff_t aligned_start, aligned_end;
size_t aligned_length;
void *tbuf;
const void __iomem *ebuf = afu->native->afu_desc_mmio + afu->eb_offset;
if (count == 0 || off < 0 || (size_t)off >= afu->eb_len)
return 0;
/* calculate aligned read window */
count = min((size_t)(afu->eb_len - off), count);
aligned_start = round_down(off, 8);
aligned_end = round_up(off + count, 8);
aligned_length = aligned_end - aligned_start;
/* max we can copy in one read is PAGE_SIZE */
if (aligned_length > ERR_BUFF_MAX_COPY_SIZE) {
aligned_length = ERR_BUFF_MAX_COPY_SIZE;
count = ERR_BUFF_MAX_COPY_SIZE - (off & 0x7);
}
/* use bounce buffer for copy */
tbuf = (void *)__get_free_page(GFP_TEMPORARY);
if (!tbuf)
return -ENOMEM;
/* perform aligned read from the mmio region */
memcpy_fromio(tbuf, ebuf + aligned_start, aligned_length);
memcpy(buf, tbuf + (off & 0x7), count);
free_page((unsigned long)tbuf);
return count;
}
static int pci_configure_afu(struct cxl_afu *afu, struct cxl *adapter, struct pci_dev *dev)
{
int rc;
if ((rc = pci_map_slice_regs(afu, adapter, dev)))
return rc;
if ((rc = sanitise_afu_regs(afu)))
goto err1;
/* We need to reset the AFU before we can read the AFU descriptor */
if ((rc = cxl_ops->afu_reset(afu)))
goto err1;
if (cxl_verbose)
dump_afu_descriptor(afu);
if ((rc = cxl_read_afu_descriptor(afu)))
goto err1;
if ((rc = cxl_afu_descriptor_looks_ok(afu)))
goto err1;
if (adapter->native->sl_ops->afu_regs_init)
if ((rc = adapter->native->sl_ops->afu_regs_init(afu)))
goto err1;
if (adapter->native->sl_ops->register_serr_irq)
if ((rc = adapter->native->sl_ops->register_serr_irq(afu)))
goto err1;
if ((rc = cxl_native_register_psl_irq(afu)))
goto err2;
return 0;
err2:
if (adapter->native->sl_ops->release_serr_irq)
adapter->native->sl_ops->release_serr_irq(afu);
err1:
pci_unmap_slice_regs(afu);
return rc;
}
static void pci_deconfigure_afu(struct cxl_afu *afu)
{
cxl_native_release_psl_irq(afu);
if (afu->adapter->native->sl_ops->release_serr_irq)
afu->adapter->native->sl_ops->release_serr_irq(afu);
pci_unmap_slice_regs(afu);
}
static int pci_init_afu(struct cxl *adapter, int slice, struct pci_dev *dev)
{
struct cxl_afu *afu;
int rc = -ENOMEM;
afu = cxl_alloc_afu(adapter, slice);
if (!afu)
return -ENOMEM;
afu->native = kzalloc(sizeof(struct cxl_afu_native), GFP_KERNEL);
if (!afu->native)
goto err_free_afu;
mutex_init(&afu->native->spa_mutex);
rc = dev_set_name(&afu->dev, "afu%i.%i", adapter->adapter_num, slice);
if (rc)
goto err_free_native;
rc = pci_configure_afu(afu, adapter, dev);
if (rc)
goto err_free_native;
/* Don't care if this fails */
cxl_debugfs_afu_add(afu);
/*
* After we call this function we must not free the afu directly, even
* if it returns an error!
*/
if ((rc = cxl_register_afu(afu)))
goto err_put1;
if ((rc = cxl_sysfs_afu_add(afu)))
goto err_put1;
adapter->afu[afu->slice] = afu;
if ((rc = cxl_pci_vphb_add(afu)))
dev_info(&afu->dev, "Can't register vPHB\n");
return 0;
err_put1:
pci_deconfigure_afu(afu);
cxl_debugfs_afu_remove(afu);
device_unregister(&afu->dev);
return rc;
err_free_native:
kfree(afu->native);
err_free_afu:
kfree(afu);
return rc;
}
static void cxl_pci_remove_afu(struct cxl_afu *afu)
{
pr_devel("%s\n", __func__);
if (!afu)
return;
cxl_pci_vphb_remove(afu);
cxl_sysfs_afu_remove(afu);
cxl_debugfs_afu_remove(afu);
spin_lock(&afu->adapter->afu_list_lock);
afu->adapter->afu[afu->slice] = NULL;
spin_unlock(&afu->adapter->afu_list_lock);
cxl_context_detach_all(afu);
cxl_ops->afu_deactivate_mode(afu, afu->current_mode);
pci_deconfigure_afu(afu);
device_unregister(&afu->dev);
}
int cxl_pci_reset(struct cxl *adapter)
{
struct pci_dev *dev = to_pci_dev(adapter->dev.parent);
int rc;
if (adapter->perst_same_image) {
dev_warn(&dev->dev,
"cxl: refusing to reset/reflash when perst_reloads_same_image is set.\n");
return -EINVAL;
}
dev_info(&dev->dev, "CXL reset\n");
/* pcie_warm_reset requests a fundamental pci reset which includes a
* PERST assert/deassert. PERST triggers a loading of the image
* if "user" or "factory" is selected in sysfs */
if ((rc = pci_set_pcie_reset_state(dev, pcie_warm_reset))) {
dev_err(&dev->dev, "cxl: pcie_warm_reset failed\n");
return rc;
}
return rc;
}
static int cxl_map_adapter_regs(struct cxl *adapter, struct pci_dev *dev)
{
if (pci_request_region(dev, 2, "priv 2 regs"))
goto err1;
if (pci_request_region(dev, 0, "priv 1 regs"))
goto err2;
pr_devel("cxl_map_adapter_regs: p1: %#016llx %#llx, p2: %#016llx %#llx",
p1_base(dev), p1_size(dev), p2_base(dev), p2_size(dev));
if (!(adapter->native->p1_mmio = ioremap(p1_base(dev), p1_size(dev))))
goto err3;
if (!(adapter->native->p2_mmio = ioremap(p2_base(dev), p2_size(dev))))
goto err4;
return 0;
err4:
iounmap(adapter->native->p1_mmio);
adapter->native->p1_mmio = NULL;
err3:
pci_release_region(dev, 0);
err2:
pci_release_region(dev, 2);
err1:
return -ENOMEM;
}
static void cxl_unmap_adapter_regs(struct cxl *adapter)
{
if (adapter->native->p1_mmio) {
iounmap(adapter->native->p1_mmio);
adapter->native->p1_mmio = NULL;
pci_release_region(to_pci_dev(adapter->dev.parent), 2);
}
if (adapter->native->p2_mmio) {
iounmap(adapter->native->p2_mmio);
adapter->native->p2_mmio = NULL;
pci_release_region(to_pci_dev(adapter->dev.parent), 0);
}
}
static int cxl_read_vsec(struct cxl *adapter, struct pci_dev *dev)
{
int vsec;
u32 afu_desc_off, afu_desc_size;
u32 ps_off, ps_size;
u16 vseclen;
u8 image_state;
if (!(vsec = find_cxl_vsec(dev))) {
dev_err(&dev->dev, "ABORTING: CXL VSEC not found!\n");
return -ENODEV;
}
CXL_READ_VSEC_LENGTH(dev, vsec, &vseclen);
if (vseclen < CXL_VSEC_MIN_SIZE) {
dev_err(&dev->dev, "ABORTING: CXL VSEC too short\n");
return -EINVAL;
}
CXL_READ_VSEC_STATUS(dev, vsec, &adapter->vsec_status);
CXL_READ_VSEC_PSL_REVISION(dev, vsec, &adapter->psl_rev);
CXL_READ_VSEC_CAIA_MAJOR(dev, vsec, &adapter->caia_major);
CXL_READ_VSEC_CAIA_MINOR(dev, vsec, &adapter->caia_minor);
CXL_READ_VSEC_BASE_IMAGE(dev, vsec, &adapter->base_image);
CXL_READ_VSEC_IMAGE_STATE(dev, vsec, &image_state);
adapter->user_image_loaded = !!(image_state & CXL_VSEC_USER_IMAGE_LOADED);
adapter->perst_select_user = !!(image_state & CXL_VSEC_USER_IMAGE_LOADED);
CXL_READ_VSEC_NAFUS(dev, vsec, &adapter->slices);
CXL_READ_VSEC_AFU_DESC_OFF(dev, vsec, &afu_desc_off);
CXL_READ_VSEC_AFU_DESC_SIZE(dev, vsec, &afu_desc_size);
CXL_READ_VSEC_PS_OFF(dev, vsec, &ps_off);
CXL_READ_VSEC_PS_SIZE(dev, vsec, &ps_size);
/* Convert everything to bytes, because there is NO WAY I'd look at the
* code a month later and forget what units these are in ;-) */
adapter->native->ps_off = ps_off * 64 * 1024;
adapter->ps_size = ps_size * 64 * 1024;
adapter->native->afu_desc_off = afu_desc_off * 64 * 1024;
adapter->native->afu_desc_size = afu_desc_size * 64 * 1024;
/* Total IRQs - 1 PSL ERROR - #AFU*(1 slice error + 1 DSI) */
adapter->user_irqs = pnv_cxl_get_irq_count(dev) - 1 - 2*adapter->slices;
return 0;
}
/*
* Workaround a PCIe Host Bridge defect on some cards, that can cause
* malformed Transaction Layer Packet (TLP) errors to be erroneously
* reported. Mask this error in the Uncorrectable Error Mask Register.
*
* The upper nibble of the PSL revision is used to distinguish between
* different cards. The affected ones have it set to 0.
*/
static void cxl_fixup_malformed_tlp(struct cxl *adapter, struct pci_dev *dev)
{
int aer;
u32 data;
if (adapter->psl_rev & 0xf000)
return;
if (!(aer = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR)))
return;
pci_read_config_dword(dev, aer + PCI_ERR_UNCOR_MASK, &data);
if (data & PCI_ERR_UNC_MALF_TLP)
if (data & PCI_ERR_UNC_INTN)
return;
data |= PCI_ERR_UNC_MALF_TLP;
data |= PCI_ERR_UNC_INTN;
pci_write_config_dword(dev, aer + PCI_ERR_UNCOR_MASK, data);
}
static int cxl_vsec_looks_ok(struct cxl *adapter, struct pci_dev *dev)
{
if (adapter->vsec_status & CXL_STATUS_SECOND_PORT)
return -EBUSY;
if (adapter->vsec_status & CXL_UNSUPPORTED_FEATURES) {
dev_err(&dev->dev, "ABORTING: CXL requires unsupported features\n");
return -EINVAL;
}
if (!adapter->slices) {
/* Once we support dynamic reprogramming we can use the card if
* it supports loadable AFUs */
dev_err(&dev->dev, "ABORTING: Device has no AFUs\n");
return -EINVAL;
}
if (!adapter->native->afu_desc_off || !adapter->native->afu_desc_size) {
dev_err(&dev->dev, "ABORTING: VSEC shows no AFU descriptors\n");
return -EINVAL;
}
if (adapter->ps_size > p2_size(dev) - adapter->native->ps_off) {
dev_err(&dev->dev, "ABORTING: Problem state size larger than "
"available in BAR2: 0x%llx > 0x%llx\n",
adapter->ps_size, p2_size(dev) - adapter->native->ps_off);
return -EINVAL;
}
return 0;
}
ssize_t cxl_pci_read_adapter_vpd(struct cxl *adapter, void *buf, size_t len)
{
return pci_read_vpd(to_pci_dev(adapter->dev.parent), 0, len, buf);
}
static void cxl_release_adapter(struct device *dev)
{
struct cxl *adapter = to_cxl_adapter(dev);
pr_devel("cxl_release_adapter\n");
cxl_remove_adapter_nr(adapter);
kfree(adapter->native);
kfree(adapter);
}
#define CXL_PSL_ErrIVTE_tberror (0x1ull << (63-31))
static int sanitise_adapter_regs(struct cxl *adapter)
{
/* Clear PSL tberror bit by writing 1 to it */
cxl_p1_write(adapter, CXL_PSL_ErrIVTE, CXL_PSL_ErrIVTE_tberror);
return cxl_tlb_slb_invalidate(adapter);
}
/* This should contain *only* operations that can safely be done in
* both creation and recovery.
*/
static int cxl_configure_adapter(struct cxl *adapter, struct pci_dev *dev)
{
int rc;
adapter->dev.parent = &dev->dev;
adapter->dev.release = cxl_release_adapter;
pci_set_drvdata(dev, adapter);
rc = pci_enable_device(dev);
if (rc) {
dev_err(&dev->dev, "pci_enable_device failed: %i\n", rc);
return rc;
}
if ((rc = cxl_read_vsec(adapter, dev)))
return rc;
if ((rc = cxl_vsec_looks_ok(adapter, dev)))
return rc;
cxl_fixup_malformed_tlp(adapter, dev);
if ((rc = setup_cxl_bars(dev)))
return rc;
if ((rc = switch_card_to_cxl(dev)))
return rc;
if ((rc = cxl_update_image_control(adapter)))
return rc;
if ((rc = cxl_map_adapter_regs(adapter, dev)))
return rc;
if ((rc = sanitise_adapter_regs(adapter)))
goto err;
if ((rc = adapter->native->sl_ops->adapter_regs_init(adapter, dev)))
goto err;
if ((rc = pnv_phb_to_cxl_mode(dev, adapter->native->sl_ops->capi_mode)))
goto err;
/* If recovery happened, the last step is to turn on snooping.
* In the non-recovery case this has no effect */
if ((rc = pnv_phb_to_cxl_mode(dev, OPAL_PHB_CAPI_MODE_SNOOP_ON)))
goto err;
/* Ignore error, adapter init is not dependant on timebase sync */
cxl_setup_psl_timebase(adapter, dev);
if ((rc = cxl_native_register_psl_err_irq(adapter)))
goto err;
return 0;
err:
cxl_unmap_adapter_regs(adapter);
return rc;
}
static void cxl_deconfigure_adapter(struct cxl *adapter)
{
struct pci_dev *pdev = to_pci_dev(adapter->dev.parent);
cxl_native_release_psl_err_irq(adapter);
cxl_unmap_adapter_regs(adapter);
pci_disable_device(pdev);
}
static const struct cxl_service_layer_ops psl_ops = {
.adapter_regs_init = init_implementation_adapter_psl_regs,
.afu_regs_init = init_implementation_afu_psl_regs,
.register_serr_irq = cxl_native_register_serr_irq,
.release_serr_irq = cxl_native_release_serr_irq,
.debugfs_add_adapter_sl_regs = cxl_debugfs_add_adapter_psl_regs,
.debugfs_add_afu_sl_regs = cxl_debugfs_add_afu_psl_regs,
.psl_irq_dump_registers = cxl_native_psl_irq_dump_regs,
.err_irq_dump_registers = cxl_native_err_irq_dump_regs,
.debugfs_stop_trace = cxl_stop_trace,
.write_timebase_ctrl = write_timebase_ctrl_psl,
.timebase_read = timebase_read_psl,
.capi_mode = OPAL_PHB_CAPI_MODE_CAPI,
cxl: Fix bug where AFU disable operation had no effect The AFU disable operation has a bug where it will not clear the enable bit and therefore will have no effect. To date this has likely been masked by fact that we perform an AFU reset before the disable, which also has the effect of clearing the enable bit, making the following disable operation effectively a noop on most hardware. This patch modifies the afu_control function to take a parameter to clear from the AFU control register so that the disable operation can clear the appropriate bit. This bug was uncovered on the Mellanox CX4, which uses an XSL rather than a PSL. On the XSL the reset operation will not complete while the AFU is enabled, meaning the enable bit was still set at the start of the disable and as a result this bug was hit and the disable also timed out. Because of this difference in behaviour between the PSL and XSL, this patch now makes the reset dependent on the card using a PSL to avoid waiting for a timeout on the XSL. It is entirely possible that we may be able to drop the reset altogether if it turns out we only ever needed it due to this bug - however I am not willing to drop it without further regression testing and have added comments to the code explaining the background. This also fixes a small issue where the AFU_Cntl register was read outside of the lock that protects it. Signed-off-by: Ian Munsie <imunsie@au1.ibm.com> Reviewed-by: Frederic Barrat <fbarrat@linux.vnet.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
2016-07-01 00:50:40 +08:00
.needs_reset_before_disable = true,
};
static const struct cxl_service_layer_ops xsl_ops = {
.adapter_regs_init = init_implementation_adapter_xsl_regs,
.debugfs_add_adapter_sl_regs = cxl_debugfs_add_adapter_xsl_regs,
.write_timebase_ctrl = write_timebase_ctrl_xsl,
.timebase_read = timebase_read_xsl,
.capi_mode = OPAL_PHB_CAPI_MODE_DMA,
};
static void set_sl_ops(struct cxl *adapter, struct pci_dev *dev)
{
if (dev->vendor == PCI_VENDOR_ID_MELLANOX && dev->device == 0x1013) {
dev_info(&adapter->dev, "Device uses an XSL\n");
adapter->native->sl_ops = &xsl_ops;
} else {
dev_info(&adapter->dev, "Device uses a PSL\n");
adapter->native->sl_ops = &psl_ops;
}
}
static struct cxl *cxl_pci_init_adapter(struct pci_dev *dev)
{
struct cxl *adapter;
int rc;
adapter = cxl_alloc_adapter();
if (!adapter)
return ERR_PTR(-ENOMEM);
adapter->native = kzalloc(sizeof(struct cxl_native), GFP_KERNEL);
if (!adapter->native) {
rc = -ENOMEM;
goto err_release;
}
set_sl_ops(adapter, dev);
/* Set defaults for parameters which need to persist over
* configure/reconfigure
*/
adapter->perst_loads_image = true;
adapter->perst_same_image = false;
rc = cxl_configure_adapter(adapter, dev);
if (rc) {
pci_disable_device(dev);
goto err_release;
}
/* Don't care if this one fails: */
cxl_debugfs_adapter_add(adapter);
/*
* After we call this function we must not free the adapter directly,
* even if it returns an error!
*/
if ((rc = cxl_register_adapter(adapter)))
goto err_put1;
if ((rc = cxl_sysfs_adapter_add(adapter)))
goto err_put1;
return adapter;
err_put1:
/* This should mirror cxl_remove_adapter, except without the
* sysfs parts
*/
cxl_debugfs_adapter_remove(adapter);
cxl_deconfigure_adapter(adapter);
device_unregister(&adapter->dev);
return ERR_PTR(rc);
err_release:
cxl_release_adapter(&adapter->dev);
return ERR_PTR(rc);
}
static void cxl_pci_remove_adapter(struct cxl *adapter)
{
pr_devel("cxl_remove_adapter\n");
cxl_sysfs_adapter_remove(adapter);
cxl_debugfs_adapter_remove(adapter);
cxl_deconfigure_adapter(adapter);
device_unregister(&adapter->dev);
}
#define CXL_MAX_PCIEX_PARENT 2
static int cxl_slot_is_switched(struct pci_dev *dev)
{
struct device_node *np;
int depth = 0;
const __be32 *prop;
if (!(np = pci_device_to_OF_node(dev))) {
pr_err("cxl: np = NULL\n");
return -ENODEV;
}
of_node_get(np);
while (np) {
np = of_get_next_parent(np);
prop = of_get_property(np, "device_type", NULL);
if (!prop || strcmp((char *)prop, "pciex"))
break;
depth++;
}
of_node_put(np);
return (depth > CXL_MAX_PCIEX_PARENT);
}
static int cxl_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
struct cxl *adapter;
int slice;
int rc;
if (cxl_pci_is_vphb_device(dev)) {
dev_dbg(&dev->dev, "cxl_init_adapter: Ignoring cxl vphb device\n");
return -ENODEV;
}
if (cxl_slot_is_switched(dev)) {
dev_info(&dev->dev, "Ignoring card on incompatible PCI slot\n");
return -ENODEV;
}
if (cxl_verbose)
dump_cxl_config_space(dev);
adapter = cxl_pci_init_adapter(dev);
if (IS_ERR(adapter)) {
dev_err(&dev->dev, "cxl_init_adapter failed: %li\n", PTR_ERR(adapter));
return PTR_ERR(adapter);
}
for (slice = 0; slice < adapter->slices; slice++) {
if ((rc = pci_init_afu(adapter, slice, dev))) {
dev_err(&dev->dev, "AFU %i failed to initialise: %i\n", slice, rc);
continue;
}
rc = cxl_afu_select_best_mode(adapter->afu[slice]);
if (rc)
dev_err(&dev->dev, "AFU %i failed to start: %i\n", slice, rc);
}
return 0;
}
static void cxl_remove(struct pci_dev *dev)
{
struct cxl *adapter = pci_get_drvdata(dev);
struct cxl_afu *afu;
int i;
/*
* Lock to prevent someone grabbing a ref through the adapter list as
* we are removing it
*/
for (i = 0; i < adapter->slices; i++) {
afu = adapter->afu[i];
cxl_pci_remove_afu(afu);
}
cxl_pci_remove_adapter(adapter);
}
static pci_ers_result_t cxl_vphb_error_detected(struct cxl_afu *afu,
pci_channel_state_t state)
{
struct pci_dev *afu_dev;
pci_ers_result_t result = PCI_ERS_RESULT_NEED_RESET;
pci_ers_result_t afu_result = PCI_ERS_RESULT_NEED_RESET;
/* There should only be one entry, but go through the list
* anyway
*/
list_for_each_entry(afu_dev, &afu->phb->bus->devices, bus_list) {
if (!afu_dev->driver)
continue;
afu_dev->error_state = state;
if (afu_dev->driver->err_handler)
afu_result = afu_dev->driver->err_handler->error_detected(afu_dev,
state);
/* Disconnect trumps all, NONE trumps NEED_RESET */
if (afu_result == PCI_ERS_RESULT_DISCONNECT)
result = PCI_ERS_RESULT_DISCONNECT;
else if ((afu_result == PCI_ERS_RESULT_NONE) &&
(result == PCI_ERS_RESULT_NEED_RESET))
result = PCI_ERS_RESULT_NONE;
}
return result;
}
static pci_ers_result_t cxl_pci_error_detected(struct pci_dev *pdev,
pci_channel_state_t state)
{
struct cxl *adapter = pci_get_drvdata(pdev);
struct cxl_afu *afu;
pci_ers_result_t result = PCI_ERS_RESULT_NEED_RESET;
int i;
/* At this point, we could still have an interrupt pending.
* Let's try to get them out of the way before they do
* anything we don't like.
*/
schedule();
/* If we're permanently dead, give up. */
if (state == pci_channel_io_perm_failure) {
/* Tell the AFU drivers; but we don't care what they
* say, we're going away.
*/
for (i = 0; i < adapter->slices; i++) {
afu = adapter->afu[i];
cxl_vphb_error_detected(afu, state);
}
return PCI_ERS_RESULT_DISCONNECT;
}
/* Are we reflashing?
*
* If we reflash, we could come back as something entirely
* different, including a non-CAPI card. As such, by default
* we don't participate in the process. We'll be unbound and
* the slot re-probed. (TODO: check EEH doesn't blindly rebind
* us!)
*
* However, this isn't the entire story: for reliablity
* reasons, we usually want to reflash the FPGA on PERST in
* order to get back to a more reliable known-good state.
*
* This causes us a bit of a problem: if we reflash we can't
* trust that we'll come back the same - we could have a new
* image and been PERSTed in order to load that
* image. However, most of the time we actually *will* come
* back the same - for example a regular EEH event.
*
* Therefore, we allow the user to assert that the image is
* indeed the same and that we should continue on into EEH
* anyway.
*/
if (adapter->perst_loads_image && !adapter->perst_same_image) {
/* TODO take the PHB out of CXL mode */
dev_info(&pdev->dev, "reflashing, so opting out of EEH!\n");
return PCI_ERS_RESULT_NONE;
}
/*
* At this point, we want to try to recover. We'll always
* need a complete slot reset: we don't trust any other reset.
*
* Now, we go through each AFU:
* - We send the driver, if bound, an error_detected callback.
* We expect it to clean up, but it can also tell us to give
* up and permanently detach the card. To simplify things, if
* any bound AFU driver doesn't support EEH, we give up on EEH.
*
* - We detach all contexts associated with the AFU. This
* does not free them, but puts them into a CLOSED state
* which causes any the associated files to return useful
* errors to userland. It also unmaps, but does not free,
* any IRQs.
*
* - We clean up our side: releasing and unmapping resources we hold
* so we can wire them up again when the hardware comes back up.
*
* Driver authors should note:
*
* - Any contexts you create in your kernel driver (except
* those associated with anonymous file descriptors) are
* your responsibility to free and recreate. Likewise with
* any attached resources.
*
* - We will take responsibility for re-initialising the
* device context (the one set up for you in
* cxl_pci_enable_device_hook and accessed through
* cxl_get_context). If you've attached IRQs or other
* resources to it, they remains yours to free.
*
* You can call the same functions to release resources as you
* normally would: we make sure that these functions continue
* to work when the hardware is down.
*
* Two examples:
*
* 1) If you normally free all your resources at the end of
* each request, or if you use anonymous FDs, your
* error_detected callback can simply set a flag to tell
* your driver not to start any new calls. You can then
* clear the flag in the resume callback.
*
* 2) If you normally allocate your resources on startup:
* * Set a flag in error_detected as above.
* * Let CXL detach your contexts.
* * In slot_reset, free the old resources and allocate new ones.
* * In resume, clear the flag to allow things to start.
*/
for (i = 0; i < adapter->slices; i++) {
afu = adapter->afu[i];
result = cxl_vphb_error_detected(afu, state);
/* Only continue if everyone agrees on NEED_RESET */
if (result != PCI_ERS_RESULT_NEED_RESET)
return result;
cxl_context_detach_all(afu);
cxl_ops->afu_deactivate_mode(afu, afu->current_mode);
pci_deconfigure_afu(afu);
}
cxl_deconfigure_adapter(adapter);
return result;
}
static pci_ers_result_t cxl_pci_slot_reset(struct pci_dev *pdev)
{
struct cxl *adapter = pci_get_drvdata(pdev);
struct cxl_afu *afu;
struct cxl_context *ctx;
struct pci_dev *afu_dev;
pci_ers_result_t afu_result = PCI_ERS_RESULT_RECOVERED;
pci_ers_result_t result = PCI_ERS_RESULT_RECOVERED;
int i;
if (cxl_configure_adapter(adapter, pdev))
goto err;
for (i = 0; i < adapter->slices; i++) {
afu = adapter->afu[i];
if (pci_configure_afu(afu, adapter, pdev))
goto err;
if (cxl_afu_select_best_mode(afu))
goto err;
list_for_each_entry(afu_dev, &afu->phb->bus->devices, bus_list) {
/* Reset the device context.
* TODO: make this less disruptive
*/
ctx = cxl_get_context(afu_dev);
if (ctx && cxl_release_context(ctx))
goto err;
ctx = cxl_dev_context_init(afu_dev);
if (!ctx)
goto err;
afu_dev->dev.archdata.cxl_ctx = ctx;
if (cxl_ops->afu_check_and_enable(afu))
goto err;
afu_dev->error_state = pci_channel_io_normal;
/* If there's a driver attached, allow it to
* chime in on recovery. Drivers should check
* if everything has come back OK, but
* shouldn't start new work until we call
* their resume function.
*/
if (!afu_dev->driver)
continue;
if (afu_dev->driver->err_handler &&
afu_dev->driver->err_handler->slot_reset)
afu_result = afu_dev->driver->err_handler->slot_reset(afu_dev);
if (afu_result == PCI_ERS_RESULT_DISCONNECT)
result = PCI_ERS_RESULT_DISCONNECT;
}
}
return result;
err:
/* All the bits that happen in both error_detected and cxl_remove
* should be idempotent, so we don't need to worry about leaving a mix
* of unconfigured and reconfigured resources.
*/
dev_err(&pdev->dev, "EEH recovery failed. Asking to be disconnected.\n");
return PCI_ERS_RESULT_DISCONNECT;
}
static void cxl_pci_resume(struct pci_dev *pdev)
{
struct cxl *adapter = pci_get_drvdata(pdev);
struct cxl_afu *afu;
struct pci_dev *afu_dev;
int i;
/* Everything is back now. Drivers should restart work now.
* This is not the place to be checking if everything came back up
* properly, because there's no return value: do that in slot_reset.
*/
for (i = 0; i < adapter->slices; i++) {
afu = adapter->afu[i];
list_for_each_entry(afu_dev, &afu->phb->bus->devices, bus_list) {
if (afu_dev->driver && afu_dev->driver->err_handler &&
afu_dev->driver->err_handler->resume)
afu_dev->driver->err_handler->resume(afu_dev);
}
}
}
static const struct pci_error_handlers cxl_err_handler = {
.error_detected = cxl_pci_error_detected,
.slot_reset = cxl_pci_slot_reset,
.resume = cxl_pci_resume,
};
struct pci_driver cxl_pci_driver = {
.name = "cxl-pci",
.id_table = cxl_pci_tbl,
.probe = cxl_probe,
.remove = cxl_remove,
.shutdown = cxl_remove,
.err_handler = &cxl_err_handler,
};