Ejemplo n.º 1
0
void eeh_sysfs_add_device(struct pci_dev *pdev)
{
	struct eeh_dev *edev = pci_dev_to_eeh_dev(pdev);
	int rc=0;

	if (!eeh_enabled())
		return;

	if (edev && (edev->mode & EEH_DEV_SYSFS))
		return;

	rc += device_create_file(&pdev->dev, &dev_attr_eeh_mode);
	rc += device_create_file(&pdev->dev, &dev_attr_eeh_pe_config_addr);
	rc += device_create_file(&pdev->dev, &dev_attr_eeh_pe_state);

	if (rc)
		pr_warn("EEH: Unable to create sysfs entries\n");
	else if (edev)
		edev->mode |= EEH_DEV_SYSFS;
}
Ejemplo n.º 2
0
long vfio_spapr_iommu_eeh_ioctl(struct iommu_group *group,
				unsigned int cmd, unsigned long arg)
{
	struct eeh_pe *pe;
	struct vfio_eeh_pe_op op;
	unsigned long minsz;
	long ret = -EINVAL;

	switch (cmd) {
	case VFIO_CHECK_EXTENSION:
		if (arg == VFIO_EEH)
			ret = eeh_enabled() ? 1 : 0;
		else
			ret = 0;
		break;
	case VFIO_EEH_PE_OP:
		pe = eeh_iommu_group_to_pe(group);
		if (!pe)
			return -ENODEV;

		minsz = offsetofend(struct vfio_eeh_pe_op, op);
		if (copy_from_user(&op, (void __user *)arg, minsz))
			return -EFAULT;
		if (op.argsz < minsz || op.flags)
			return -EINVAL;

		switch (op.op) {
		case VFIO_EEH_PE_DISABLE:
			ret = eeh_pe_set_option(pe, EEH_OPT_DISABLE);
			break;
		case VFIO_EEH_PE_ENABLE:
			ret = eeh_pe_set_option(pe, EEH_OPT_ENABLE);
			break;
		case VFIO_EEH_PE_UNFREEZE_IO:
			ret = eeh_pe_set_option(pe, EEH_OPT_THAW_MMIO);
			break;
		case VFIO_EEH_PE_UNFREEZE_DMA:
			ret = eeh_pe_set_option(pe, EEH_OPT_THAW_DMA);
			break;
		case VFIO_EEH_PE_GET_STATE:
			ret = eeh_pe_get_state(pe);
			break;
		case VFIO_EEH_PE_RESET_DEACTIVATE:
			ret = eeh_pe_reset(pe, EEH_RESET_DEACTIVATE, true);
			break;
		case VFIO_EEH_PE_RESET_HOT:
			ret = eeh_pe_reset(pe, EEH_RESET_HOT, true);
			break;
		case VFIO_EEH_PE_RESET_FUNDAMENTAL:
			ret = eeh_pe_reset(pe, EEH_RESET_FUNDAMENTAL, true);
			break;
		case VFIO_EEH_PE_CONFIGURE:
			ret = eeh_pe_configure(pe);
			break;
		case VFIO_EEH_PE_INJECT_ERR:
			minsz = offsetofend(struct vfio_eeh_pe_op, err.mask);
			if (op.argsz < minsz)
				return -EINVAL;
			if (copy_from_user(&op, (void __user *)arg, minsz))
				return -EFAULT;

			ret = eeh_pe_inject_err(pe, op.err.type, op.err.func,
						op.err.addr, op.err.mask);
			break;
		default:
			ret = -EINVAL;
		}
	}

	return ret;
}
Ejemplo n.º 3
0
/**
 * eeh_dev_check_failure - Check if all 1's data is due to EEH slot freeze
 * @edev: eeh device
 *
 * Check for an EEH failure for the given device node.  Call this
 * routine if the result of a read was all 0xff's and you want to
 * find out if this is due to an EEH slot freeze.  This routine
 * will query firmware for the EEH status.
 *
 * Returns 0 if there has not been an EEH error; otherwise returns
 * a non-zero value and queues up a slot isolation event notification.
 *
 * It is safe to call this routine in an interrupt context.
 */
int eeh_dev_check_failure(struct eeh_dev *edev)
{
	int ret;
	int active_flags = (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE);
	unsigned long flags;
	struct pci_dn *pdn;
	struct pci_dev *dev;
	struct eeh_pe *pe, *parent_pe, *phb_pe;
	int rc = 0;
	const char *location = NULL;

	eeh_stats.total_mmio_ffs++;

	if (!eeh_enabled())
		return 0;

	if (!edev) {
		eeh_stats.no_dn++;
		return 0;
	}
	dev = eeh_dev_to_pci_dev(edev);
	pe = eeh_dev_to_pe(edev);

	/* Access to IO BARs might get this far and still not want checking. */
	if (!pe) {
		eeh_stats.ignored_check++;
		pr_debug("EEH: Ignored check for %s\n",
			eeh_pci_name(dev));
		return 0;
	}

	if (!pe->addr && !pe->config_addr) {
		eeh_stats.no_cfg_addr++;
		return 0;
	}

	/*
	 * On PowerNV platform, we might already have fenced PHB
	 * there and we need take care of that firstly.
	 */
	ret = eeh_phb_check_failure(pe);
	if (ret > 0)
		return ret;

	/*
	 * If the PE isn't owned by us, we shouldn't check the
	 * state. Instead, let the owner handle it if the PE has
	 * been frozen.
	 */
	if (eeh_pe_passed(pe))
		return 0;

	/* If we already have a pending isolation event for this
	 * slot, we know it's bad already, we don't need to check.
	 * Do this checking under a lock; as multiple PCI devices
	 * in one slot might report errors simultaneously, and we
	 * only want one error recovery routine running.
	 */
	eeh_serialize_lock(&flags);
	rc = 1;
	if (pe->state & EEH_PE_ISOLATED) {
		pe->check_count++;
		if (pe->check_count % EEH_MAX_FAILS == 0) {
			pdn = eeh_dev_to_pdn(edev);
			if (pdn->node)
				location = of_get_property(pdn->node, "ibm,loc-code", NULL);
			printk(KERN_ERR "EEH: %d reads ignored for recovering device at "
				"location=%s driver=%s pci addr=%s\n",
				pe->check_count,
				location ? location : "unknown",
				eeh_driver_name(dev), eeh_pci_name(dev));
			printk(KERN_ERR "EEH: Might be infinite loop in %s driver\n",
				eeh_driver_name(dev));
			dump_stack();
		}
		goto dn_unlock;
	}

	/*
	 * Now test for an EEH failure.  This is VERY expensive.
	 * Note that the eeh_config_addr may be a parent device
	 * in the case of a device behind a bridge, or it may be
	 * function zero of a multi-function device.
	 * In any case they must share a common PHB.
	 */
	ret = eeh_ops->get_state(pe, NULL);

	/* Note that config-io to empty slots may fail;
	 * they are empty when they don't have children.
	 * We will punt with the following conditions: Failure to get
	 * PE's state, EEH not support and Permanently unavailable
	 * state, PE is in good state.
	 */
	if ((ret < 0) ||
	    (ret == EEH_STATE_NOT_SUPPORT) ||
	    ((ret & active_flags) == active_flags)) {
		eeh_stats.false_positives++;
		pe->false_positives++;
		rc = 0;
		goto dn_unlock;
	}

	/*
	 * It should be corner case that the parent PE has been
	 * put into frozen state as well. We should take care
	 * that at first.
	 */
	parent