History

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.

Mika Westerberg committed 4 years ago

Commit cd149ef1 parent e7833624 files · +96 −39Browse files

Unified · Split

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

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t