Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mtd: spi-nor: intel-spi: Disable write protection only if asked

Currently the driver tries to disable the BIOS write protection
automatically even if this is not what the user wants. For this reason
modify the driver so that by default it does not touch the write
protection. Only if specifically asked by the user (setting writeable=1
command line parameter) the driver tries to disable the BIOS write
protection.

Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Reviewed-by: Mauro Lima <mauro.lima@eclypsium.com>
Reviewed-by: Tudor Ambarus <tudor.ambarus@microchip.com>
Acked-by: Lee Jones <lee.jones@linaro.org>
Link: https://lore.kernel.org/r/20220209122706.42439-2-mika.westerberg@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Mika Westerberg and committed by
Mark Brown
cd149eff e783362e

+96 -39
+54 -5
drivers/mfd/lpc_ich.c
··· 63 63 #define SPIBASE_BYT 0x54 64 64 #define SPIBASE_BYT_SZ 512 65 65 #define SPIBASE_BYT_EN BIT(1) 66 + #define BYT_BCR 0xfc 67 + #define BYT_BCR_WPD BIT(0) 66 68 67 69 #define SPIBASE_LPT 0x3800 68 70 #define SPIBASE_LPT_SZ 512 ··· 1086 1084 return ret; 1087 1085 } 1088 1086 1087 + static bool lpc_ich_byt_set_writeable(void __iomem *base, void *data) 1088 + { 1089 + u32 val; 1090 + 1091 + val = readl(base + BYT_BCR); 1092 + if (!(val & BYT_BCR_WPD)) { 1093 + val |= BYT_BCR_WPD; 1094 + writel(val, base + BYT_BCR); 1095 + val = readl(base + BYT_BCR); 1096 + } 1097 + 1098 + return val & BYT_BCR_WPD; 1099 + } 1100 + 1101 + static bool lpc_ich_lpt_set_writeable(void __iomem *base, void *data) 1102 + { 1103 + struct pci_dev *pdev = data; 1104 + u32 bcr; 1105 + 1106 + pci_read_config_dword(pdev, BCR, &bcr); 1107 + if (!(bcr & BCR_WPD)) { 1108 + bcr |= BCR_WPD; 1109 + pci_write_config_dword(pdev, BCR, bcr); 1110 + pci_read_config_dword(pdev, BCR, &bcr); 1111 + } 1112 + 1113 + return bcr & BCR_WPD; 1114 + } 1115 + 1116 + static bool lpc_ich_bxt_set_writeable(void __iomem *base, void *data) 1117 + { 1118 + unsigned int spi = PCI_DEVFN(13, 2); 1119 + struct pci_bus *bus = data; 1120 + u32 bcr; 1121 + 1122 + pci_bus_read_config_dword(bus, spi, BCR, &bcr); 1123 + if (!(bcr & BCR_WPD)) { 1124 + bcr |= BCR_WPD; 1125 + pci_bus_write_config_dword(bus, spi, BCR, bcr); 1126 + pci_bus_read_config_dword(bus, spi, BCR, &bcr); 1127 + } 1128 + 1129 + return bcr & BCR_WPD; 1130 + } 1131 + 1089 1132 static int lpc_ich_init_spi(struct pci_dev *dev) 1090 1133 { 1091 1134 struct lpc_ich_priv *priv = pci_get_drvdata(dev); 1092 1135 struct resource *res = &intel_spi_res[0]; 1093 1136 struct intel_spi_boardinfo *info; 1094 - u32 spi_base, rcba, bcr; 1137 + u32 spi_base, rcba; 1095 1138 1096 1139 info = devm_kzalloc(&dev->dev, sizeof(*info), GFP_KERNEL); 1097 1140 if (!info) ··· 1150 1103 if (spi_base & SPIBASE_BYT_EN) { 1151 1104 res->start = spi_base & ~(SPIBASE_BYT_SZ - 1); 1152 1105 res->end = res->start + SPIBASE_BYT_SZ - 1; 1106 + 1107 + info->set_writeable = lpc_ich_byt_set_writeable; 1153 1108 } 1154 1109 break; 1155 1110 ··· 1162 1113 res->start = spi_base + SPIBASE_LPT; 1163 1114 res->end = res->start + SPIBASE_LPT_SZ - 1; 1164 1115 1165 - pci_read_config_dword(dev, BCR, &bcr); 1166 - info->writeable = !!(bcr & BCR_WPD); 1116 + info->set_writeable = lpc_ich_lpt_set_writeable; 1117 + info->data = dev; 1167 1118 } 1168 1119 break; 1169 1120 ··· 1184 1135 res->start = spi_base & 0xfffffff0; 1185 1136 res->end = res->start + SPIBASE_APL_SZ - 1; 1186 1137 1187 - pci_bus_read_config_dword(bus, spi, BCR, &bcr); 1188 - info->writeable = !!(bcr & BCR_WPD); 1138 + info->set_writeable = lpc_ich_bxt_set_writeable; 1139 + info->data = bus; 1189 1140 } 1190 1141 1191 1142 pci_bus_write_config_byte(bus, p2sb, 0xe1, 0x1);
+19 -10
drivers/mtd/spi-nor/controllers/intel-spi-pci.c
··· 16 16 #define BCR 0xdc 17 17 #define BCR_WPD BIT(0) 18 18 19 + static bool intel_spi_pci_set_writeable(void __iomem *base, void *data) 20 + { 21 + struct pci_dev *pdev = data; 22 + u32 bcr; 23 + 24 + /* Try to make the chip read/write */ 25 + pci_read_config_dword(pdev, BCR, &bcr); 26 + if (!(bcr & BCR_WPD)) { 27 + bcr |= BCR_WPD; 28 + pci_write_config_dword(pdev, BCR, bcr); 29 + pci_read_config_dword(pdev, BCR, &bcr); 30 + } 31 + 32 + return bcr & BCR_WPD; 33 + } 34 + 19 35 static const struct intel_spi_boardinfo bxt_info = { 20 36 .type = INTEL_SPI_BXT, 37 + .set_writeable = intel_spi_pci_set_writeable, 21 38 }; 22 39 23 40 static const struct intel_spi_boardinfo cnl_info = { 24 41 .type = INTEL_SPI_CNL, 42 + .set_writeable = intel_spi_pci_set_writeable, 25 43 }; 26 44 27 45 static int intel_spi_pci_probe(struct pci_dev *pdev, ··· 47 29 { 48 30 struct intel_spi_boardinfo *info; 49 31 struct intel_spi *ispi; 50 - u32 bcr; 51 32 int ret; 52 33 53 34 ret = pcim_enable_device(pdev); ··· 58 41 if (!info) 59 42 return -ENOMEM; 60 43 61 - /* Try to make the chip read/write */ 62 - pci_read_config_dword(pdev, BCR, &bcr); 63 - if (!(bcr & BCR_WPD)) { 64 - bcr |= BCR_WPD; 65 - pci_write_config_dword(pdev, BCR, bcr); 66 - pci_read_config_dword(pdev, BCR, &bcr); 67 - } 68 - info->writeable = !!(bcr & BCR_WPD); 69 - 44 + info->data = pdev; 70 45 ispi = intel_spi_probe(&pdev->dev, &pdev->resource[0], info); 71 46 if (IS_ERR(ispi)) 72 47 return PTR_ERR(ispi);
+19 -22
drivers/mtd/spi-nor/controllers/intel-spi.c
··· 131 131 * @sregs: Start of software sequencer registers 132 132 * @nregions: Maximum number of regions 133 133 * @pr_num: Maximum number of protected range registers 134 - * @writeable: Is the chip writeable 135 134 * @locked: Is SPI setting locked 136 135 * @swseq_reg: Use SW sequencer in register reads/writes 137 136 * @swseq_erase: Use SW sequencer in erase operation ··· 148 149 void __iomem *sregs; 149 150 size_t nregions; 150 151 size_t pr_num; 151 - bool writeable; 152 152 bool locked; 153 153 bool swseq_reg; 154 154 bool swseq_erase; ··· 302 304 INTEL_SPI_TIMEOUT * 1000); 303 305 } 304 306 307 + static bool intel_spi_set_writeable(struct intel_spi *ispi) 308 + { 309 + if (!ispi->info->set_writeable) 310 + return false; 311 + 312 + return ispi->info->set_writeable(ispi->base, ispi->info->data); 313 + } 314 + 305 315 static int intel_spi_init(struct intel_spi *ispi) 306 316 { 307 317 u32 opmenu0, opmenu1, lvscc, uvscc, val; ··· 322 316 ispi->nregions = BYT_FREG_NUM; 323 317 ispi->pr_num = BYT_PR_NUM; 324 318 ispi->swseq_reg = true; 325 - 326 - if (writeable) { 327 - /* Disable write protection */ 328 - val = readl(ispi->base + BYT_BCR); 329 - if (!(val & BYT_BCR_WPD)) { 330 - val |= BYT_BCR_WPD; 331 - writel(val, ispi->base + BYT_BCR); 332 - val = readl(ispi->base + BYT_BCR); 333 - } 334 - 335 - ispi->writeable = !!(val & BYT_BCR_WPD); 336 - } 337 - 338 319 break; 339 320 340 321 case INTEL_SPI_LPT: ··· 349 356 350 357 default: 351 358 return -EINVAL; 359 + } 360 + 361 + /* Try to disable write protection if user asked to do so */ 362 + if (writeable && !intel_spi_set_writeable(ispi)) { 363 + dev_warn(ispi->dev, "can't disable chip write protection\n"); 364 + writeable = false; 352 365 } 353 366 354 367 /* Disable #SMI generation from HW sequencer */ ··· 883 884 /* 884 885 * If any of the regions have protection bits set, make the 885 886 * whole partition read-only to be on the safe side. 887 + * 888 + * Also if the user did not ask the chip to be writeable 889 + * mask the bit too. 886 890 */ 887 - if (intel_spi_is_protected(ispi, base, limit)) 888 - ispi->writeable = false; 891 + if (!writeable || intel_spi_is_protected(ispi, base, limit)) 892 + part->mask_flags |= MTD_WRITEABLE; 889 893 890 894 end = (limit << 12) + 4096; 891 895 if (end > part->size) ··· 929 927 930 928 ispi->dev = dev; 931 929 ispi->info = info; 932 - ispi->writeable = info->writeable; 933 930 934 931 ret = intel_spi_init(ispi); 935 932 if (ret) ··· 945 944 } 946 945 947 946 intel_spi_fill_partition(ispi, &part); 948 - 949 - /* Prevent writes if not explicitly enabled */ 950 - if (!ispi->writeable || !writeable) 951 - ispi->nor.mtd.flags &= ~MTD_WRITEABLE; 952 947 953 948 ret = mtd_device_register(&ispi->nor.mtd, &part, 1); 954 949 if (ret)
+4 -2
include/linux/platform_data/x86/intel-spi.h
··· 19 19 /** 20 20 * struct intel_spi_boardinfo - Board specific data for Intel SPI driver 21 21 * @type: Type which this controller is compatible with 22 - * @writeable: The chip is writeable 22 + * @set_writeable: Try to make the chip writeable (optional) 23 + * @data: Data to be passed to @set_writeable can be %NULL 23 24 */ 24 25 struct intel_spi_boardinfo { 25 26 enum intel_spi_type type; 26 - bool writeable; 27 + bool (*set_writeable)(void __iomem *base, void *data); 28 + void *data; 27 29 }; 28 30 29 31 #endif /* INTEL_SPI_PDATA_H */