Skip to content

Commit 718004a

Browse files
Uwe Kleine-Königmiquelraynal
authored andcommitted
mtd: rawnand: pasemi: Don't use static data to track per-device state
Up to now the pasemi nand driver only supported a single device instance. However the check for that was racy because two parallel calls of pasemi_nand_probe() could pass the check if (pasemi_nand_mtd) return -ENODEV; before any of them assigns a non-NULL value to it. So rework the driver to make use of per-device driver data. As an intended side effect the driver can bind more than one device and also gets rid of the check if (!pasemi_nand_mtd) return 0; in the remove callback that could only ever trigger after the above race happened. Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> Link: https://lore.kernel.org/linux-mtd/20230102124051.1508424-1-u.kleine-koenig@pengutronix.de
1 parent 34569d8 commit 718004a

1 file changed

Lines changed: 35 additions & 28 deletions

File tree

drivers/mtd/nand/raw/pasemi_nand.c

Lines changed: 35 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,12 @@
2626
#define CLE_PIN_CTL 15
2727
#define ALE_PIN_CTL 14
2828

29-
static unsigned int lpcctl;
30-
static struct mtd_info *pasemi_nand_mtd;
31-
static struct nand_controller controller;
29+
struct pasemi_ddata {
30+
struct nand_chip chip;
31+
unsigned int lpcctl;
32+
struct nand_controller controller;
33+
};
34+
3235
static const char driver_name[] = "pasemi-nand";
3336

3437
static void pasemi_read_buf(struct nand_chip *chip, u_char *buf, int len)
@@ -55,6 +58,8 @@ static void pasemi_write_buf(struct nand_chip *chip, const u_char *buf,
5558
static void pasemi_hwcontrol(struct nand_chip *chip, int cmd,
5659
unsigned int ctrl)
5760
{
61+
struct pasemi_ddata *ddata = container_of(chip, struct pasemi_ddata, chip);
62+
5863
if (cmd == NAND_CMD_NONE)
5964
return;
6065

@@ -65,12 +70,14 @@ static void pasemi_hwcontrol(struct nand_chip *chip, int cmd,
6570

6671
/* Push out posted writes */
6772
eieio();
68-
inl(lpcctl);
73+
inl(ddata->lpcctl);
6974
}
7075

7176
static int pasemi_device_ready(struct nand_chip *chip)
7277
{
73-
return !!(inl(lpcctl) & LBICTRL_LPCCTL_NR);
78+
struct pasemi_ddata *ddata = container_of(chip, struct pasemi_ddata, chip);
79+
80+
return !!(inl(ddata->lpcctl) & LBICTRL_LPCCTL_NR);
7481
}
7582

7683
static int pasemi_attach_chip(struct nand_chip *chip)
@@ -93,29 +100,31 @@ static int pasemi_nand_probe(struct platform_device *ofdev)
93100
struct device_node *np = dev->of_node;
94101
struct resource res;
95102
struct nand_chip *chip;
103+
struct nand_controller *controller;
96104
int err = 0;
105+
struct pasemi_ddata *ddata;
106+
struct mtd_info *pasemi_nand_mtd;
97107

98108
err = of_address_to_resource(np, 0, &res);
99109

100110
if (err)
101111
return -EINVAL;
102112

103-
/* We only support one device at the moment */
104-
if (pasemi_nand_mtd)
105-
return -ENODEV;
106-
107113
dev_dbg(dev, "pasemi_nand at %pR\n", &res);
108114

109115
/* Allocate memory for MTD device structure and private data */
110-
chip = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
111-
if (!chip) {
116+
ddata = kzalloc(sizeof(*ddata), GFP_KERNEL);
117+
if (!ddata) {
112118
err = -ENOMEM;
113119
goto out;
114120
}
121+
platform_set_drvdata(ofdev, ddata);
122+
chip = &ddata->chip;
123+
controller = &ddata->controller;
115124

116-
controller.ops = &pasemi_ops;
117-
nand_controller_init(&controller);
118-
chip->controller = &controller;
125+
controller->ops = &pasemi_ops;
126+
nand_controller_init(controller);
127+
chip->controller = controller;
119128

120129
pasemi_nand_mtd = nand_to_mtd(chip);
121130

@@ -136,10 +145,10 @@ static int pasemi_nand_probe(struct platform_device *ofdev)
136145
goto out_ior;
137146
}
138147

139-
lpcctl = pci_resource_start(pdev, 0);
148+
ddata->lpcctl = pci_resource_start(pdev, 0);
140149
pci_dev_put(pdev);
141150

142-
if (!request_region(lpcctl, 4, driver_name)) {
151+
if (!request_region(ddata->lpcctl, 4, driver_name)) {
143152
err = -EBUSY;
144153
goto out_ior;
145154
}
@@ -172,45 +181,43 @@ static int pasemi_nand_probe(struct platform_device *ofdev)
172181
}
173182

174183
dev_info(dev, "PA Semi NAND flash at %pR, control at I/O %x\n", &res,
175-
lpcctl);
184+
ddata->lpcctl);
176185

177186
return 0;
178187

179188
out_cleanup_nand:
180189
nand_cleanup(chip);
181190
out_lpc:
182-
release_region(lpcctl, 4);
191+
release_region(ddata->lpcctl, 4);
183192
out_ior:
184193
iounmap(chip->legacy.IO_ADDR_R);
185194
out_mtd:
186-
kfree(chip);
195+
kfree(ddata);
187196
out:
188197
return err;
189198
}
190199

191200
static int pasemi_nand_remove(struct platform_device *ofdev)
192201
{
193-
struct nand_chip *chip;
202+
struct pasemi_ddata *ddata = platform_get_drvdata(ofdev);
203+
struct mtd_info *pasemi_nand_mtd;
194204
int ret;
205+
struct nand_chip *chip;
195206

196-
if (!pasemi_nand_mtd)
197-
return 0;
198-
199-
chip = mtd_to_nand(pasemi_nand_mtd);
207+
chip = &ddata->chip;
208+
pasemi_nand_mtd = nand_to_mtd(chip);
200209

201210
/* Release resources, unregister device */
202211
ret = mtd_device_unregister(pasemi_nand_mtd);
203212
WARN_ON(ret);
204213
nand_cleanup(chip);
205214

206-
release_region(lpcctl, 4);
215+
release_region(ddata->lpcctl, 4);
207216

208217
iounmap(chip->legacy.IO_ADDR_R);
209218

210219
/* Free the MTD device structure */
211-
kfree(chip);
212-
213-
pasemi_nand_mtd = NULL;
220+
kfree(ddata);
214221

215222
return 0;
216223
}

0 commit comments

Comments
 (0)