/*
* 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.
*/
#include <linux/spinlock.h>
#include <linux/uaccess.h>
#include <linux/delay.h>
#include "cxl.h"
#include "hcalls.h"
#include "trace.h"
#define CXL_ERROR_DETECTED_EVENT 1
#define CXL_SLOT_RESET_EVENT 2
#define CXL_RESUME_EVENT 3
static void pci_error_handlers(struct cxl_afu *afu,
int bus_error_event,
pci_channel_state_t state)
{
struct pci_dev *afu_dev;
if (afu->phb == NULL)
return;
list_for_each_entry(afu_dev, &afu->phb->bus->devices, bus_list) {
if (!afu_dev->driver)
continue;
switch (bus_error_event) {
case CXL_ERROR_DETECTED_EVENT:
afu_dev->error_state = state;
if (afu_dev->driver->err_handler &&
afu_dev->driver->err_handler->error_detected)
afu_dev->driver->err_handler->error_detected(afu_dev, state);
break;
case CXL_SLOT_RESET_EVENT:
afu_dev->error_state = state;
if (afu_dev->driver->err_handler &&
afu_dev->driver->err_handler->slot_reset)
afu_dev->driver->err_handler->slot_reset(afu_dev);
break;
case CXL_RESUME_EVENT:
if (afu_dev->driver->err_handler &&
afu_dev->driver->err_handler->resume)
afu_dev->driver->err_handler->resume(afu_dev);
break;
}
}
}
static irqreturn_t guest_handle_psl_slice_error(struct cxl_context *ctx, u64 dsisr,
u64 errstat)
{
pr_devel("in %s\n", __func__);
dev_crit(&ctx->afu->dev, "PSL ERROR STATUS: 0x%.16llx\n", errstat);
return cxl_ops->ack_irq(ctx, 0, errstat);
}
static ssize_t guest_collect_vpd(struct cxl *adapter, struct cxl_afu *afu,
void *buf, size_t len)
{
unsigned int entries, mod;
unsigned long **vpd_buf = NULL;
struct sg_list *le;
int rc = 0, i, tocopy;
u64 out = 0;
if (buf == NULL)
return -EINVAL;
/* number of entries in the list */
entries = len / SG_BUFFER_SIZE;
mod = len % SG_BUFFER_SIZE;
if (mod)
entries++;
if (entries > SG_MAX_ENTRIES) {
entries = SG_MAX_ENTRIES;
len = SG_MAX_ENTRIES * SG_BUFFER_SIZE;
mod = 0;
}
vpd_buf = kcalloc(entries, sizeof(unsigned long *), GFP_KERNEL);
if (!vpd_buf)
return -ENOMEM;
le = (struct sg_list *)get_zeroed_page(GFP_KERNEL);
if (!le) {