Skip to content

Commit 47c16ac

Browse files
davejiangvinodkoul
authored andcommitted
dmaengine: idxd: fix idxd conf_dev 'struct device' lifetime
The devm managed lifetime is incompatible with 'struct device' objects that resides in idxd context. This is one of the series that clean up the idxd driver 'struct device' lifetime. Fix idxd->conf_dev 'struct device' lifetime. Address issues flagged by CONFIG_DEBUG_KOBJECT_RELEASE. Add release functions in order to free the allocated memory at the appropriate time. Reported-by: Jason Gunthorpe <[email protected]> Fixes: bfe1d56 ("dmaengine: idxd: Init and probe for Intel data accelerators") Signed-off-by: Dave Jiang <[email protected]> Link: https://lore.kernel.org/r/161852985319.2203940.4650791514462735368.stgit@djiang5-desk3.ch.intel.com Signed-off-by: Vinod Koul <[email protected]>
1 parent f7f7739 commit 47c16ac

File tree

3 files changed

+94
-90
lines changed

3 files changed

+94
-90
lines changed

drivers/dma/idxd/idxd.h

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <linux/percpu-rwsem.h>
99
#include <linux/wait.h>
1010
#include <linux/cdev.h>
11+
#include <linux/idr.h>
1112
#include "registers.h"
1213

1314
#define IDXD_DRIVER_VERSION "1.00"
@@ -255,6 +256,23 @@ extern struct bus_type dsa_bus_type;
255256
extern struct bus_type iax_bus_type;
256257

257258
extern bool support_enqcmd;
259+
extern struct device_type dsa_device_type;
260+
extern struct device_type iax_device_type;
261+
262+
static inline bool is_dsa_dev(struct device *dev)
263+
{
264+
return dev->type == &dsa_device_type;
265+
}
266+
267+
static inline bool is_iax_dev(struct device *dev)
268+
{
269+
return dev->type == &iax_device_type;
270+
}
271+
272+
static inline bool is_idxd_dev(struct device *dev)
273+
{
274+
return is_dsa_dev(dev) || is_iax_dev(dev);
275+
}
258276

