Merge tag 'powerpc-3.20-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mpe/linux

Pull powerpc updates from Michael Ellerman:

 - Update of all defconfigs

 - Addition of a bunch of config options to modernise our defconfigs

 - Some PS3 updates from Geoff

 - Optimised memcmp for 64 bit from Anton

 - Fix for kprobes that allows 'perf probe' to work from Naveen

 - Several cxl updates from Ian & Ryan

 - Expanded support for the '24x7' PMU from Cody & Sukadev

 - Freescale updates from Scott:
    "Highlights include 8xx optimizations, some more work on datapath
     device tree content, e300 machine check support, t1040 corenet
     error reporting, and various cleanups and fixes"

* tag 'powerpc-3.20-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mpe/linux: (102 commits)
  cxl: Add missing return statement after handling AFU errror
  cxl: Fail AFU initialisation if an invalid configuration record is found
  cxl: Export optional AFU configuration record in sysfs
  powerpc/mm: Warn on flushing tlb page in kernel context
  powerpc/powernv: Add OPAL soft-poweroff routine
  powerpc/perf/hv-24x7: Document sysfs event description entries
  powerpc/perf/hv-gpci: add the remaining gpci requests
  powerpc/perf/{hv-gpci, hv-common}: generate requests with counters annotated
  powerpc/perf/hv-24x7: parse catalog and populate sysfs with events
  perf: define EVENT_DEFINE_RANGE_FORMAT_LITE helper
  perf: add PMU_EVENT_ATTR_STRING() helper
  perf: provide sysfs_show for struct perf_pmu_events_attr
  powerpc/kernel: Avoid initializing device-tree pointer twice
  powerpc: Remove old compile time disabled syscall tracing code
  powerpc/kernel: Make syscall_exit a local label
  cxl: Fix device_node reference counting
  powerpc/mm: bail out early when flushing TLB page
  powerpc: defconfigs: add MTD_SPI_NOR (new dependency for M25P80)
  perf/powerpc: reset event hw state when adding it to the PMU
  powerpc/qe: Use strlcpy()
  ...
This commit is contained in:
Linus Torvalds
2015-02-11 18:15:38 -08:00
237 changed files with 5119 additions and 3178 deletions

View File

@@ -1,3 +1,6 @@
cxl-y += main.o file.o irq.o fault.o native.o context.o sysfs.o debugfs.o pci.o
cxl-y += main.o file.o irq.o fault.o native.o context.o sysfs.o debugfs.o pci.o trace.o
obj-$(CONFIG_CXL) += cxl.o
obj-$(CONFIG_CXL_BASE) += base.o
# For tracepoints to include our trace.h from tracepoint infrastructure:
CFLAGS_trace.o := -I$(src)

View File

