diff options
author | Fabio Estevam <fabio.estevam@freescale.com> | 2015-01-13 17:14:15 -0500 |
---|---|---|
committer | Brian Norris <computersforpeace@gmail.com> | 2015-01-20 15:37:57 -0500 |
commit | cfe4af3aac3bd63e9caf548157805ca46ad7b073 (patch) | |
tree | 8432c64db6f009425799a7e09c22b2321a1b12c9 /drivers/mtd | |
parent | fcc87a95195236b0935183361a72e4a98bf577d8 (diff) |
mtd: fsl-quadspi: Fix module unbound
When removing the fsl-quadspi module and running 'cat /proc/mtd' afterwards,
we see garbage data like:
$ rmmod fsl-quadspi
$ cat /proc/mtd
dev: size erasesize name
mtd0: 00000000 00000000 "(null)"
mtd0: 00000000 00000000 "(null)"
mtd0: 00000000 00000000 "(null)"
...
mtd0: a22296c6c756e28 00000000 "(null)"
mtd0: a22296c6c756e28 3064746d "(null)"
If we continue doing multiple module load/unload operations, then it will also
lead to a kernel crash.
The reason for this is due to the wrong mtd index used in
mtd_device_unregister() in the remove function.
We need to keep the mtd unregister index aligned with the one used in the probe
function, which means we need to take into account the 'has_second_chip'
property. By doing so we can guarantee that the mtd index is the same in the
registration and unregistration functions.
With this patch applied we can load/unload the fsl-quadspi driver several times
and it will result in no crash.
Signed-off-by: Fabio Estevam <fabio.estevam@freescale.com>
Acked-by: Huang Shijie <shijie.huang@intel.com>
Tested-by: Frank Li <Frank.Li@freescale.com>
Acked-by: Allen Xu <han.xu@freescale.com>
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/spi-nor/fsl-quadspi.c | 19 |
1 files changed, 13 insertions, 6 deletions
diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c index 9d6080079a45..a46bea33580f 100644 --- a/drivers/mtd/spi-nor/fsl-quadspi.c +++ b/drivers/mtd/spi-nor/fsl-quadspi.c | |||
@@ -227,6 +227,7 @@ struct fsl_qspi { | |||
227 | u32 nor_num; | 227 | u32 nor_num; |
228 | u32 clk_rate; | 228 | u32 clk_rate; |
229 | unsigned int chip_base_addr; /* We may support two chips. */ | 229 | unsigned int chip_base_addr; /* We may support two chips. */ |
230 | bool has_second_chip; | ||
230 | }; | 231 | }; |
231 | 232 | ||
232 | static inline int is_vybrid_qspi(struct fsl_qspi *q) | 233 | static inline int is_vybrid_qspi(struct fsl_qspi *q) |
@@ -783,7 +784,6 @@ static int fsl_qspi_probe(struct platform_device *pdev) | |||
783 | struct spi_nor *nor; | 784 | struct spi_nor *nor; |
784 | struct mtd_info *mtd; | 785 | struct mtd_info *mtd; |
785 | int ret, i = 0; | 786 | int ret, i = 0; |
786 | bool has_second_chip = false; | ||
787 | const struct of_device_id *of_id = | 787 | const struct of_device_id *of_id = |
788 | of_match_device(fsl_qspi_dt_ids, &pdev->dev); | 788 | of_match_device(fsl_qspi_dt_ids, &pdev->dev); |
789 | 789 | ||
@@ -860,14 +860,14 @@ static int fsl_qspi_probe(struct platform_device *pdev) | |||
860 | goto irq_failed; | 860 | goto irq_failed; |
861 | 861 | ||
862 | if (of_get_property(np, "fsl,qspi-has-second-chip", NULL)) | 862 | if (of_get_property(np, "fsl,qspi-has-second-chip", NULL)) |
863 | has_second_chip = true; | 863 | q->has_second_chip = true; |
864 | 864 | ||
865 | /* iterate the subnodes. */ | 865 | /* iterate the subnodes. */ |
866 | for_each_available_child_of_node(dev->of_node, np) { | 866 | for_each_available_child_of_node(dev->of_node, np) { |
867 | char modalias[40]; | 867 | char modalias[40]; |
868 | 868 | ||
869 | /* skip the holes */ | 869 | /* skip the holes */ |
870 | if (!has_second_chip) | 870 | if (!q->has_second_chip) |
871 | i *= 2; | 871 | i *= 2; |
872 | 872 | ||
873 | nor = &q->nor[i]; | 873 | nor = &q->nor[i]; |
@@ -943,9 +943,12 @@ static int fsl_qspi_probe(struct platform_device *pdev) | |||
943 | return 0; | 943 | return 0; |
944 | 944 | ||
945 | last_init_failed: | 945 | last_init_failed: |
946 | for (i = 0; i < q->nor_num; i++) | 946 | for (i = 0; i < q->nor_num; i++) { |
947 | /* skip the holes */ | ||
948 | if (!q->has_second_chip) | ||
949 | i *= 2; | ||
947 | mtd_device_unregister(&q->mtd[i]); | 950 | mtd_device_unregister(&q->mtd[i]); |
948 | 951 | } | |
949 | irq_failed: | 952 | irq_failed: |
950 | clk_disable_unprepare(q->clk); | 953 | clk_disable_unprepare(q->clk); |
951 | clk_failed: | 954 | clk_failed: |
@@ -960,8 +963,12 @@ static int fsl_qspi_remove(struct platform_device *pdev) | |||
960 | struct fsl_qspi *q = platform_get_drvdata(pdev); | 963 | struct fsl_qspi *q = platform_get_drvdata(pdev); |
961 | int i; | 964 | int i; |
962 | 965 | ||
963 | for (i = 0; i < q->nor_num; i++) | 966 | for (i = 0; i < q->nor_num; i++) { |
967 | /* skip the holes */ | ||
968 | if (!q->has_second_chip) | ||
969 | i *= 2; | ||
964 | mtd_device_unregister(&q->mtd[i]); | 970 | mtd_device_unregister(&q->mtd[i]); |
971 | } | ||
965 | 972 | ||
966 | /* disable the hardware */ | 973 | /* disable the hardware */ |
967 | writel(QUADSPI_MCR_MDIS_MASK, q->iobase + QUADSPI_MCR); | 974 | writel(QUADSPI_MCR_MDIS_MASK, q->iobase + QUADSPI_MCR); |