svn commit: r311801 - stable/11/sys/compat/linuxkpi/common/include/linux
Hans Petter Selasky
hselasky at FreeBSD.org
Mon Jan 9 17:18:40 UTC 2017
Author: hselasky
Date: Mon Jan 9 17:18:39 2017
New Revision: 311801
URL: https://svnweb.freebsd.org/changeset/base/311801
Log:
MFC r310553:
Improve LinuxKPI device support. Only delete own BSD devices and not
the ones obtained through devclass_get_device(). Some minor code
cleanups while at it.
Obtained from: kmacy @
Sponsored by: Mellanox Technologies
Modified:
stable/11/sys/compat/linuxkpi/common/include/linux/device.h
Directory Properties:
stable/11/ (props changed)
Modified: stable/11/sys/compat/linuxkpi/common/include/linux/device.h
==============================================================================
--- stable/11/sys/compat/linuxkpi/common/include/linux/device.h Mon Jan 9 17:16:14 2017 (r311800)
+++ stable/11/sys/compat/linuxkpi/common/include/linux/device.h Mon Jan 9 17:18:39 2017 (r311801)
@@ -63,6 +63,14 @@ struct device {
struct device *parent;
struct list_head irqents;
device_t bsddev;
+ /*
+ * The following flag is used to determine if the LinuxKPI is
+ * responsible for detaching the BSD device or not. If the
+ * LinuxKPI got the BSD device using devclass_get_device(), it
+ * must not try to detach or delete it, because it's already
+ * done somewhere else.
+ */
+ bool bsddev_attached_here;
dev_t devt;
struct class *class;
void (*release)(struct device *dev);
@@ -208,23 +216,36 @@ static inline struct device *kobj_to_dev
static inline void
device_initialize(struct device *dev)
{
- device_t bsddev;
+ device_t bsddev = NULL;
+ int unit = -1;
- bsddev = NULL;
if (dev->devt) {
- int unit = MINOR(dev->devt);
+ unit = MINOR(dev->devt);
bsddev = devclass_get_device(dev->class->bsdclass, unit);
+ dev->bsddev_attached_here = false;
+ } else if (dev->parent == NULL) {
+ bsddev = devclass_get_device(dev->class->bsdclass, 0);
+ dev->bsddev_attached_here = false;
+ } else {
+ dev->bsddev_attached_here = true;
+ }
+
+ if (bsddev == NULL && dev->parent != NULL) {
+ bsddev = device_add_child(dev->parent->bsddev,
+ dev->class->kobj.name, unit);
}
+
if (bsddev != NULL)
device_set_softc(bsddev, dev);
dev->bsddev = bsddev;
+ MPASS(dev->bsddev != NULL);
kobject_init(&dev->kobj, &linux_dev_ktype);
}
static inline int
device_add(struct device *dev)
-{
+{
if (dev->bsddev != NULL) {
if (dev->devt == 0)
dev->devt = makedev(0, device_get_unit(dev->bsddev));
@@ -256,13 +277,13 @@ device_create_groups_vargs(struct class
goto error;
}
- device_initialize(dev);
dev->devt = devt;
dev->class = class;
dev->parent = parent;
dev->groups = groups;
dev->release = device_create_release;
- dev->bsddev = devclass_get_device(dev->class->bsdclass, MINOR(devt));
+ /* device_initialize() needs the class and parent to be set */
+ device_initialize(dev);
dev_set_drvdata(dev, drvdata);
retval = kobject_set_name_vargs(&dev->kobj, fmt, args);
@@ -298,17 +319,21 @@ device_create_with_groups(struct class *
static inline int
device_register(struct device *dev)
{
- device_t bsddev;
- int unit;
+ device_t bsddev = NULL;
+ int unit = -1;
- bsddev = NULL;
- unit = -1;
+ if (dev->bsddev != NULL)
+ goto done;
if (dev->devt) {
unit = MINOR(dev->devt);
bsddev = devclass_get_device(dev->class->bsdclass, unit);
+ dev->bsddev_attached_here = false;
} else if (dev->parent == NULL) {
bsddev = devclass_get_device(dev->class->bsdclass, 0);
+ dev->bsddev_attached_here = false;
+ } else {
+ dev->bsddev_attached_here = true;
}
if (bsddev == NULL && dev->parent != NULL) {
bsddev = device_add_child(dev->parent->bsddev,
@@ -320,6 +345,7 @@ device_register(struct device *dev)
device_set_softc(bsddev, dev);
}
dev->bsddev = bsddev;
+done:
kobject_init(&dev->kobj, &linux_dev_ktype);
kobject_add(&dev->kobj, &dev->class->kobj, dev_name(dev));
@@ -334,7 +360,7 @@ device_unregister(struct device *dev)
bsddev = dev->bsddev;
dev->bsddev = NULL;
- if (bsddev != NULL) {
+ if (bsddev != NULL && dev->bsddev_attached_here) {
mtx_lock(&Giant);
device_delete_child(device_get_parent(bsddev), bsddev);
mtx_unlock(&Giant);
@@ -350,7 +376,7 @@ device_del(struct device *dev)
bsddev = dev->bsddev;
dev->bsddev = NULL;
- if (bsddev != NULL) {
+ if (bsddev != NULL && dev->bsddev_attached_here) {
mtx_lock(&Giant);
device_delete_child(device_get_parent(bsddev), bsddev);
mtx_unlock(&Giant);
More information about the svn-src-all
mailing list