git: b8ff248f6595 - main - stand/ofw: Subclass devnet to cope with ofw's unique needs

From: Warner Losh <imp_at_FreeBSD.org>
Date: Wed, 30 Nov 2022 22:31:30 UTC
The branch main has been updated by imp:

URL: https://cgit.FreeBSD.org/src/commit/?id=b8ff248f6595067ef9a31d5d4cec5fb9b9052fc3

commit b8ff248f6595067ef9a31d5d4cec5fb9b9052fc3
Author:     Warner Losh <imp@FreeBSD.org>
AuthorDate: 2022-11-30 22:10:05 +0000
Commit:     Warner Losh <imp@FreeBSD.org>
CommitDate: 2022-11-30 22:30:33 +0000

    stand/ofw: Subclass devnet to cope with ofw's unique needs
    
    We need to match devices in a slightly special way: We have to look up
    the path and see if the device is a 'network' device in order to use it.
    
    Sponsored by:           Netflix
    Tested by:              grehan@ (with tweaks to my original patch)
    Differential Revision:  https://reviews.freebsd.org/D37557
---
 stand/libofw/libofw.h    |  1 +
 stand/libofw/ofw_net.c   | 75 ++++++++++++++++++++++++++++++++++++++++++++++++
 stand/powerpc/ofw/conf.c |  2 +-
 3 files changed, 77 insertions(+), 1 deletion(-)

diff --git a/stand/libofw/libofw.h b/stand/libofw/libofw.h
index 0494a78135e7..ce7e6e986029 100644
--- a/stand/libofw/libofw.h
+++ b/stand/libofw/libofw.h
@@ -48,6 +48,7 @@ extern int	ofw_getdev(void **vdev, const char *devspec, const char **path);
 extern ev_sethook_t ofw_setcurrdev;
 
 extern struct devsw		ofwdisk;
+extern struct devsw		ofw_netdev;
 extern struct netif_driver	ofwnet;
 
 int	ofwn_getunit(const char *);
diff --git a/stand/libofw/ofw_net.c b/stand/libofw/ofw_net.c
index fa4a3abd88e8..59b9f8de7efb 100644
--- a/stand/libofw/ofw_net.c
+++ b/stand/libofw/ofw_net.c
@@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$");
 #include <net.h>
 #include <netif.h>
 
+#include "libofw.h"
 #include "openfirm.h"
 
 static int	ofwn_probe(struct netif *, void *);
@@ -267,3 +268,77 @@ ofwn_getunit(const char *path)
 	return -1;
 }
 #endif
+
+/*
+ * To properly match network devices, we have to subclass the netdev device.
+ * It has a different devdesc than a normal network device (which is fine:
+ * it's a struct superset) and different matching criteria (since it has to
+ * look at the path, find a handle and see if that handle is a network node
+ * or not).
+ */
+
+static int ofwnd_init(void);
+static int ofwnd_parsedev(struct devdesc **, const char *, const char **);
+static bool ofwnd_match(struct devsw *, const char *);
+static char *ofwnd_fmtdev(struct devdesc *);
+
+struct devsw ofw_netdev = {
+	.dv_name = "network",
+	.dv_type = DEVT_NET,
+	.dv_init = ofwnd_init,
+	.dv_match = ofwnd_match,
+	.dv_fmtdev = ofwnd_fmtdev,
+	.dv_parsedev = ofwnd_parsedev,
+};
+
+static int ofwnd_init(void)
+{
+	netdev.dv_init();
+	ofw_netdev.dv_strategy = netdev.dv_strategy;
+	ofw_netdev.dv_open = netdev.dv_open;
+	ofw_netdev.dv_close = netdev.dv_close;
+	ofw_netdev.dv_ioctl = netdev.dv_ioctl;
+	ofw_netdev.dv_print = netdev.dv_print;
+	ofw_netdev.dv_fmtdev = netdev.dv_fmtdev;
+	/* parsedev is unique to ofwnd */
+	/* match is unique to ofwnd */
+	return (0);
+}
+
+static int
+ofwnd_parsedev(struct devdesc **dev, const char *devspec, const char **path)
+{
+	const char *rem_path;
+	struct ofw_devdesc *idev;
+
+	if (ofw_path_to_handle(devspec, ofw_netdev.dv_name, &rem_path) == -1)
+		return (ENOENT);
+	idev = malloc(sizeof(struct ofw_devdesc));
+	if (idev == NULL) {
+		printf("ofw_parsedev: malloc failed\n");
+		return ENOMEM;
+	};
+	strlcpy(idev->d_path, devspec, min(rem_path - devspec + 1,
+		sizeof(idev->d_path)));
+	if (dev != NULL)
+		*dev = &idev->dd;
+	if (path != NULL)
+		*path = rem_path;
+	return 0;
+}
+
+static bool
+ofwnd_match(struct devsw *devsw, const char *devspec)
+{
+	const char *path;
+
+	return (ofw_path_to_handle(devspec, devsw->dv_name, &path) != -1);
+}
+
+static char *
+ofwnd_fmtdev(struct devdesc *idev)
+{
+	struct ofw_devdesc *dev = (struct ofw_devdesc *)idev;
+
+	return (dev->d_path);
+}
diff --git a/stand/powerpc/ofw/conf.c b/stand/powerpc/ofw/conf.c
index a472faeed97b..c2b28f4fe0f0 100644
--- a/stand/powerpc/ofw/conf.c
+++ b/stand/powerpc/ofw/conf.c
@@ -54,7 +54,7 @@ struct devsw *devsw[] = {
     &ofwdisk,
 #endif
 #if defined(LOADER_NET_SUPPORT)
-    &netdev,
+    &ofw_netdev,
 #endif
     NULL
 };