lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <1269998334.18090.278.camel@macbook.infradead.org>
Date:	Wed, 31 Mar 2010 02:18:54 +0100
From:	David Woodhouse <dwmw2@...radead.org>
To:	davem@...emloft.net
Cc:	netdev@...r.kernel.org
Subject: [PATCH 1/2] phylib: Support phy module autoloading

We don't use the normal hotplug mechanism because it doesn't work. It will
load the module some time after the device appears, but that's not good
enough for us -- we need the driver loaded _immediately_ because otherwise
the NIC driver may just abort and then the phy 'device' goes away.

Instead, we just issue a request_module() directly in phy_device_create().

The device aliases take the form 'phy:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
with a binary representation of the phy_id. This means that the "don't
care" bits of driver's phy_id_mask can be question marks which modprobe
will interpret correctly as wildcards.

So a driver with { .phy_id = 0x02345600, .phy_id_mask = 0x0fffff00 }
will have an alias of phy:????00100011010001010110???????? and will be
loaded whenever any matching phy is created by phy_device_create().

Signed-off-by: David Woodhouse <David.Woodhouse@...el.com>
---
 drivers/net/phy/phy_device.c    |   13 +++++++++++++
 include/linux/mod_devicetable.h |   20 ++++++++++++++++++++
 include/linux/phy.h             |    1 +
 scripts/mod/file2alias.c        |   25 +++++++++++++++++++++++++
 4 files changed, 59 insertions(+), 0 deletions(-)

diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index db17945..b35ec7e 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -149,6 +149,8 @@ EXPORT_SYMBOL(phy_scan_fixups);
 struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id)
 {
 	struct phy_device *dev;
+	char modid[37];
+
 	/* We allocate the device, and initialize the
 	 * default values */
 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
@@ -179,6 +181,17 @@ struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id)
 	mutex_init(&dev->lock);
 	INIT_DELAYED_WORK(&dev->state_queue, phy_state_machine);
 
+#ifdef CONFIG_MODULES
+	/* Request the appropriate module unconditionally. A hotplug
+	   event would have done so anyway. But normal hotplug won't
+	   work for MDIO -- because it relies on the device staying
+	   around for long enough for the driver to get loaded. With
+	   MDIO, the NIC driver will get bored and give up as soon
+	   as it finds that there's no driver _already_ loaded. */
+	sprintf(modid, "phy:" PHYID_FMT, PHYID_ARGS(phy_id));
+	request_module(modid);
+#endif
+
 	return dev;
 }
 EXPORT_SYMBOL(phy_device_create);
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index f58e9d8..0c3e300 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -474,4 +474,24 @@ struct platform_device_id {
 			__attribute__((aligned(sizeof(kernel_ulong_t))));
 };
 
+#define PHY_MODULE_PREFIX	"phy:"
+
+#define PHYID_FMT "%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d"
+#define PHYID_ARGS(_id) \
+	(_id)>>31, ((_id)>>30) & 1, ((_id)>>29) & 1, ((_id)>>28) & 1,	\
+	((_id)>>27) & 1, ((_id)>>26) & 1, ((_id)>>25) & 1, ((_id)>>24) & 1, \
+	((_id)>>23) & 1, ((_id)>>22) & 1, ((_id)>>21) & 1, ((_id)>>20) & 1, \
+	((_id)>>19) & 1, ((_id)>>18) & 1, ((_id)>>17) & 1, ((_id)>>16) & 1, \
+	((_id)>>15) & 1, ((_id)>>14) & 1, ((_id)>>13) & 1, ((_id)>>12) & 1, \
+	((_id)>>11) & 1, ((_id)>>10) & 1, ((_id)>>9) & 1, ((_id)>>8) & 1, \
+	((_id)>>7) & 1, ((_id)>>6) & 1, ((_id)>>5) & 1, ((_id)>>4) & 1, \
+	((_id)>>3) & 1, ((_id)>>2) & 1, ((_id)>>1) & 1, (_id) & 1
+
+
+
+struct phy_device_id {
+	uint32_t phy_id;
+	uint32_t phy_id_mask;
+};
+
 #endif /* LINUX_MOD_DEVICETABLE_H */
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 14d7fdf..f269f1b 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -24,6 +24,7 @@
 #include <linux/mii.h>
 #include <linux/timer.h>
 #include <linux/workqueue.h>
+#include <linux/mod_devicetable.h>
 
 #include <asm/atomic.h>
 
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index 220213e..b412185 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -796,6 +796,27 @@ static int do_platform_entry(const char *filename,
 	return 1;
 }
 
+static int do_phy_entry(const char *filename,
+			struct phy_device_id *id, char *alias)
+{
+	char str[33];
+	int i;
+
+	str[32] = 0;
+
+	for (i = 0; i < 32; i++) {
+		if (!((id->phy_id_mask >> (31-i)) & 1))
+			str[i] = '?';
+		else if ((id->phy_id >> (31-i)) & 1)
+			str[i] = '1';
+		else
+			str[i] = '0';
+	}
+
+	sprintf(alias, PHY_MODULE_PREFIX "%s", str);
+	return 1;
+}
+
 /* Ignore any prefix, eg. some architectures prepend _ */
 static inline int sym_is(const char *symbol, const char *name)
 {
@@ -943,6 +964,10 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
 		do_table(symval, sym->st_size,
 			 sizeof(struct platform_device_id), "platform",
 			 do_platform_entry, mod);
+	else if (sym_is(symname, "__mod_phy_device_table"))
+		do_table(symval, sym->st_size,
+			 sizeof(struct phy_device_id), "phy",
+			 do_phy_entry, mod);
 	free(zeros);
 }
 
-- 
1.6.6.1

-- 
David Woodhouse                            Open Source Technology Centre
David.Woodhouse@...el.com                              Intel Corporation

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