blob: 039efb606e31921e73086d2f906dabaaa198adf4 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0
/*
* Enable/disable PCIe ECRC checking
*
* (C) Copyright 2009 Hewlett-Packard Development Company, L.P.
* Andrew Patterson <andrew.patterson@hp.com>
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/pci.h>
#include <linux/pci_regs.h>
#include <linux/errno.h>
#include "../../pci.h"
#define ECRC_POLICY_DEFAULT 0 /* ECRC set by BIOS */
#define ECRC_POLICY_OFF 1 /* ECRC off for performance */
#define ECRC_POLICY_ON 2 /* ECRC on for data integrity */
static int ecrc_policy = ECRC_POLICY_DEFAULT;
static const char *ecrc_policy_str[] = {
[ECRC_POLICY_DEFAULT] = "bios",
[ECRC_POLICY_OFF] = "off",
[ECRC_POLICY_ON] = "on"
};
/**
* enable_ercr_checking - enable PCIe ECRC checking for a device
* @dev: the PCI device
*
* Returns 0 on success, or negative on failure.
*/
static int enable_ecrc_checking(struct pci_dev *dev)
{
int pos;
u32 reg32;
if (!pci_is_pcie(dev))
return -ENODEV;
pos = dev->aer_cap;
if (!pos)
return -ENODEV;
pci_read_config_dword(dev, pos + PCI_ERR_CAP, &reg32);
if (reg32 & PCI_ERR_CAP_ECRC_GENC)
reg32 |= PCI_ERR_CAP_ECRC_GENE;
if (reg32 & PCI_ERR_CAP_ECRC_CHKC)
reg32 |= PCI_ERR_CAP_ECRC_CHKE;
pci_write_config_dword(dev, pos + PCI_ERR_CAP, reg32);
return 0;
}
/**
* disable_ercr_checking - disables PCIe ECRC checking for a device
* @dev: the PCI device
*
* Returns 0 on success, or negative on failure.
*/
static int disable_ecrc_checking(struct pci_dev *dev)
{
int pos;
u32 reg32;
if (!pci_is_pcie(dev))
return -ENODEV;
pos = dev->aer_cap;
if (!pos)
return -ENODEV;
pci_read_config_dword(dev, pos + PCI_ERR_CAP, &reg32);
reg32 &= ~(PCI_ERR_CAP_ECRC_GENE | PCI_ERR_CAP_ECRC_CHKE);
pci_write_config_dword(dev, pos + PCI_ERR_CAP, reg32);
return 0;
}
/**
* pcie_set_ecrc_checking - set/unset PCIe ECRC checking for a device based on global policy
* @dev: the PCI device
*/
void pcie_set_ecrc_checking(struct pci_dev *dev)
{
switch (ecrc_policy) {
case ECRC_POLICY_DEFAULT:
return;
case ECRC_POLICY_OFF:
disable_ecrc_checking(dev);
break;
case ECRC_POLICY_ON:
enable_ecrc_checking(dev);
break;
default:
return;
}
}
/**
* pcie_ecrc_get_policy - parse kernel command-line ecrc option
*/
void pcie_ecrc_get_policy(char *str)
{
int i;
for (i = 0; i < ARRAY_SIZE(ecrc_policy_str); i++)
if (!strncmp(str, ecrc_policy_str[i],
strlen(ecrc_policy_str[i])))
break;
if (i >= ARRAY_SIZE(ecrc_policy_str))
return;
ecrc_policy = i;
}