diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c
index 05f22f971312..6612f8bc79c9 100644
--- a/net/switchdev/switchdev.c
+++ b/net/switchdev/switchdev.c
@@ -22,17 +22,103 @@
 static LIST_HEAD(deferred);
 static DEFINE_SPINLOCK(deferred_lock);
 
-typedef void switchdev_deferred_func_t(struct net_device *dev,
-				       const void *data);
-
 struct switchdev_deferred_item {
 	struct list_head list;
-	struct net_device *dev;
+
+	enum switchdev_notifier_type nt;
+	union {
+		/* Guaranteed to be first in all subtypes */
+		struct switchdev_notifier_info info;
+
+		struct {
+			struct switchdev_notifier_port_attr_info info;
+			struct switchdev_attr attr;
+		} attr;
+
+		struct {
+			struct switchdev_notifier_port_obj_info info;
+			union {
+				struct switchdev_obj_port_vlan vlan;
+				struct switchdev_obj_port_mdb mdb;
+			};
+		} obj;
+	};
 	netdevice_tracker dev_tracker;
-	switchdev_deferred_func_t *func;
-	unsigned long data[];
 };
 
+static int switchdev_port_notify(struct net_device *dev,
+				 enum switchdev_notifier_type nt,
+				 struct switchdev_notifier_info *info,
+				 struct netlink_ext_ack *extack)
+{
+	const struct switchdev_notifier_port_attr_info *attri;
+	const struct switchdev_notifier_port_obj_info *obji;
+	int err;
+	int rc;
+
+	rc = call_switchdev_blocking_notifiers(nt, dev, info, extack);
+	err = notifier_to_errno(rc);
+
+	switch (nt) {
+	case SWITCHDEV_PORT_ATTR_SET:
+		attri = container_of(info, typeof(*attri), info);
+		if (err) {
+			WARN_ON(!attri->handled);
+			return err;
+		}
+		if (!attri->handled)
+			return -EOPNOTSUPP;
+		break;
+	case SWITCHDEV_PORT_OBJ_ADD:
+	case SWITCHDEV_PORT_OBJ_DEL:
+		obji = container_of(info, typeof(*obji), info);
+		if (err) {
+			WARN_ON(!obji->handled);
+			return err;
+		}
+		if (!obji->handled)
+			return -EOPNOTSUPP;
+		break;
+	default:
+		break;
+	}
+
+	return err;
+}
+
+static void switchdev_deferred_notify(struct switchdev_deferred_item *dfitem)
+{
+	const struct switchdev_attr *attr;
+	const struct switchdev_obj *obj;
+	char info_str[128];
+	int err;
+
+	err = switchdev_port_notify(dfitem->info.dev, dfitem->nt, &dfitem->info, NULL);
+	if (err && err != -EOPNOTSUPP) {
+		switchdev_notifier_str(dfitem->nt, &dfitem->info,
+				       info_str, sizeof(info_str));
+		netdev_err(dfitem->info.dev,
+			   "deferred switchdev call failed (err=%d): %s",
+			   err, info_str);
+	}
+
+	switch (dfitem->nt) {
+	case SWITCHDEV_PORT_ATTR_SET:
+		attr = &dfitem->attr.attr;
+		if (attr->complete)
+			attr->complete(dfitem->info.dev, err, attr->complete_priv);
+		break;
+	case SWITCHDEV_PORT_OBJ_ADD:
+	case SWITCHDEV_PORT_OBJ_DEL:
+		obj = dfitem->obj.info.obj;
+		if (obj->complete)
+			obj->complete(dfitem->info.dev, err, obj->complete_priv);
+		break;
+	default:
+		break;
+	}
+}
+
 static struct switchdev_deferred_item *switchdev_deferred_dequeue(void)
 {
 	struct switchdev_deferred_item *dfitem;
@@ -63,8 +149,8 @@ void switchdev_deferred_process(void)
 	ASSERT_RTNL();
 
 	while ((dfitem = switchdev_deferred_dequeue())) {
-		dfitem->func(dfitem->dev, dfitem->data);
-		netdev_put(dfitem->dev, &dfitem->dev_tracker);
+		switchdev_deferred_notify(dfitem);
+		netdev_put(dfitem->info.dev, &dfitem->dev_tracker);
 		kfree(dfitem);
 	}
 }
@@ -79,19 +165,9 @@ static void switchdev_deferred_process_work(struct work_struct *work)
 
 static DECLARE_WORK(deferred_process_work, switchdev_deferred_process_work);
 
