1/* 2 * Enables/disables PCIe ECRC checking. 3 * 4 * (C) Copyright 2009 Hewlett-Packard Development Company, L.P. 5 * Andrew Patterson <andrew.patterson@hp.com> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; version 2 of the License. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 19 * 02111-1307, USA. 20 * 21 */ 22 23#include <linux/kernel.h> 24#include <linux/module.h> 25#include <linux/moduleparam.h> 26#include <linux/pci.h> 27#include <linux/pci_regs.h> 28#include <linux/errno.h> 29#include "../../pci.h" 30 31#define ECRC_POLICY_DEFAULT 0 /* ECRC set by BIOS */ 32#define ECRC_POLICY_OFF 1 /* ECRC off for performance */ 33#define ECRC_POLICY_ON 2 /* ECRC on for data integrity */ 34 35static int ecrc_policy = ECRC_POLICY_DEFAULT; 36 37static const char *ecrc_policy_str[] = { 38 [ECRC_POLICY_DEFAULT] = "bios", 39 [ECRC_POLICY_OFF] = "off", 40 [ECRC_POLICY_ON] = "on" 41}; 42 43/** 44 * enable_ercr_checking - enable PCIe ECRC checking for a device 45 * @dev: the PCI device 46 * 47 * Returns 0 on success, or negative on failure. 48 */ 49static int enable_ecrc_checking(struct pci_dev *dev) 50{ 51 int pos; 52 u32 reg32; 53 54 if (!pci_is_pcie(dev)) 55 return -ENODEV; 56 57 pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); 58 if (!pos) 59 return -ENODEV; 60 61 pci_read_config_dword(dev, pos + PCI_ERR_CAP, ®32); 62 if (reg32 & PCI_ERR_CAP_ECRC_GENC) 63 reg32 |= PCI_ERR_CAP_ECRC_GENE; 64 if (reg32 & PCI_ERR_CAP_ECRC_CHKC) 65 reg32 |= PCI_ERR_CAP_ECRC_CHKE; 66 pci_write_config_dword(dev, pos + PCI_ERR_CAP, reg32); 67 68 return 0; 69} 70 71/** 72 * disable_ercr_checking - disables PCIe ECRC checking for a device 73 * @dev: the PCI device 74 * 75 * Returns 0 on success, or negative on failure. 76 */ 77static int disable_ecrc_checking(struct pci_dev *dev) 78{ 79 int pos; 80 u32 reg32; 81 82 if (!pci_is_pcie(dev)) 83 return -ENODEV; 84 85 pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); 86 if (!pos) 87 return -ENODEV; 88 89 pci_read_config_dword(dev, pos + PCI_ERR_CAP, ®32); 90 reg32 &= ~(PCI_ERR_CAP_ECRC_GENE | PCI_ERR_CAP_ECRC_CHKE); 91 pci_write_config_dword(dev, pos + PCI_ERR_CAP, reg32); 92 93 return 0; 94} 95 96/** 97 * pcie_set_ecrc_checking - set/unset PCIe ECRC checking for a device based on global policy 98 * @dev: the PCI device 99 */ 100void pcie_set_ecrc_checking(struct pci_dev *dev) 101{ 102 switch (ecrc_policy) { 103 case ECRC_POLICY_DEFAULT: 104 return; 105 case ECRC_POLICY_OFF: 106 disable_ecrc_checking(dev); 107 break; 108 case ECRC_POLICY_ON: 109 enable_ecrc_checking(dev); 110 break; 111 default: 112 return; 113 } 114} 115 116/** 117 * pcie_ecrc_get_policy - parse kernel command-line ecrc option 118 */ 119void pcie_ecrc_get_policy(char *str) 120{ 121 int i; 122 123 for (i = 0; i < ARRAY_SIZE(ecrc_policy_str); i++) 124 if (!strncmp(str, ecrc_policy_str[i], 125 strlen(ecrc_policy_str[i]))) 126 break; 127 if (i >= ARRAY_SIZE(ecrc_policy_str)) 128 return; 129 130 ecrc_policy = i; 131} 132