259277
static inline bool wq_dedicated(struct idxd_wq *wq)
260278
{
@@ -292,18 +310,6 @@ static inline int idxd_get_wq_portal_full_offset(int wq_id,
292310
return ((wq_id * 4) << PAGE_SHIFT) + idxd_get_wq_portal_offset(prot);
293311
}
294312

295-
static inline void idxd_set_type(struct idxd_device *idxd)
296-
{
297-
struct pci_dev *pdev = idxd->pdev;
298-
299-
if (pdev->device == PCI_DEVICE_ID_INTEL_DSA_SPR0)
300-
idxd->type = IDXD_TYPE_DSA;
301-
else if (pdev->device == PCI_DEVICE_ID_INTEL_IAX_SPR0)
302-
idxd->type = IDXD_TYPE_IAX;
303-
else
304-
idxd->type = IDXD_TYPE_UNKNOWN;
305-
}
306-
307313
static inline void idxd_wq_get(struct idxd_wq *wq)
308314
{
309315
wq->client_count++;
@@ -319,14 +325,16 @@ static inline int idxd_wq_refcount(struct idxd_wq *wq)
319325
return wq->client_count;
320326
};
321327

328+
struct ida *idxd_ida(struct idxd_device *idxd);
322329
const char *idxd_get_dev_name(struct idxd_device *idxd);
323330
int idxd_register_bus_type(void);
324331
void idxd_unregister_bus_type(void);
325-
int idxd_setup_sysfs(struct idxd_device *idxd);
326-
void idxd_cleanup_sysfs(struct idxd_device *idxd);
332+
int idxd_register_devices(struct idxd_device *idxd);
333+
void idxd_unregister_devices(struct idxd_device *idxd);
327334
int idxd_register_driver(void);
328335
void idxd_unregister_driver(void);
329336
struct bus_type *idxd_get_bus_type(struct idxd_device *idxd);
337+
struct device_type *idxd_get_device_type(struct idxd_device *idxd);
330338

331339
/* device interrupt control */
332340
void idxd_msix_perm_setup(struct idxd_device *idxd);

drivers/dma/idxd/init.c

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ static char *idxd_name[] = {
5151
"iax"
5252
};
5353

54+
struct ida *idxd_ida(struct idxd_device *idxd)
55+
{
56+
return &idxd_idas[idxd->type];
57+
}
58+
5459
const char *idxd_get_dev_name(struct idxd_device *idxd)
5560
{
5661
return idxd_name[idxd->type];
@@ -81,9 +86,8 @@ static int idxd_setup_interrupts(struct idxd_device *idxd)
8186
* We implement 1 completion list per MSI-X entry except for
8287
* entry 0, which is for errors and others.
8388
*/
84-
idxd->irq_entries = devm_kcalloc(dev, msixcnt,
85-
sizeof(struct idxd_irq_entry),
86-
GFP_KERNEL);
89+
idxd->irq_entries = kcalloc_node(msixcnt, sizeof(struct idxd_irq_entry),
90+
GFP_KERNEL, dev_to_node(dev));
8791
if (!idxd->irq_entries) {
8892
rc = -ENOMEM;
8993
goto err_irq_entries;
@@ -262,16 +266,44 @@ static void idxd_read_caps(struct idxd_device *idxd)
262266
}
263267
}
264268

269+
static inline void idxd_set_type(struct idxd_device *idxd)
270+
{
271+
struct pci_dev *pdev = idxd->pdev;
272+
273+
if (pdev->device == PCI_DEVICE_ID_INTEL_DSA_SPR0)
274+
idxd->type = IDXD_TYPE_DSA;
275+
else if (pdev->device == PCI_DEVICE_ID_INTEL_IAX_SPR0)
276+
idxd->type = IDXD_TYPE_IAX;
277+
else
278+
idxd->type = IDXD_TYPE_UNKNOWN;
279+
}
280+
265281
static struct idxd_device *idxd_alloc(struct pci_dev *pdev)
266282
{
267283
struct device *dev = &pdev->dev;
268284
struct idxd_device *idxd;
285+
int rc;
269286

270-
idxd = devm_kzalloc(dev, sizeof(struct idxd_device), GFP_KERNEL);
287+
idxd = kzalloc_node(sizeof(*idxd), GFP_KERNEL, dev_to_node(dev));
271288
if (!idxd)
272289
return NULL;
273290

274291
idxd->pdev = pdev;
292+
idxd_set_type(idxd);
293+
idxd->id = ida_alloc(idxd_ida(idxd), GFP_KERNEL);
294+
if (idxd->id < 0)
295+
return NULL;
296+
297+
device_initialize(&idxd->conf_dev);
298+
idxd->conf_dev.parent = dev;
299+
idxd->conf_dev.bus = idxd_get_bus_type(idxd);
300+
idxd->conf_dev.type = idxd_get_device_type(idxd);
301+
rc = dev_set_name(&idxd->conf_dev, "%s%d", idxd_get_dev_name(idxd), idxd->id);
302+
if (rc < 0) {
303+
put_device(&idxd->conf_dev);
304+
return NULL;
305+
}
306+
275307
spin_lock_init(&idxd->dev_lock);
276308

277309
return idxd;
@@ -347,20 +379,11 @@ static int idxd_probe(struct idxd_device *idxd)
347379

348380
dev_dbg(dev, "IDXD interrupt setup complete.\n");
349381

350-
idxd->id = ida_alloc(&idxd_idas[idxd->type], GFP_KERNEL);
351-
if (idxd->id < 0) {
352-
rc = -ENOMEM;
353-
goto err_ida_fail;
354-
}
355-
356382
idxd->major = idxd_cdev_get_major(idxd);
357383

358384
dev_dbg(dev, "IDXD device %d probed successfully\n", idxd->id);
359385
return 0;
360386

361-
err_ida_fail:
362-
idxd_mask_error_interrupts(idxd);
363-
idxd_mask_msix_vectors(idxd);
364387
err_setup:
365388
if (device_pasid_enabled(idxd))
366389
idxd_disable_system_pasid(idxd);
@@ -412,7 +435,6 @@ static int idxd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
412435
if (rc)
413436
goto err;
414437

415-
idxd_set_type(idxd);
416438

417439
idxd_type_init(idxd);
418440

@@ -427,7 +449,7 @@ static int idxd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
427449
goto err;
428450
}
429451

430-
rc = idxd_setup_sysfs(idxd);
452+
rc = idxd_register_devices(idxd);
431453
if (rc) {
432454
dev_err(dev, "IDXD sysfs setup failed\n");
433455
goto err;
@@ -443,6 +465,7 @@ static int idxd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
443465
err:
444466
pci_iounmap(pdev, idxd->reg_base);
445467
err_iomap:
468+
put_device(&idxd->conf_dev);
446469
err_idxd_alloc:
447470
pci_disable_device(pdev);
448471
return rc;
@@ -511,11 +534,10 @@ static void idxd_remove(struct pci_dev *pdev)
511534
struct idxd_device *idxd = pci_get_drvdata(pdev);
512535

513536
dev_dbg(&pdev->dev, "%s called\n", __func__);
514-
idxd_cleanup_sysfs(idxd);
515537
idxd_shutdown(pdev);
516538
if (device_pasid_enabled(idxd))
517539
idxd_disable_system_pasid(idxd);
518-
ida_free(&idxd_idas[idxd->type], idxd->id);
540+
idxd_unregister_devices(idxd);
519541
}
520542

521543
static struct pci_driver idxd_pci_driver = {

drivers/dma/idxd/sysfs.c

Lines changed: 33 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -16,51 +16,26 @@ static char *idxd_wq_type_names[] = {
1616
[IDXD_WQT_USER] = "user",
1717
};
1818

19-
static void idxd_conf_device_release(struct device *dev)
19+
static void idxd_conf_sub_device_release(struct device *dev)
2020
{
2121
dev_dbg(dev, "%s for %s\n", __func__, dev_name(dev));
2222
}
2323

2424
static struct device_type idxd_group_device_type = {
2525
.name = "group",
26-
.release = idxd_conf_device_release,
26+
.release = idxd_conf_sub_device_release,
2727
};
2828

2929
static struct device_type idxd_wq_device_type = {
3030
.name = "wq",
31-
.release = idxd_conf_device_release,
31+
.release = idxd_conf_sub_device_release,
3232
};
3333

3434
static struct device_type idxd_engine_device_type = {
3535
.name = "engine",
36-
.release = idxd_conf_device_release,
36+
.release = idxd_conf_sub_device_release,
3737
};
3838

39-
static struct device_type dsa_device_type = {
40-
.name = "dsa",
41-
.release = idxd_conf_device_release,
42-
};
43-
44-
static struct device_type iax_device_type = {
45-
.name = "iax",
46-
.release = idxd_conf_device_release,
47-
};
48-
49-
static inline bool is_dsa_dev(struct device *dev)
50-
{
51-
return dev ? dev->type == &dsa_device_type : false;
52-
}
53-
54-
static inline bool is_iax_dev(struct device *dev)
55-
{
56-
return dev ? dev->type == &iax_device_type : false;
57-
}
58-
59-
static inline bool is_idxd_dev(struct device *dev)
60-
{
61-
return is_dsa_dev(dev) || is_iax_dev(dev);
62-
}
63-
6439
static inline bool is_idxd_wq_dev(struct device *dev)
6540
{
6641
return dev ? dev->type == &idxd_wq_device_type : false;
@@ -405,7 +380,7 @@ struct bus_type *idxd_get_bus_type(struct idxd_device *idxd)
405380
return idxd_bus_types[idxd->type];
406381
}
407382

408-
static struct device_type *idxd_get_device_type(struct idxd_device *idxd)
383+
struct device_type *idxd_get_device_type(struct idxd_device *idxd)
409384
{
410385
if (idxd->type == IDXD_TYPE_DSA)
411386
return &dsa_device_type;
@@ -1644,6 +1619,30 @@ static const struct attribute_group *idxd_attribute_groups[] = {
16441619
NULL,
16451620
};
16461621

1622+
static void idxd_conf_device_release(struct device *dev)
1623+
{
1624+
struct idxd_device *idxd = container_of(dev, struct idxd_device, conf_dev);
1625+
1626+
kfree(idxd->groups);
1627+
kfree(idxd->wqs);
1628+
kfree(idxd->engines);
1629+
kfree(idxd->irq_entries);
1630+
ida_free(idxd_ida(idxd), idxd->id);
1631+
kfree(idxd);
1632+
}
1633+
1634+
struct device_type dsa_device_type = {
1635+
.name = "dsa",
1636+
.release = idxd_conf_device_release,
1637+
.groups = idxd_attribute_groups,
1638+
};
1639+
1640+
struct device_type iax_device_type = {
1641+
.name = "iax",
1642+
.release = idxd_conf_device_release,
1643+
.groups = idxd_attribute_groups,
1644+
};
1645+
16471646
static int idxd_setup_engine_sysfs(struct idxd_device *idxd)
16481647
{
16491648
struct device *dev = &idxd->pdev->dev;
@@ -1745,39 +1744,14 @@ static int idxd_setup_wq_sysfs(struct idxd_device *idxd)
17451744
return rc;
17461745
}
17471746

1748-
static int idxd_setup_device_sysfs(struct idxd_device *idxd)
1747+
int idxd_register_devices(struct idxd_device *idxd)
17491748
{
17501749
struct device *dev = &idxd->pdev->dev;
17511750
int rc;
1752-
char devname[IDXD_NAME_SIZE];
17531751

1754-
sprintf(devname, "%s%d", idxd_get_dev_name(idxd), idxd->id);
1755-
idxd->conf_dev.parent = dev;
1756-
dev_set_name(&idxd->conf_dev, "%s", devname);
1757-
idxd->conf_dev.bus = idxd_get_bus_type(idxd);
1758-
idxd->conf_dev.groups = idxd_attribute_groups;
1759-
idxd->conf_dev.type = idxd_get_device_type(idxd);
1760-
1761-
dev_dbg(dev, "IDXD device register: %s\n", dev_name(&idxd->conf_dev));
1762-
rc = device_register(&idxd->conf_dev);
1763-
if (rc < 0) {
1764-
put_device(&idxd->conf_dev);
1765-
return rc;
1766-
}
1767-
1768-
return 0;
1769-
}
1770-
1771-
int idxd_setup_sysfs(struct idxd_device *idxd)
1772-
{
1773-
struct device *dev = &idxd->pdev->dev;
1774-
int rc;
1775-
1776-
rc = idxd_setup_device_sysfs(idxd);
1777-
if (rc < 0) {
1778-
dev_dbg(dev, "Device sysfs registering failed: %d\n", rc);
1752+
rc = device_add(&idxd->conf_dev);
1753+
if (rc < 0)
17791754
return rc;
1780-
}
17811755

17821756
rc = idxd_setup_wq_sysfs(idxd);
17831757
if (rc < 0) {
@@ -1803,7 +1777,7 @@ int idxd_setup_sysfs(struct idxd_device *idxd)
18031777
return 0;
18041778
}
18051779

1806-
void idxd_cleanup_sysfs(struct idxd_device *idxd)
1780+
void idxd_unregister_devices(struct idxd_device *idxd)
18071781
{
18081782
int i;
18091783

0 commit comments

Comments
 (0)