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 @
MFC after:	1 week
Sponsored by:	Mellanox Technologies
This commit is contained in:
hselasky 2016-12-25 19:49:09 +00:00
parent 8f3c939828
commit bc7c5848fe

View File

@ -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(struct kobject *kobj)
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 *class, struct device *parent,
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 *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);