-static int switchdev_deferred_enqueue(struct net_device *dev,
-				      const void *data, size_t data_len,
-				      switchdev_deferred_func_t *func)
+static int switchdev_deferred_enqueue(struct switchdev_deferred_item *dfitem)
 {
-	struct switchdev_deferred_item *dfitem;
-
-	dfitem = kmalloc(struct_size(dfitem, data, data_len), GFP_ATOMIC);
-	if (!dfitem)
-		return -ENOMEM;
-	dfitem->dev = dev;
-	dfitem->func = func;
-	memcpy(dfitem->data, data, data_len);
-	netdev_hold(dev, &dfitem->dev_tracker, GFP_ATOMIC);
+	netdev_hold(dfitem->info.dev, &dfitem->dev_tracker, GFP_ATOMIC);
 	spin_lock_bh(&deferred_lock);
 	list_add_tail(&dfitem->list, &deferred);
 	spin_unlock_bh(&deferred_lock);
@@ -99,62 +175,24 @@ static int switchdev_deferred_enqueue(struct net_device *dev,
 	return 0;
 }
 
-static int switchdev_port_attr_notify(enum switchdev_notifier_type nt,
-				      struct net_device *dev,
-				      const struct switchdev_attr *attr,
-				      struct netlink_ext_ack *extack)
+static int switchdev_port_attr_defer(struct net_device *dev,
+				     const struct switchdev_attr *attr)
 {
-	int err;
-	int rc;
-
-	struct switchdev_notifier_port_attr_info attr_info = {
-		.attr = attr,
-		.handled = false,
-	};
-
-	rc = call_switchdev_blocking_notifiers(nt, dev,
-					       &attr_info.info, extack);
-	err = notifier_to_errno(rc);
-	if (err) {
-		WARN_ON(!attr_info.handled);
-		return err;
-	}
+	struct switchdev_deferred_item *dfitem;
 
-	if (!attr_info.handled)
-		return -EOPNOTSUPP;
+	dfitem = kzalloc(sizeof(*dfitem), GFP_ATOMIC);
+	if (!dfitem)
+		return -ENOMEM;
 
+	dfitem->nt = SWITCHDEV_PORT_ATTR_SET;
+	dfitem->info.dev = dev;
+	dfitem->attr.attr = *attr;
+	dfitem->attr.info.attr = &dfitem->attr.attr;
+	dfitem->attr.info.handled = false;
+	switchdev_deferred_enqueue(dfitem);
 	return 0;
 }
 
-static int switchdev_port_attr_set_now(struct net_device *dev,
-				       const struct switchdev_attr *attr,
-				       struct netlink_ext_ack *extack)
-{
-	return switchdev_port_attr_notify(SWITCHDEV_PORT_ATTR_SET, dev, attr,
-					  extack);
-}
-
-static void switchdev_port_attr_set_deferred(struct net_device *dev,
-					     const void *data)
-{
-	const struct switchdev_attr *attr = data;
-	int err;
-
-	err = switchdev_port_attr_set_now(dev, attr, NULL);
-	if (err && err != -EOPNOTSUPP)
-		netdev_err(dev, "failed (err=%d) to set attribute (id=%d)\n",
-			   err, attr->id);
-	if (attr->complete)
-		attr->complete(dev, err, attr->complete_priv);
-}
-
-static int switchdev_port_attr_set_defer(struct net_device *dev,
-					 const struct switchdev_attr *attr)
-{
-	return switchdev_deferred_enqueue(dev, attr, sizeof(*attr),
-					  switchdev_port_attr_set_deferred);
-}
-
 /**
  *	switchdev_port_attr_set - Set port attribute
  *
@@ -169,73 +207,75 @@ int switchdev_port_attr_set(struct net_device *dev,
 			    const struct switchdev_attr *attr,
 			    struct netlink_ext_ack *extack)
 {
+	struct switchdev_notifier_port_attr_info attr_info = {
+		.attr = attr,
+		.handled = false,
+	};
+
 	if (attr->flags & SWITCHDEV_F_DEFER)
-		return switchdev_port_attr_set_defer(dev, attr);
+		return switchdev_port_attr_defer(dev, attr);
+
 	ASSERT_RTNL();
-	return switchdev_port_attr_set_now(dev, attr, extack);
+	return switchdev_port_notify(dev, SWITCHDEV_PORT_ATTR_SET,
+				     &attr_info.info, extack);
 }
 EXPORT_SYMBOL_GPL(switchdev_port_attr_set);
 
-static size_t switchdev_obj_size(const struct switchdev_obj *obj)
+static int switchdev_port_obj_defer(struct net_device *dev,
+				    enum switchdev_notifier_type nt,
+				    const struct switchdev_obj *obj)
 {
+	const struct switchdev_obj_port_vlan *vlan;
+	const struct switchdev_obj_port_mdb *mdb;
+	struct switchdev_deferred_item *dfitem;
+
+	dfitem = kzalloc(sizeof(*dfitem), GFP_ATOMIC);
+	if (!dfitem)
+		return -ENOMEM;
+
+	dfitem->nt = nt;
+	dfitem->info.dev = dev;
+	dfitem->obj.info.handled = false;
+
 	switch (obj->id) {
 	case SWITCHDEV_OBJ_ID_PORT_VLAN:
-		return sizeof(struct switchdev_obj_port_vlan);
+		vlan = SWITCHDEV_OBJ_PORT_VLAN(obj);
+		dfitem->obj.vlan = *vlan;
+		dfitem->obj.info.obj = &dfitem->obj.vlan.obj;
+		break;
 	case SWITCHDEV_OBJ_ID_PORT_MDB:
-		return sizeof(struct switchdev_obj_port_mdb);
 	case SWITCHDEV_OBJ_ID_HOST_MDB:
-		return sizeof(struct switchdev_obj_port_mdb);
+		mdb = SWITCHDEV_OBJ_PORT_MDB(obj);
+		dfitem->obj.mdb = *mdb;
+		dfitem->obj.info.obj = &dfitem->obj.mdb.obj;
+		break;
 	default:
-		BUG();
+		goto err_free;
 	}
+
+	switchdev_deferred_enqueue(dfitem);
 	return 0;
+
+err_free:
+	kfree(dfitem);
+	return -EINVAL;
 }
 
-static int switchdev_port_obj_notify(enum switchdev_notifier_type nt,
-				     struct net_device *dev,
-				     const struct switchdev_obj *obj,
-				     struct netlink_ext_ack *extack)
+static int switchdev_port_obj_op(struct net_device *dev,
+				 enum switchdev_notifier_type nt,
+				 const struct switchdev_obj *obj,
+				 struct netlink_ext_ack *extack)
 {
-	int rc;
-	int err;
-
 	struct switchdev_notifier_port_obj_info obj_info = {
 		.obj = obj,
 		.handled = false,
 	};
 
-	rc = call_switchdev_blocking_notifiers(nt, dev, &obj_info.info, extack);
-	err = notifier_to_errno(rc);
-	if (err) {
-		WARN_ON(!obj_info.handled);
-		return err;
-	}
-	if (!obj_info.handled)
-		return -EOPNOTSUPP;
-	return 0;
-}
-
-static void switchdev_port_obj_add_deferred(struct net_device *dev,
-					    const void *data)
-{
-	const struct switchdev_obj *obj = data;
-	int err;
+	if (obj->flags & SWITCHDEV_F_DEFER)
+		return switchdev_port_obj_defer(dev, nt, obj);
 
 	ASSERT_RTNL();
-	err = switchdev_port_obj_notify(SWITCHDEV_PORT_OBJ_ADD,
-					dev, obj, NULL);
-	if (err && err != -EOPNOTSUPP)
-		netdev_err(dev, "failed (err=%d) to add object (id=%d)\n",
-			   err, obj->id);
-	if (obj->complete)
-		obj->complete(dev, err, obj->complete_priv);
-}
-
-static int switchdev_port_obj_add_defer(struct net_device *dev,
-					const struct switchdev_obj *obj)
-{
-	return switchdev_deferred_enqueue(dev, obj, switchdev_obj_size(obj),
-					  switchdev_port_obj_add_deferred);
+	return switchdev_port_notify(dev, nt, &obj_info.info, extack);
 }
 
 /**
@@ -252,42 +292,10 @@ int switchdev_port_obj_add(struct net_device *dev,
 			   const struct switchdev_obj *obj,
 			   struct netlink_ext_ack *extack)
 {
-	if (obj->flags & SWITCHDEV_F_DEFER)
-		return switchdev_port_obj_add_defer(dev, obj);
-	ASSERT_RTNL();
-	return switchdev_port_obj_notify(SWITCHDEV_PORT_OBJ_ADD,
-					 dev, obj, extack);
+	return switchdev_port_obj_op(dev, SWITCHDEV_PORT_OBJ_ADD, obj, extack);
 }
 EXPORT_SYMBOL_GPL(switchdev_port_obj_add);
 
-static int switchdev_port_obj_del_now(struct net_device *dev,
-				      const struct switchdev_obj *obj)
-{
-	return switchdev_port_obj_notify(SWITCHDEV_PORT_OBJ_DEL,
-					 dev, obj, NULL);
-}
-
-static void switchdev_port_obj_del_deferred(struct net_device *dev,
-					    const void *data)
-{
-	const struct switchdev_obj *obj = data;
-	int err;
-
-	err = switchdev_port_obj_del_now(dev, obj);
-	if (err && err != -EOPNOTSUPP)
-		netdev_err(dev, "failed (err=%d) to del object (id=%d)\n",
-			   err, obj->id);
-	if (obj->complete)
-		obj->complete(dev, err, obj->complete_priv);
-}
-
-static int switchdev_port_obj_del_defer(struct net_device *dev,
-					const struct switchdev_obj *obj)
-{
-	return switchdev_deferred_enqueue(dev, obj, switchdev_obj_size(obj),
-					  switchdev_port_obj_del_deferred);
-}
-
 /**
  *	switchdev_port_obj_del - Delete port object
  *
@@ -300,10 +308,7 @@ static int switchdev_port_obj_del_defer(struct net_device *dev,
 int switchdev_port_obj_del(struct net_device *dev,
 			   const struct switchdev_obj *obj)
 {
-	if (obj->flags & SWITCHDEV_F_DEFER)
-		return switchdev_port_obj_del_defer(dev, obj);
-	ASSERT_RTNL();
-	return switchdev_port_obj_del_now(dev, obj);
+	return switchdev_port_obj_op(dev, SWITCHDEV_PORT_OBJ_DEL, obj, NULL);
 }
 EXPORT_SYMBOL_GPL(switchdev_port_obj_del);
 