@@ -287,6 +287,13 @@ static const cxl_p2n_reg_t CXL_PSL_WED_An = {0x0A0};
#define CXL_PE_SOFTWARE_STATE_S (1ul << (31 - 30)) /* Suspend */
#define CXL_PE_SOFTWARE_STATE_T (1ul << (31 - 31)) /* Terminate */
/****** CXL_PSL_RXCTL_An (Implementation Specific) **************************
* Controls AFU Hang Pulse, which sets the timeout for the AFU to respond to
* the PSL for any response (except MMIO). Timeouts will occur between 1x to 2x
* of the hang pulse frequency.
*/
#define CXL_PSL_RXCTL_AFUHP_4S 0x7000000000000000ULL
/* SPA->sw_command_status */
#define CXL_SPA_SW_CMD_MASK 0xffff000000000000ULL
#define CXL_SPA_SW_CMD_TERMINATE 0x0001000000000000ULL
@@ -375,6 +382,10 @@ struct cxl_afu {
int slice;
int modes_supported;
int current_mode;
int crs_num;
u64 crs_len;
u64 crs_offset;
struct list_head crs;
enum prefault_modes prefault_mode;
bool psa;
bool pp_psa;
@@ -481,6 +492,8 @@ void cxl_release_one_irq(struct cxl *adapter, int hwirq);
int cxl_alloc_irq_ranges(struct cxl_irq_ranges *irqs, struct cxl *adapter, unsigned int num);
void cxl_release_irq_ranges(struct cxl_irq_ranges *irqs, struct cxl *adapter);
int cxl_setup_irq(struct cxl *adapter, unsigned int hwirq, unsigned int virq);
int cxl_update_image_control(struct cxl *adapter);
int cxl_reset(struct cxl *adapter);
/* common == phyp + powernv */
struct cxl_process_element_common {
@@ -542,6 +555,15 @@ static inline void __iomem *_cxl_p2n_addr(struct cxl_afu *afu, cxl_p2n_reg_t reg
#define cxl_p2n_read(afu, reg) \
in_be64(_cxl_p2n_addr(afu, reg))
#define cxl_afu_cr_read64(afu, cr, off) \
in_le64((afu)->afu_desc_mmio + (afu)->crs_offset + ((cr) * (afu)->crs_len) + (off))
#define cxl_afu_cr_read32(afu, cr, off) \
in_le32((afu)->afu_desc_mmio + (afu)->crs_offset + ((cr) * (afu)->crs_len) + (off))
u16 cxl_afu_cr_read16(struct cxl_afu *afu, int cr, u64 off);
u8 cxl_afu_cr_read8(struct cxl_afu *afu, int cr, u64 off);
struct cxl_calls {
void (*cxl_slbia)(struct mm_struct *mm);
struct module *owner;

View File

@@ -20,6 +20,7 @@
#include <asm/mmu.h>
#include "cxl.h"
#include "trace.h"
static bool sste_matches(struct cxl_sste *sste, struct copro_slb *slb)
{
@@ -75,6 +76,7 @@ static void cxl_load_segment(struct cxl_context *ctx, struct copro_slb *slb)
pr_devel("CXL Populating SST[%li]: %#llx %#llx\n",
sste - ctx->sstp, slb->vsid, slb->esid);
trace_cxl_ste_write(ctx, sste - ctx->sstp, slb->esid, slb->vsid);
sste->vsid_data = cpu_to_be64(slb->vsid);
sste->esid_data = cpu_to_be64(slb->esid);
@@ -116,6 +118,7 @@ static int cxl_handle_segment_miss(struct cxl_context *ctx,
int rc;
pr_devel("CXL interrupt: Segment fault pe: %i ea: %#llx\n", ctx->pe, ea);
trace_cxl_ste_miss(ctx, ea);
if ((rc = cxl_fault_segment(ctx, mm, ea)))
cxl_ack_ae(ctx);
@@ -135,6 +138,8 @@ static void cxl_handle_page_fault(struct cxl_context *ctx,
int result;
unsigned long access, flags, inv_flags = 0;
trace_cxl_pte_miss(ctx, dsisr, dar);
if ((result = copro_handle_mm_fault(mm, dar, dsisr, &flt))) {
pr_devel("copro_handle_mm_fault failed: %#x\n", result);
return cxl_ack_ae(ctx);
@@ -180,6 +185,12 @@ void cxl_handle_fault(struct work_struct *fault_work)
return;
}
/* Early return if the context is being / has been detached */
if (ctx->status == CLOSED) {
cxl_ack_ae(ctx);
return;
}
pr_devel("CXL BOTTOM HALF handling fault for afu pe: %i. "
"DSISR: %#llx DAR: %#llx\n", ctx->pe, dsisr, dar);

View File

@@ -23,6 +23,7 @@
#include <asm/copro.h>
#include "cxl.h"
#include "trace.h"
#define CXL_NUM_MINORS 256 /* Total to reserve */
#define CXL_DEV_MINORS 13 /* 1 control + 4 AFUs * 3 (dedicated/master/shared) */
@@ -186,9 +187,13 @@ static long afu_ioctl_start_work(struct cxl_context *ctx,
*/
ctx->pid = get_pid(get_task_pid(current, PIDTYPE_PID));
trace_cxl_attach(ctx, work.work_element_descriptor, work.num_interrupts, amr);
if ((rc = cxl_attach_process(ctx, false, work.work_element_descriptor,
amr)))
amr))) {
afu_release_irqs(ctx);
goto out;
}
ctx->status = STARTED;
rc = 0;

View File

@@ -17,6 +17,7 @@
#include <misc/cxl.h>
#include "cxl.h"
#include "trace.h"
/* XXX: This is implementation specific */
static irqreturn_t handle_psl_slice_error(struct cxl_context *ctx, u64 dsisr, u64 errstat)
@@ -100,6 +101,8 @@ static irqreturn_t cxl_irq(int irq, void *data, struct cxl_irq_info *irq_info)
dsisr = irq_info->dsisr;
dar = irq_info->dar;
trace_cxl_psl_irq(ctx, irq, dsisr, dar);
pr_devel("CXL interrupt %i for afu pe: %i DSISR: %#llx DAR: %#llx\n", irq, ctx->pe, dsisr, dar);
if (dsisr & CXL_PSL_DSISR_An_DS) {
@@ -167,6 +170,7 @@ static irqreturn_t cxl_irq(int irq, void *data, struct cxl_irq_info *irq_info)
}
cxl_ack_irq(ctx, CXL_PSL_TFC_An_A, 0);
return IRQ_HANDLED;
}
if (dsisr & CXL_PSL_DSISR_An_OC)
pr_devel("CXL interrupt: OS Context Warning\n");
@@ -237,6 +241,7 @@ static irqreturn_t cxl_irq_afu(int irq, void *data)
return IRQ_HANDLED;
}
trace_cxl_afu_irq(ctx, afu_irq, irq, hwirq);
pr_devel("Received AFU interrupt %i for pe: %i (virq %i hwirq %lx)\n",
afu_irq, ctx->pe, irq, hwirq);
@@ -436,7 +441,7 @@ int afu_register_irqs(struct cxl_context *ctx, u32 count)
*/
INIT_LIST_HEAD(&ctx->irq_names);
for (r = 1; r < CXL_IRQ_RANGES; r++) {
for (i = 0; i < ctx->irqs.range[r]; hwirq++, i++) {
for (i = 0; i < ctx->irqs.range[r]; i++) {
irq_name = kmalloc(sizeof(struct cxl_irq_name),
GFP_KERNEL);
if (!irq_name)

View File

@@ -23,6 +23,7 @@
#include <misc/cxl.h>
#include "cxl.h"
#include "trace.h"
static DEFINE_SPINLOCK(adapter_idr_lock);
static DEFINE_IDR(cxl_adapter_idr);
@@ -48,6 +49,7 @@ static inline void _cxl_slbia(struct cxl_context *ctx, struct mm_struct *mm)
ctx->afu->adapter->adapter_num, ctx->afu->slice, ctx->pe);
spin_lock_irqsave(&ctx->sste_lock, flags);
trace_cxl_slbia(ctx);
memset(ctx->sstp, 0, ctx->sst_size);
spin_unlock_irqrestore(&ctx->sste_lock, flags);
mb();

View File

@@ -18,24 +18,28 @@
#include <misc/cxl.h>
#include "cxl.h"
#include "trace.h"
static int afu_control(struct cxl_afu *afu, u64 command,
u64 result, u64 mask, bool enabled)
{
u64 AFU_Cntl = cxl_p2n_read(afu, CXL_AFU_Cntl_An);
unsigned long timeout = jiffies + (HZ * CXL_TIMEOUT);
int rc = 0;
spin_lock(&afu->afu_cntl_lock);
pr_devel("AFU command starting: %llx\n", command);
trace_cxl_afu_ctrl(afu, command);
cxl_p2n_write(afu, CXL_AFU_Cntl_An, AFU_Cntl | command);
AFU_Cntl = cxl_p2n_read(afu, CXL_AFU_Cntl_An);
while ((AFU_Cntl & mask) != result) {
if (time_after_eq(jiffies, timeout)) {
dev_warn(&afu->dev, "WARNING: AFU control timed out!\n");
spin_unlock(&afu->afu_cntl_lock);
return -EBUSY;
rc = -EBUSY;
goto out;
}
pr_devel_ratelimited("AFU control... (0x%.16llx)\n",
AFU_Cntl | command);
@@ -44,9 +48,11 @@ static int afu_control(struct cxl_afu *afu, u64 command,
};
pr_devel("AFU command complete: %llx\n", command);
afu->enabled = enabled;
out:
trace_cxl_afu_ctrl_done(afu, command, rc);
spin_unlock(&afu->afu_cntl_lock);
return 0;
return rc;
}
static int afu_enable(struct cxl_afu *afu)
@@ -91,6 +97,9 @@ int cxl_psl_purge(struct cxl_afu *afu)
u64 dsisr, dar;
u64 start, end;
unsigned long timeout = jiffies + (HZ * CXL_TIMEOUT);
int rc = 0;
trace_cxl_psl_ctrl(afu, CXL_PSL_SCNTL_An_Pc);
pr_devel("PSL purge request\n");
@@ -107,7 +116,8 @@ int cxl_psl_purge(struct cxl_afu *afu)
== CXL_PSL_SCNTL_An_Ps_Pending) {
if (time_after_eq(jiffies, timeout)) {
dev_warn(&afu->dev, "WARNING: PSL Purge timed out!\n");
return -EBUSY;
rc = -EBUSY;
goto out;
}
dsisr = cxl_p2n_read(afu, CXL_PSL_DSISR_An);
pr_devel_ratelimited("PSL purging... PSL_CNTL: 0x%.16llx PSL_DSISR: 0x%.16llx\n", PSL_CNTL, dsisr);
@@ -128,7 +138,9 @@ int cxl_psl_purge(struct cxl_afu *afu)
cxl_p1n_write(afu, CXL_PSL_SCNTL_An,
PSL_CNTL & ~CXL_PSL_SCNTL_An_Pc);
return 0;
out:
trace_cxl_psl_ctrl_done(afu, CXL_PSL_SCNTL_An_Pc, rc);
return rc;
}
static int spa_max_procs(int spa_size)
@@ -185,6 +197,7 @@ static int alloc_spa(struct cxl_afu *afu)
static void release_spa(struct cxl_afu *afu)
{
cxl_p1n_write(afu, CXL_PSL_SPAP_An, 0);
free_pages((unsigned long) afu->spa, afu->spa_order);
}
@@ -278,6 +291,9 @@ static int do_process_element_cmd(struct cxl_context *ctx,
{
u64 state;
unsigned long timeout = jiffies + (HZ * CXL_TIMEOUT);
int rc = 0;
trace_cxl_llcmd(ctx, cmd);
WARN_ON(!ctx->afu->enabled);
@@ -289,12 +305,14 @@ static int do_process_element_cmd(struct cxl_context *ctx,
while (1) {
if (time_after_eq(jiffies, timeout)) {
dev_warn(&ctx->afu->dev, "WARNING: Process Element Command timed out!\n");
return -EBUSY;
rc = -EBUSY;
goto out;
}
state = be64_to_cpup(ctx->afu->sw_command_status);
if (state == ~0ULL) {
pr_err("cxl: Error adding process element to AFU\n");
return -1;
rc = -1;
goto out;
}
if ((state & (CXL_SPA_SW_CMD_MASK | CXL_SPA_SW_STATE_MASK | CXL_SPA_SW_LINK_MASK)) ==
(cmd | (cmd >> 16) | ctx->pe))
@@ -309,7 +327,9 @@ static int do_process_element_cmd(struct cxl_context *ctx,
schedule();
}
return 0;
out:
trace_cxl_llcmd_done(ctx, cmd, rc);
return rc;
}
static int add_process_element(struct cxl_context *ctx)
@@ -629,6 +649,8 @@ static inline int detach_process_native_afu_directed(struct cxl_context *ctx)
int cxl_detach_process(struct cxl_context *ctx)
{
trace_cxl_detach(ctx);
if (ctx->afu->current_mode == CXL_MODE_DEDICATED)
return detach_process_native_dedicated(ctx);
@@ -667,6 +689,7 @@ static void recover_psl_err(struct cxl_afu *afu, u64 errstat)
int cxl_ack_irq(struct cxl_context *ctx, u64 tfc, u64 psl_reset_mask)
{
trace_cxl_psl_irq_ack(ctx, tfc);
if (tfc)
cxl_p2n_write(ctx->afu, CXL_PSL_TFC_An, tfc);
if (psl_reset_mask)

View File

@@ -21,6 +21,7 @@
#include <asm/msi_bitmap.h>
#include <asm/pci-bridge.h> /* for struct pci_controller */
#include <asm/pnv-pci.h>
#include <asm/io.h>
#include "cxl.h"
@@ -113,6 +114,24 @@
#define AFUD_EB_LEN(val) EXTRACT_PPC_BITS(val, 8, 63)
#define AFUD_READ_EB_OFF(afu) AFUD_READ(afu, 0x48)
u16 cxl_afu_cr_read16(struct cxl_afu *afu, int cr, u64 off)
{
u64 aligned_off = off & ~0x3L;
u32 val;
val = cxl_afu_cr_read32(afu, cr, aligned_off);
return (val >> ((off & 0x2) * 8)) & 0xffff;
}
u8 cxl_afu_cr_read8(struct cxl_afu *afu, int cr, u64 off)
{
u64 aligned_off = off & ~0x3L;
u32 val;
val = cxl_afu_cr_read32(afu, cr, aligned_off);
return (val >> ((off & 0x3) * 8)) & 0xff;
}
static DEFINE_PCI_DEVICE_TABLE(cxl_pci_tbl) = {
{ PCI_DEVICE(PCI_VENDOR_ID_IBM, 0x0477), },
{ PCI_DEVICE(PCI_VENDOR_ID_IBM, 0x044b), },
@@ -316,7 +335,7 @@ static int init_implementation_adapter_regs(struct cxl *adapter, struct pci_dev
u64 psl_dsnctl;
u64 chipid;
if (!(np = pnv_pci_to_phb_node(dev)))
if (!(np = pnv_pci_get_phb_node(dev)))
return -ENODEV;
while (np && !(prop = of_get_property(np, "ibm,chip-id", NULL)))
@@ -348,7 +367,7 @@ static int init_implementation_afu_regs(struct cxl_afu *afu)
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, 0xF000000000000000ULL);
cxl_p1n_write(afu, CXL_PSL_RXCTL_A, CXL_PSL_RXCTL_AFUHP_4S);
return 0;
}
@@ -361,6 +380,41 @@ int cxl_setup_irq(struct cxl *adapter, unsigned int hwirq,
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_alloc_one_irq(struct cxl *adapter)
{
struct pci_dev *dev = to_pci_dev(adapter->dev.parent);
@@ -520,6 +574,7 @@ static int cxl_read_afu_descriptor(struct cxl_afu *afu)
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;
@@ -534,11 +589,17 @@ static int cxl_read_afu_descriptor(struct cxl_afu *afu)
if ((afu->pp_psa = AFUD_PPPSA_PP(val)))
afu->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);
return 0;
}
static int cxl_afu_descriptor_looks_ok(struct cxl_afu *afu)
{
int i;
if (afu->psa && afu->adapter->ps_size <
(afu->pp_offset + afu->pp_size*afu->max_procs_virtualised)) {
dev_err(&afu->dev, "per-process PSA can't fit inside the PSA!\n");
@@ -548,6 +609,13 @@ static int cxl_afu_descriptor_looks_ok(struct cxl_afu *afu)
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++) {
if ((cxl_afu_cr_read32(afu, i, 0) == 0)) {
dev_err(&afu->dev, "ABORTING: AFU configuration record %i is invalid\n", i);
return -EINVAL;
}
}
return 0;
}
@@ -706,6 +774,42 @@ static void cxl_remove_afu(struct cxl_afu *afu)
device_unregister(&afu->dev);
}
int cxl_reset(struct cxl *adapter)
{
struct pci_dev *dev = to_pci_dev(adapter->dev.parent);
int rc;
int i;
u32 val;
dev_info(&dev->dev, "CXL reset\n");
for (i = 0; i < adapter->slices; i++)
cxl_remove_afu(adapter->afu[i]);
/* 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;
}
/* the PERST done above fences the PHB. So, reset depends on EEH
* to unbind the driver, tell Sapphire to reinit the PHB, and rebind
* the driver. Do an mmio read explictly to ensure EEH notices the
* fenced PHB. Retry for a few seconds before giving up. */
i = 0;
while (((val = mmio_read32be(adapter->p1_mmio)) != 0xffffffff) &&
(i < 5)) {
msleep(500);
i++;
}
if (val != 0xffffffff)
dev_err(&dev->dev, "cxl: PERST failed to trigger EEH\n");
return rc;
}
static int cxl_map_adapter_regs(struct cxl *adapter, struct pci_dev *dev)
{
@@ -770,8 +874,8 @@ static int cxl_read_vsec(struct cxl *adapter, struct pci_dev *dev)
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_loads_image = !!(image_state & CXL_VSEC_PERST_LOADS_IMAGE);
adapter->perst_select_user = !!(image_state & CXL_VSEC_PERST_SELECT_USER);
adapter->perst_loads_image = true;
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);
@@ -879,6 +983,9 @@ static struct cxl *cxl_init_adapter(struct pci_dev *dev)
if ((rc = cxl_vsec_looks_ok(adapter, dev)))
goto err2;
if ((rc = cxl_update_image_control(adapter)))
goto err2;
if ((rc = cxl_map_adapter_regs(adapter, dev)))
goto err2;
@@ -888,9 +995,15 @@ static struct cxl *cxl_init_adapter(struct pci_dev *dev)
if ((rc = init_implementation_adapter_regs(adapter, dev)))
goto err3;
if ((rc = pnv_phb_to_cxl(dev)))
if ((rc = pnv_phb_to_cxl_mode(dev, OPAL_PHB_CAPI_MODE_CAPI)))
goto err3;
/* 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 err3;
}
if ((rc = cxl_register_psl_err_irq(adapter)))
goto err3;

View File

@@ -10,6 +10,7 @@
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/sysfs.h>
#include <linux/pci_regs.h>
#include "cxl.h"
@@ -56,11 +57,68 @@ static ssize_t image_loaded_show(struct device *device,
return scnprintf(buf, PAGE_SIZE, "factory\n");
}
static ssize_t reset_adapter_store(struct device *device,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct cxl *adapter = to_cxl_adapter(device);
int rc;
int val;
rc = sscanf(buf, "%i", &val);
if ((rc != 1) || (val != 1))
return -EINVAL;
if ((rc = cxl_reset(adapter)))
return rc;
return count;
}
static ssize_t load_image_on_perst_show(struct device *device,
struct device_attribute *attr,
char *buf)
{
struct cxl *adapter = to_cxl_adapter(device);
if (!adapter->perst_loads_image)
return scnprintf(buf, PAGE_SIZE, "none\n");
if (adapter->perst_select_user)
return scnprintf(buf, PAGE_SIZE, "user\n");
return scnprintf(buf, PAGE_SIZE, "factory\n");
}
static ssize_t load_image_on_perst_store(struct device *device,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct cxl *adapter = to_cxl_adapter(device);
int rc;
if (!strncmp(buf, "none", 4))
adapter->perst_loads_image = false;
else if (!strncmp(buf, "user", 4)) {
adapter->perst_select_user = true;
adapter->perst_loads_image = true;
} else if (!strncmp(buf, "factory", 7)) {
adapter->perst_select_user = false;
adapter->perst_loads_image = true;
} else
return -EINVAL;
if ((rc = cxl_update_image_control(adapter)))
return rc;
return count;
}
static struct device_attribute adapter_attrs[] = {
__ATTR_RO(caia_version),
__ATTR_RO(psl_revision),
__ATTR_RO(base_image),
__ATTR_RO(image_loaded),
__ATTR_RW(load_image_on_perst),
__ATTR(reset, S_IWUSR, NULL, reset_adapter_store),
};
@@ -310,8 +368,6 @@ static struct device_attribute afu_attrs[] = {
__ATTR(reset, S_IWUSR, NULL, reset_store_afu),
};
int cxl_sysfs_adapter_add(struct cxl *adapter)
{
int i, rc;
@@ -334,31 +390,191 @@ void cxl_sysfs_adapter_remove(struct cxl *adapter)
device_remove_file(&adapter->dev, &adapter_attrs[i]);
}
struct afu_config_record {
struct kobject kobj;
struct bin_attribute config_attr;
struct list_head list;
int cr;
u16 device;
u16 vendor;
u32 class;
};
#define to_cr(obj) container_of(obj, struct afu_config_record, kobj)
static ssize_t vendor_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
struct afu_config_record *cr = to_cr(kobj);
return scnprintf(buf, PAGE_SIZE, "0x%.4x\n", cr->vendor);
}
static ssize_t device_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
struct afu_config_record *cr = to_cr(kobj);
return scnprintf(buf, PAGE_SIZE, "0x%.4x\n", cr->device);
}
static ssize_t class_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
struct afu_config_record *cr = to_cr(kobj);
return scnprintf(buf, PAGE_SIZE, "0x%.6x\n", cr->class);
}
static ssize_t afu_read_config(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr, char *buf,
loff_t off, size_t count)
{
struct afu_config_record *cr = to_cr(kobj);
struct cxl_afu *afu = to_cxl_afu(container_of(kobj->parent, struct device, kobj));
u64 i, j, val, size = afu->crs_len;
if (off > size)
return 0;
if (off + count > size)
count = size - off;
for (i = 0; i < count;) {
val = cxl_afu_cr_read64(afu, cr->cr, off & ~0x7);
for (j = off & 0x7; j < 8 && i < count; i++, j++, off++)
buf[i] = (val >> (j * 8)) & 0xff;
}
return count;
}
static struct kobj_attribute vendor_attribute =
__ATTR_RO(vendor);
static struct kobj_attribute device_attribute =
__ATTR_RO(device);
static struct kobj_attribute class_attribute =
__ATTR_RO(class);
static struct attribute *afu_cr_attrs[] = {
&vendor_attribute.attr,
&device_attribute.attr,
&class_attribute.attr,
NULL,
};
static void release_afu_config_record(struct kobject *kobj)
{
struct afu_config_record *cr = to_cr(kobj);
kfree(cr);
}
static struct kobj_type afu_config_record_type = {
.sysfs_ops = &kobj_sysfs_ops,
.release = release_afu_config_record,
.default_attrs = afu_cr_attrs,
};
static struct afu_config_record *cxl_sysfs_afu_new_cr(struct cxl_afu *afu, int cr_idx)
{
struct afu_config_record *cr;
int rc;
cr = kzalloc(sizeof(struct afu_config_record), GFP_KERNEL);
if (!cr)
return ERR_PTR(-ENOMEM);
cr->cr = cr_idx;
cr->device = cxl_afu_cr_read16(afu, cr_idx, PCI_DEVICE_ID);
cr->vendor = cxl_afu_cr_read16(afu, cr_idx, PCI_VENDOR_ID);
cr->class = cxl_afu_cr_read32(afu, cr_idx, PCI_CLASS_REVISION) >> 8;
/*
* Export raw AFU PCIe like config record. For now this is read only by
* root - we can expand that later to be readable by non-root and maybe
* even writable provided we have a good use-case. Once we suport
* exposing AFUs through a virtual PHB they will get that for free from
* Linux' PCI infrastructure, but until then it's not clear that we
* need it for anything since the main use case is just identifying
* AFUs, which can be done via the vendor, device and class attributes.
*/
sysfs_bin_attr_init(&cr->config_attr);
cr->config_attr.attr.name = "config";
cr->config_attr.attr.mode = S_IRUSR;
cr->config_attr.size = afu->crs_len;
cr->config_attr.read = afu_read_config;
rc = kobject_init_and_add(&cr->kobj, &afu_config_record_type,
&afu->dev.kobj, "cr%i", cr->cr);
if (rc)
goto err;
rc = sysfs_create_bin_file(&cr->kobj, &cr->config_attr);
if (rc)
goto err1;
rc = kobject_uevent(&cr->kobj, KOBJ_ADD);
if (rc)
goto err2;
return cr;
err2:
sysfs_remove_bin_file(&cr->kobj, &cr->config_attr);
err1:
kobject_put(&cr->kobj);
return ERR_PTR(rc);
err:
kfree(cr);
return ERR_PTR(rc);
}
void cxl_sysfs_afu_remove(struct cxl_afu *afu)
{
struct afu_config_record *cr, *tmp;
int i;
for (i = 0; i < ARRAY_SIZE(afu_attrs); i++)
device_remove_file(&afu->dev, &afu_attrs[i]);
list_for_each_entry_safe(cr, tmp, &afu->crs, list) {
sysfs_remove_bin_file(&cr->kobj, &cr->config_attr);
kobject_put(&cr->kobj);
}
}
int cxl_sysfs_afu_add(struct cxl_afu *afu)
{
struct afu_config_record *cr;
int i, rc;
INIT_LIST_HEAD(&afu->crs);
for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) {
if ((rc = device_create_file(&afu->dev, &afu_attrs[i])))
goto err;
}
for (i = 0; i < afu->crs_num; i++) {
cr = cxl_sysfs_afu_new_cr(afu, i);
if (IS_ERR(cr)) {
rc = PTR_ERR(cr);
goto err1;
}
list_add(&cr->list, &afu->crs);
}
return 0;
err1:
cxl_sysfs_afu_remove(afu);
return rc;
err:
for (i--; i >= 0; i--)
device_remove_file(&afu->dev, &afu_attrs[i]);
return rc;
}
void cxl_sysfs_afu_remove(struct cxl_afu *afu)
{
int i;
for (i = 0; i < ARRAY_SIZE(afu_attrs); i++)
device_remove_file(&afu->dev, &afu_attrs[i]);
}
int cxl_sysfs_afu_m_add(struct cxl_afu *afu)
{
int i, rc;

13
drivers/misc/cxl/trace.c Normal file
View File

@@ -0,0 +1,13 @@
/*
* Copyright 2015 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.
*/
#ifndef __CHECKER__
#define CREATE_TRACE_POINTS
#include "trace.h"
#endif

459
drivers/misc/cxl/trace.h Normal file
View File

@@ -0,0 +1,459 @@
/*
* Copyright 2015 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.
*/
#undef TRACE_SYSTEM
#define TRACE_SYSTEM cxl
#if !defined(_CXL_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
#define _CXL_TRACE_H
#include <linux/tracepoint.h>
#include "cxl.h"
#define DSISR_FLAGS \
{ CXL_PSL_DSISR_An_DS, "DS" }, \
{ CXL_PSL_DSISR_An_DM, "DM" }, \
{ CXL_PSL_DSISR_An_ST, "ST" }, \
{ CXL_PSL_DSISR_An_UR, "UR" }, \
{ CXL_PSL_DSISR_An_PE, "PE" }, \
{ CXL_PSL_DSISR_An_AE, "AE" }, \
{ CXL_PSL_DSISR_An_OC, "OC" }, \
{ CXL_PSL_DSISR_An_M, "M" }, \
{ CXL_PSL_DSISR_An_P, "P" }, \
{ CXL_PSL_DSISR_An_A, "A" }, \
{ CXL_PSL_DSISR_An_S, "S" }, \
{ CXL_PSL_DSISR_An_K, "K" }
#define TFC_FLAGS \
{ CXL_PSL_TFC_An_A, "A" }, \
{ CXL_PSL_TFC_An_C, "C" }, \
{ CXL_PSL_TFC_An_AE, "AE" }, \
{ CXL_PSL_TFC_An_R, "R" }
#define LLCMD_NAMES \
{ CXL_SPA_SW_CMD_TERMINATE, "TERMINATE" }, \
{ CXL_SPA_SW_CMD_REMOVE, "REMOVE" }, \
{ CXL_SPA_SW_CMD_SUSPEND, "SUSPEND" }, \
{ CXL_SPA_SW_CMD_RESUME, "RESUME" }, \
{ CXL_SPA_SW_CMD_ADD, "ADD" }, \
{ CXL_SPA_SW_CMD_UPDATE, "UPDATE" }
#define AFU_COMMANDS \
{ 0, "DISABLE" }, \
{ CXL_AFU_Cntl_An_E, "ENABLE" }, \
{ CXL_AFU_Cntl_An_RA, "RESET" }
#define PSL_COMMANDS \
{ CXL_PSL_SCNTL_An_Pc, "PURGE" }, \
{ CXL_PSL_SCNTL_An_Sc, "SUSPEND" }
DECLARE_EVENT_CLASS(cxl_pe_class,
TP_PROTO(struct cxl_context *ctx),
TP_ARGS(ctx),
TP_STRUCT__entry(
__field(u8, card)
__field(u8, afu)
__field(u16, pe)
),
TP_fast_assign(
__entry->card = ctx->afu->adapter->adapter_num;
__entry->afu = ctx->afu->slice;
__entry->pe = ctx->pe;
),
TP_printk("afu%i.%i pe=%i",
__entry->card,
__entry->afu,
__entry->pe
)
);
TRACE_EVENT(cxl_attach,
TP_PROTO(struct cxl_context *ctx, u64 wed, s16 num_interrupts, u64 amr),
TP_ARGS(ctx, wed, num_interrupts, amr),
TP_STRUCT__entry(
__field(u8, card)
__field(u8, afu)
__field(u16, pe)
__field(pid_t, pid)
__field(u64, wed)
__field(u64, amr)
__field(s16, num_interrupts)
),
TP_fast_assign(
__entry->card = ctx->afu->adapter->adapter_num;
__entry->afu = ctx->afu->slice;
__entry->pe = ctx->pe;
__entry->pid = pid_nr(ctx->pid);
__entry->wed = wed;
__entry->amr = amr;
__entry->num_interrupts = num_interrupts;
),
TP_printk("afu%i.%i pid=%i pe=%i wed=0x%.16llx irqs=%i amr=0x%llx",
__entry->card,
__entry->afu,
__entry->pid,
__entry->pe,
__entry->wed,
__entry->num_interrupts,
__entry->amr
)
);
DEFINE_EVENT(cxl_pe_class, cxl_detach,
TP_PROTO(struct cxl_context *ctx),
TP_ARGS(ctx)
);
TRACE_EVENT(cxl_afu_irq,
TP_PROTO(struct cxl_context *ctx, int afu_irq, int virq, irq_hw_number_t hwirq),
TP_ARGS(ctx, afu_irq, virq, hwirq),
TP_STRUCT__entry(
__field(u8, card)
__field(u8, afu)
__field(u16, pe)
__field(u16, afu_irq)
__field(int, virq)
__field(irq_hw_number_t, hwirq)
),
TP_fast_assign(
__entry->card = ctx->afu->adapter->adapter_num;
__entry->afu = ctx->afu->slice;
__entry->pe = ctx->pe;
__entry->afu_irq = afu_irq;
__entry->virq = virq;
__entry->hwirq = hwirq;
),
TP_printk("afu%i.%i pe=%i afu_irq=%i virq=%i hwirq=0x%lx",
__entry->card,
__entry->afu,
__entry->pe,
__entry->afu_irq,
__entry->virq,
__entry->hwirq
)
);
TRACE_EVENT(cxl_psl_irq,
TP_PROTO(struct cxl_context *ctx, int irq, u64 dsisr, u64 dar),
TP_ARGS(ctx, irq, dsisr, dar),
TP_STRUCT__entry(
__field(u8, card)
__field(u8, afu)
__field(u16, pe)
__field(int, irq)
__field(u64, dsisr)
__field(u64, dar)
),
TP_fast_assign(
__entry->card = ctx->afu->adapter->adapter_num;
__entry->afu = ctx->afu->slice;
__entry->pe = ctx->pe;
__entry->irq = irq;
__entry->dsisr = dsisr;
__entry->dar = dar;
),
TP_printk("afu%i.%i pe=%i irq=%i dsisr=%s dar=0x%.16llx",
__entry->card,
__entry->afu,
__entry->pe,
__entry->irq,
__print_flags(__entry->dsisr, "|", DSISR_FLAGS),
__entry->dar
)
);
TRACE_EVENT(cxl_psl_irq_ack,
TP_PROTO(struct cxl_context *ctx, u64 tfc),
TP_ARGS(ctx, tfc),
TP_STRUCT__entry(
__field(u8, card)
__field(u8, afu)
__field(u16, pe)
__field(u64, tfc)
),
TP_fast_assign(
__entry->card = ctx->afu->adapter->adapter_num;
__entry->afu = ctx->afu->slice;
__entry->pe = ctx->pe;
__entry->tfc = tfc;
),
TP_printk("afu%i.%i pe=%i tfc=%s",
__entry->card,
__entry->afu,
__entry->pe,
__print_flags(__entry->tfc, "|", TFC_FLAGS)
)
);
TRACE_EVENT(cxl_ste_miss,
TP_PROTO(struct cxl_context *ctx, u64 dar),
TP_ARGS(ctx, dar),
TP_STRUCT__entry(
__field(u8, card)
__field(u8, afu)
__field(u16, pe)
__field(u64, dar)
),
TP_fast_assign(
__entry->card = ctx->afu->adapter->adapter_num;
__entry->afu = ctx->afu->slice;
__entry->pe = ctx->pe;
__entry->dar = dar;
),
TP_printk("afu%i.%i pe=%i dar=0x%.16llx",
__entry->card,
__entry->afu,
__entry->pe,
__entry->dar
)
);
TRACE_EVENT(cxl_ste_write,
TP_PROTO(struct cxl_context *ctx, unsigned int idx, u64 e, u64 v),
TP_ARGS(ctx, idx, e, v),
TP_STRUCT__entry(
__field(u8, card)
__field(u8, afu)
__field(u16, pe)
__field(unsigned int, idx)
__field(u64, e)
__field(u64, v)
),
TP_fast_assign(
__entry->card = ctx->afu->adapter->adapter_num;
__entry->afu = ctx->afu->slice;
__entry->pe = ctx->pe;
__entry->idx = idx;
__entry->e = e;
__entry->v = v;
),
TP_printk("afu%i.%i pe=%i SSTE[%i] E=0x%.16llx V=0x%.16llx",
__entry->card,
__entry->afu,
__entry->pe,
__entry->idx,
__entry->e,
__entry->v
)
);
TRACE_EVENT(cxl_pte_miss,
TP_PROTO(struct cxl_context *ctx, u64 dsisr, u64 dar),
TP_ARGS(ctx, dsisr, dar),
TP_STRUCT__entry(
__field(u8, card)
__field(u8, afu)
__field(u16, pe)
__field(u64, dsisr)
__field(u64, dar)
),
TP_fast_assign(
__entry->card = ctx->afu->adapter->adapter_num;
__entry->afu = ctx->afu->slice;
__entry->pe = ctx->pe;
__entry->dsisr = dsisr;
__entry->dar = dar;
),
TP_printk("afu%i.%i pe=%i dsisr=%s dar=0x%.16llx",
__entry->card,
__entry->afu,
__entry->pe,
__print_flags(__entry->dsisr, "|", DSISR_FLAGS),
__entry->dar
)
);
TRACE_EVENT(cxl_llcmd,
TP_PROTO(struct cxl_context *ctx, u64 cmd),
TP_ARGS(ctx, cmd),
TP_STRUCT__entry(
__field(u8, card)
__field(u8, afu)
__field(u16, pe)
__field(u64, cmd)
),
TP_fast_assign(
__entry->card = ctx->afu->adapter->adapter_num;
__entry->afu = ctx->afu->slice;
__entry->pe = ctx->pe;
__entry->cmd = cmd;
),
TP_printk("afu%i.%i pe=%i cmd=%s",
__entry->card,
__entry->afu,
__entry->pe,
__print_symbolic_u64(__entry->cmd, LLCMD_NAMES)
)
);
TRACE_EVENT(cxl_llcmd_done,
TP_PROTO(struct cxl_context *ctx, u64 cmd, int rc),
TP_ARGS(ctx, cmd, rc),
TP_STRUCT__entry(
__field(u8, card)
__field(u8, afu)
__field(u16, pe)
__field(u64, cmd)
__field(int, rc)
),
TP_fast_assign(
__entry->card = ctx->afu->adapter->adapter_num;
__entry->afu = ctx->afu->slice;
__entry->pe = ctx->pe;
__entry->rc = rc;
__entry->cmd = cmd;
),
TP_printk("afu%i.%i pe=%i cmd=%s rc=%i",
__entry->card,
__entry->afu,
__entry->pe,
__print_symbolic_u64(__entry->cmd, LLCMD_NAMES),
__entry->rc
)
);
DECLARE_EVENT_CLASS(cxl_afu_psl_ctrl,
TP_PROTO(struct cxl_afu *afu, u64 cmd),
TP_ARGS(afu, cmd),
TP_STRUCT__entry(
__field(u8, card)
__field(u8, afu)
__field(u64, cmd)
),
TP_fast_assign(
__entry->card = afu->adapter->adapter_num;
__entry->afu = afu->slice;
__entry->cmd = cmd;
),
TP_printk("afu%i.%i cmd=%s",
__entry->card,
__entry->afu,
__print_symbolic_u64(__entry->cmd, AFU_COMMANDS)
)
);
DECLARE_EVENT_CLASS(cxl_afu_psl_ctrl_done,
TP_PROTO(struct cxl_afu *afu, u64 cmd, int rc),
TP_ARGS(afu, cmd, rc),
TP_STRUCT__entry(
__field(u8, card)
__field(u8, afu)
__field(u64, cmd)
__field(int, rc)
),
TP_fast_assign(
__entry->card = afu->adapter->adapter_num;
__entry->afu = afu->slice;
__entry->rc = rc;
__entry->cmd = cmd;
),
TP_printk("afu%i.%i cmd=%s rc=%i",
__entry->card,
__entry->afu,
__print_symbolic_u64(__entry->cmd, AFU_COMMANDS),
__entry->rc
)
);
DEFINE_EVENT(cxl_afu_psl_ctrl, cxl_afu_ctrl,
TP_PROTO(struct cxl_afu *afu, u64 cmd),
TP_ARGS(afu, cmd)
);
DEFINE_EVENT(cxl_afu_psl_ctrl_done, cxl_afu_ctrl_done,
TP_PROTO(struct cxl_afu *afu, u64 cmd, int rc),
TP_ARGS(afu, cmd, rc)
);
DEFINE_EVENT_PRINT(cxl_afu_psl_ctrl, cxl_psl_ctrl,
TP_PROTO(struct cxl_afu *afu, u64 cmd),
TP_ARGS(afu, cmd),
TP_printk("psl%i.%i cmd=%s",
__entry->card,
__entry->afu,
__print_symbolic_u64(__entry->cmd, PSL_COMMANDS)
)
);
DEFINE_EVENT_PRINT(cxl_afu_psl_ctrl_done, cxl_psl_ctrl_done,
TP_PROTO(struct cxl_afu *afu, u64 cmd, int rc),
TP_ARGS(afu, cmd, rc),
TP_printk("psl%i.%i cmd=%s rc=%i",
__entry->card,
__entry->afu,
__print_symbolic_u64(__entry->cmd, PSL_COMMANDS),
__entry->rc
)
);
DEFINE_EVENT(cxl_pe_class, cxl_slbia,
TP_PROTO(struct cxl_context *ctx),
TP_ARGS(ctx)
);
#endif /* _CXL_TRACE_H */
/* This part must be outside protection */
#undef TRACE_INCLUDE_PATH
#define TRACE_INCLUDE_PATH .
#define TRACE_INCLUDE_FILE trace
#include <trace/define_trace.h>