Exemplo n.º 1
0
/* Check for an eeh failure at the given token address.
 * The given value has been read and it should be 1's (0xff, 0xffff or
 * 0xffffffff).
 *
 * Probe to determine if an error actually occurred.  If not return val.
 * Otherwise panic.
 */
unsigned long eeh_check_failure(void *token, unsigned long val)
{
	unsigned long addr;
	struct pci_dev *dev;
	struct device_node *dn;
	unsigned long ret, rets[2];

	/* IO BAR access could get us here...or if we manually force EEH
	 * operation on even if the hardware won't support it.
	 */
	if (!eeh_implemented || ibm_read_slot_reset_state == RTAS_UNKNOWN_SERVICE)
		return val;

	/* Finding the phys addr + pci device is quite expensive.
	 * However, the RTAS call is MUCH slower.... :(
	 */
	addr = eeh_token_to_phys((unsigned long)token);
	dev = pci_find_dev_by_addr(addr);
	if (!dev) {
		printk("EEH: no pci dev found for addr=0x%lx\n", addr);
		return val;
	}
	dn = pci_device_to_OF_node(dev);
	if (!dn) {
		printk("EEH: no pci dn found for addr=0x%lx\n", addr);
		return val;
	}

	/* Access to IO BARs might get this far and still not want checking. */
	if (!(dn->eeh_mode & EEH_MODE_SUPPORTED) || dn->eeh_mode & EEH_MODE_NOCHECK)
		return val;


	/* 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.
	 */
	if (dn->eeh_config_addr) {
		ret = rtas_call(ibm_read_slot_reset_state, 3, 3, rets,
				dn->eeh_config_addr, BUID_HI(dn->phb->buid), BUID_LO(dn->phb->buid));
		if (ret == 0 && rets[1] == 1 && rets[0] >= 2) {
			/*
			 * XXX We should create a separate sysctl for this.
			 *
			 * Since the panic_on_oops sysctl is used to halt
			 * the system in light of potential corruption, we
			 * can use it here.
			 */
			if (panic_on_oops)
				panic("EEH: MMIO failure (%ld) on device:\n%s\n", rets[0], pci_name(dev));
			else
				printk("EEH: MMIO failure (%ld) on device:\n%s\n", rets[0], pci_name(dev));
		}
	}
	eeh_false_positives++;
	return val;	/* good case */

}
Exemplo n.º 2
0
/**
 * eeh_check_failure - check if all 1's data is due to EEH slot freeze
 * @token i/o token, should be address in the form 0xA....
 * @val value, should be all 1's (XXX why do we need this arg??)
 *
 * Check for an EEH failure at the given token address.  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 event.  This routine
 * will query firmware for the EEH status.
 *
 * Note this routine is safe to call in an interrupt context.
 */
unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned long val)
{
	unsigned long addr;
	struct pci_dev *dev;
	struct device_node *dn;

	/* Finding the phys addr + pci device; this is pretty quick. */
	addr = eeh_token_to_phys((unsigned long __force) token);
	dev = pci_get_device_by_addr(addr);
	if (!dev) {
		no_device++;
		return val;
	}

	dn = pci_device_to_OF_node(dev);
	eeh_dn_check_failure (dn, dev);

	pci_dev_put(dev);
	return val;
}
Exemplo n.º 3
0
/* Check for an eeh failure at the given token address.
 * The given value has been read and it should be 1's (0xff, 0xffff or
 * 0xffffffff).
 *
 * Probe to determine if an error actually occurred.  If not return val.
 * Otherwise panic.
 */
unsigned long eeh_check_failure(void *token, unsigned long val)
{
	unsigned long addr;
	struct pci_dev *dev;
	struct device_node *dn;
	unsigned long ret, rets[2];

	/* IO BAR access could get us here...or if we manually force EEH
	 * operation on even if the hardware won't support it.
	 */
	if (!eeh_implemented || ibm_read_slot_reset_state == RTAS_UNKNOWN_SERVICE)
		return val;

	/* Finding the phys addr + pci device is quite expensive.
	 * However, the RTAS call is MUCH slower.... :(
	 */
	addr = eeh_token_to_phys((unsigned long)token);
	dev = pci_find_dev_by_addr(addr);
	if (!dev) {
		printk("EEH: no pci dev found for addr=0x%lx\n", addr);
		return val;
	}
	dn = pci_device_to_OF_node(dev);
	if (!dn) {
		printk("EEH: no pci dn found for addr=0x%lx\n", addr);
		return val;
	}

	/* Access to IO BARs might get this far and still not want checking. */
	if (!(dn->eeh_mode & EEH_MODE_SUPPORTED) || dn->eeh_mode & EEH_MODE_NOCHECK)
		return val;


	/* 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.
	 */
	if (dn->eeh_config_addr) {
		ret = rtas_call(ibm_read_slot_reset_state, 3, 3, rets,
				dn->eeh_config_addr, BUID_HI(dn->phb->buid), BUID_LO(dn->phb->buid));
		if (ret == 0 && rets[1] == 1 && rets[0] >= 2) {
			unsigned char   slot_err_buf[RTAS_ERROR_LOG_MAX];
			unsigned long   slot_err_ret;

			memset(slot_err_buf, 0, RTAS_ERROR_LOG_MAX);
			slot_err_ret = rtas_call(rtas_token("ibm,slot-error-detail"),
						 8, 1, dn->eeh_config_addr,
						 BUID_HI(dn->phb->buid), BUID_LO(dn->phb->buid),
						 NULL, 0, __pa(slot_err_buf), RTAS_ERROR_LOG_MAX,
						 2 /* Permanent Error */);
			if (slot_err_ret == 0)
				log_error(slot_err_buf, ERR_TYPE_RTAS_LOG, 1 /* Fatal */);

			panic("EEH:  MMIO failure (%ld) on device:\n  %s %s\n",
			      rets[0], dev->slot_name, dev->name);
		}
	}
	eeh_false_positives++;
	return val;	/* good case */

}