public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* RFC: bus_type and device_class merge (or partial merge)
@ 2002-12-19 19:36 Adam J. Richter
  2002-12-19 20:37 ` Patrick Mochel
  0 siblings, 1 reply; 7+ messages in thread
From: Adam J. Richter @ 2002-12-19 19:36 UTC (permalink / raw)
  To: mochel; +Cc: linux-kernel

	If there is a more specific mailing list than lkml for discussing
the generic driver model, please feel free to redirect me.

	I'm thinking about trying to embed struct device_class into
struct bus_type or perhaps just eliminate the separate struct
bus_type.  The two structures are almost identical, especially
considering that device_class.devnum appears not to be used by
anything.

struct bus_type {
	char			* name;

	struct subsystem	subsys;
	struct subsystem	drvsubsys;
	struct subsystem	devsubsys;
	struct list_head	devices;
	struct list_head	drivers;

	int		(*match)(struct device * dev, struct device_driver * drv);
	struct device * (*add)	(struct device * parent, char * bus_id);
	int		(*hotplug) (struct device *dev, char **envp, 
				    int num_envp, char *buffer, int buffer_size);
};

struct device_class {
	char			* name;
	u32			devnum;

	struct subsystem	subsys;
	struct subsystem	devsubsys;
	struct subsystem	drvsubsys;
	struct list_head	drivers;
	struct list_head	devices;

	int	(*add_device)(struct device *);
	void	(*remove_device)(struct device *);
	int	(*hotplug)(struct device *dev, char **envp, 
			   int num_envp, char *buffer, int buffer_size);
};


	At first appearance, a bus_type (PCI, USB, etc.) and a
device_class (network devices, input, block devices), may seem like
opposite ends of the device driver abstraction, but really I think
these are basically the same, and, more importantly, there can be many
layers of these interfaces, and the decision about which are bus_types
and which are device_classes is causing unnecessary coplexity.  For
example, SCSI defines both.  SCSI can be a hardware bus, bus it also
needs device_class so that scsi_debug (and eventually scsi generic) can
use the struct interface mechanism.

	If you look at the five places where a struct device_class is
actually defined in 2.5.52, you'll see that either the device_class is
not referenced by anything else or it has no bus type.  So, there
seems to be little use of the distinction.

device_class variable   Referenced elsewhere?           bus_type?

cpu_devclass            No                              system_bus_type
memblk_devclass         No                              system_bus_type
node_devclass           No                              system_bus_type
input_devclass          Yes (mousedev, tsdev)           (None)
shost_devclass          Yes (scsi_debug)                (None)


	Also, merging device_class and bus_type could also enable a
little more consolidation between struct device_interface and struct
device_driver (as with device_class.devnum, device_interface.devnum
does not appear to be used currently).

	Anyhow, I think this could shrink the drivers/base a bit and
make it slightly more understandable.  I'd be interested in knowing if
anyone else is contemplating or developing this or wants to point out
issues to watch out for.

Adam J. Richter     __     ______________   575 Oroville Road
adam@yggdrasil.com     \ /                  Milpitas, California 95035
+1 408 309-6081         | g g d r a s i l   United States of America
                         "Free Software For The Rest Of Us."

^ permalink raw reply	[flat|nested] 7+ messages in thread
* Re: RFC: bus_type and device_class merge (or partial merge)
@ 2002-12-21  9:00 Adam J. Richter
  0 siblings, 0 replies; 7+ messages in thread
From: Adam J. Richter @ 2002-12-21  9:00 UTC (permalink / raw)
  To: mochel; +Cc: linux-kernel

[-- Attachment #1: Type: text/plain, Size: 1005 bytes --]

>If you're interested, I've finished a paper for linux.conf.au on the 
>driver model that should describe the various objects and purposes (much 
>better than the Ottawa paper did). You can find it at: 
>
>http://kernel.org/pub/linux/kernel/people/mochel/doc/lca/driver-model-lca2003.tar.gz

	Thanks.  I've read it now.  Here is a proposed patch.  The
only substantive change is a correction to the misunderstanding about
the risk of bus driver modules being unloaded (you might want to
delete the second paragraph that I added).  I've cc'ed linux-kernel
as others might want to comment that proposed change.

	The other changes are just typos and one TeX quirk (apparentlyd
underscores don't have to be escaped in "verbatim" sections).

-- 
Adam J. Richter     __     ______________   575 Oroville Road
adam@yggdrasil.com     \ /                  Milpitas, California 95035
+1 408 309-6081         | g g d r a s i l   United States of America
                         "Free Software For The Rest Of Us."

[-- Attachment #2: diffs --]
[-- Type: text/plain, Size: 6668 bytes --]

diff -u -r driver-model-lca2003/source/buses.tex driver-model-lca2003.modified/source/buses.tex
--- driver-model-lca2003/source/buses.tex	2002-12-18 09:57:33.000000000 -0800
+++ driver-model-lca2003.modified/source/buses.tex	2002-12-21 00:57:20.000000000 -0800
@@ -211,24 +211,28 @@
 \end{table}
 
 
-There are two caveats of using bus drivers as they are currently
-implemented in the driver model . First, the de facto means of
-referencing a bus driver is via a pointer to its struct
-bus\_type. This implies that the bus drivers must not declare the
-object as 'static' and must be explicitly exported for modules to
-use. An alternative is to provide a helper that searches for and
-returns a bus with a specified name. This is a more desirable solution
-from an abstraction perspective, and will likely be added to the
-model.  
-
-Secondly, bus drivers contain no internal means of preventing their
-module to unload while their reference count is positive. This causes
-the referring object to access invalid memory if the module is
-unloaded. The proposed solution is to use a semaphore, like device
-drivers contain, that bus\_unregister() waits on, and is only unlocked
-when the reference count reaches 0. This will be fixed in the near
-future. 
-
+A bus driver is referenced via a pointer to its struct bus\_type. This
+implies that the bus drivers must not declare the object as 'static'
+and that it must be explicitly exported for modules to use. The reference
+to the bus driver's struct bus\_type means that the bus driver module
+will automatically be loaded by modprobe before any users of that
+bus type.  It also means that the dependency code built into the
+kernel module system will prevent a bus driver from being unloaded
+until all device drivers for that bus are unloaded, elmininating the
+need to reference counting or other locking schemes.
+
+An alternative is to provide a helper that searches for and
+returns a bus with a specified name, which might be useful with,
+for example, a module that contained drivers for PCI and
+MicroChannel versions of a device and one wanted to build a kernel
+with support for both drivers built in and then run this driver
+in a situtation where, say, the MicroChannel bus module was not
+available (for example on a customized ram disk).  However, if this
+were really necessary, then splitting such a module into bus specific
+parts and a ``core'' would reduce kernel footprint and probably result
+in less complexity than implementing run-time lookup of bus types,
+and developing a scheme for rebinding such a driver if, for example,
+the microchannel bus driver is loaded later.
 
 \subsection*{Driver Binding}
 
@@ -339,16 +343,16 @@
 \begin{footnotesize}
 \begin{verbatim}
 
-struct callback\_data {
+struct callback_data {
        struct device * dev;
        char * id;
 };
 
 static int callback(struct device * dev, void * data)
 {
-        struct callback\_data * cd = (struct callback\_data *)data;
-        if (!strcmp(dev->bus\_id,cd->id)) {
-                cd->dev = get\_device(dev);
+        struct callback_data * cd = data;
+        if (!strcmp(dev->bus_id,cd->id)) {
+                cd->dev = get_device(dev);
                 return 1;
         }
         return 0;
@@ -356,15 +360,15 @@
 
 static int caller(void)
 {
-        struct callback\_data data = {
+        struct callback_data data = {
                 .id = "00:00.0",
         };
 
         /* find PCI device with ID 00:00.0  */
-        if(bus\_for\_each\_dev(&pci\_bus\_type,&data,callback)) {
+        if(bus_for_each_dev(&pci_bus_type,&data,callback)) {
                 struct device * dev = data.dev;
                 /* fiddle with device */
-                put\_device(dev);
+                put_device(dev);
         }
 }
 
diff -u -r driver-model-lca2003/source/classes.tex driver-model-lca2003.modified/source/classes.tex
--- driver-model-lca2003/source/classes.tex	2002-12-18 11:53:00.000000000 -0800
+++ driver-model-lca2003.modified/source/classes.tex	2002-12-21 00:07:01.000000000 -0800
@@ -122,10 +122,10 @@
 
 
 Struct device\_class most closely resembles struct bus\_type. Indeed,
-many of the fields of struct device\_class server a similar purpose as
+many of the fields of struct device\_class serve a similar purpose as
 those in struct bus\_type. The subordinate subsystem 'devsubsys' and
 the 'devices' list manage the list of devices registered with the
-class. Like with buses, these structures must exist in parallel, since
+class. As with buses, these structures must exist in parallel, since
 a kobject may not belong to more than one subsystem at a time. The
 same is true of the 'drvsubsys' and 'drivers' list with regard to
 drivers registered with the classes.
diff -u -r driver-model-lca2003/source/devices.tex driver-model-lca2003.modified/source/devices.tex
--- driver-model-lca2003/source/devices.tex	2002-12-18 11:35:06.000000000 -0800
+++ driver-model-lca2003.modified/source/devices.tex	2002-12-20 08:35:20.000000000 -0800
@@ -63,7 +63,7 @@
 
 saved\_state	& void *	& Pointer to saved state for device. \\\hline
 
-dma\_mask	& dma\_mask\_t *	& DMA address mask the device
+dma\_mask	& dma\_mask\_t	& DMA address mask the device
 	can support.\\\hline
 
 \end{tabularx} \\
diff -u -r driver-model-lca2003/source/platform.tex driver-model-lca2003.modified/source/platform.tex
--- driver-model-lca2003/source/platform.tex	2002-12-18 10:33:57.000000000 -0800
+++ driver-model-lca2003.modified/source/platform.tex	2002-12-21 00:08:28.000000000 -0800
@@ -216,7 +216,7 @@
 cause problems, though, when a driver is running on a platform where
 the ports to probe for existence are different. It doesn't even have
 to be different architectures, only different revisions of the same
-platform. Probing undefined I/O ports is dangerous and cause very
+platform. Probing undefined I/O ports is dangerous and causes very
 unpredictable behavior. It can also be a very slow process, and
 significantly delay the boot process.
 
diff -u -r driver-model-lca2003/source/sysfs.tex driver-model-lca2003.modified/source/sysfs.tex
--- driver-model-lca2003/source/sysfs.tex	2002-12-18 09:57:33.000000000 -0800
+++ driver-model-lca2003.modified/source/sysfs.tex	2002-12-20 08:34:42.000000000 -0800
@@ -74,7 +74,7 @@
 sysfs has been a standard part of the Linux kernel as of version
 2.5.45. It has existed under a different name (driverfs or ddfs) since
 kernel version 2.5.2. The de-facto standard mount point for sysfs is a
-new directory named '/sys'. It may be mounted from user pace by doing:
+new directory named '/sys'. It may be mounted from user space by doing:
 
 
 \begin{alltt}

^ permalink raw reply	[flat|nested] 7+ messages in thread
* Re: RFC: bus_type and device_class merge (or partial merge)
@ 2002-12-21 10:43 Adam J. Richter
  0 siblings, 0 replies; 7+ messages in thread
From: Adam J. Richter @ 2002-12-21 10:43 UTC (permalink / raw)
  To: mochel; +Cc: linux-kernel

On Thu, 19 Dec 2002 22:29:39 -0600 (CST), Patrick Mochel wrote:
>> 	A philosophical musing is not substitute for identifying real
>> technical advantages or disadvantages, but thanks for the response.

>Ouch. 

	Sorry for the harsh tone.  For what it's worth, I advocate the
generic device model.  For example, I recently posted a proposed port
of pa-risc devices to it (although it looks like it will not be
integrated because the developers do not like struct kobject and
subsystem being so big).


>> 	If my proposed changes shrink kernel memory footprint, improve
>> code maintainability, allow multiple drivers per device (e.g., scsi
>> generic and scsi disk), users will be better off with those advantages
>> than being lost in a doctrine for which they've lost track of the benefits.

>You're trying to pinch pennies with the footprint you're talking about. 
>The extra structure definition costs nothing, and the code to interface 
>those objects with the other driver model objects is trivial.

	True, but drivers/base is mandatory for everything including
wristwatch implementations, and these things add up to the point where
they can tip the balance in favor of VxWorks et al, so I think these
little optimizations are often worthwhile, even if we're only talking
about 2kB (text+data size of class.o).  In general, if you want small
code, you need to have the discipline to go after lots of little
bloats.


>Plus, you'd be overloading the object to behave differently depending on
>how it was referenced, causing more code.  That certainly wouldn't improve
>code maintainability.

	Huh?  I'd like to understand what you mean in that first
sentence.  Can you walk through a hypothetical example?  I expect the
changes that I have in mind to decrease overall code size (even if
only slightly).

	More importantly, I expect the changes that I have in mind
to reduce the total amount of code that needs to be maintained and
to make it easier to write other facilities that use the generic
device layer (see below for examples).


>A device belongs to exactly one bus type and exactly one class type.

	I have a Radeon All-In-Wonder 7500 card in my livingroom.
It appears as a single PCI device in lspci, but has the functionality
of three different device_classes (imagine these things ported to the
driver model):
			- frambuffer_devclass
			- video4linux_devclass
			- audio_devclass

	From this example, it seems to me that that one device does
not necessarily belong to exactly one devclass, but I think that can
be made true of each struct intf_data under your scheme (under my
approach struct intf_data would be replaced by struct device for
another bus_type, such as netdevice_bus_type or gendisk_bus_type).



>This 
>is easy to express. If you combine the objects, you either reference each 
>instance explicitly, kinda like they are now,

	I don't understand this clause.

>or you represent it in some 
>list, which will complicate the existing code immensely.

>What problem would that solve?

	Reducing the complexity of scsi-generic, scsi-debug, usbdevfs,
etc. by allowing them to use the rendezvous code of drivers/base, as
measured, say, in line count of these individual facilities and total
kernel line count.  I believe I know how to do this without changing
the source code of regular "exclusive" drivers.


>How would that allow you to bind multiple drivers to a device?

	I imagine combining device_driver and device_interface in a
way that more resembles device_interface.

	Something like this (maybe convert to kobject/subsystem for
sysfs support):

struct device_driver {
	...
	int	share_dev : 1;
};

/* Note that a driver could register multiple nexi for the
   same <device,driver> pair but different interfaces (e.g., scsi_disk,
   scsi_generic). */
struct dev_drv_nexus {	/* Replaces intf_data */
	struct device_driver	* driver;
	struct device		* dev;
	void			* driver_data;
	struct list_head	same_dev, same_driver;
};

sturct device {
	/* Delete device.driver, device.driver_data. */

	/* A maximum of one driver with share_dev==0 can be bound to a
	   device, and it must always be the first device on the list
	   (share_dev==1 drivers are added at the tail of the list;
	   share_dev==0 drivers are added at the front of the list). */
	struct subsystem	nexi;
};

extern struct dev_drv_nexus *dev_unshared_nexus(struct device *dev)


static inline struct nexus *dev_unshared_nexus(struct device *dev)
{
	struct dev_drv_nexus *nexus;
	BUG_ON(list_empty(&dev->nexi));
	nexus = list_entry(dev->nexi->next, struct nexus, same_dev);
	BUG_ON(nexus->driver->share_dev);
	return nexus;
}

/* Only for use by drivers that have share_dev==0 */
static inline void *dev_get_drvdata(struct device *dev)
{
	return dev_unshared_nexus(dev)->driver_data;
}

/* Only for use by drivers that have share_dev==0 */
static inline void dev_get_drvdata(struct device *dev, void *driver_data)
{
	dev_unshared_nexus(dev)->driver_data->driver_data = driver_data;
}




>Why would you want to do that anyway? 

>To support scsi-generic?

	That's one example, yes.

>I've talked with SCSI people before about this. 
>It's bad to treat it as a driver, because it causes the core to special 
>case these wacky instances where you have an extension of the bus driver 
>apply to each device registered with it. I've gotten verbal confirmation 
>that scsi-generic will change in this regard, and I've offered to provide 
>hooks to make this easier to express.

	From this message by Mike Anderson on November 7, I think what
you only heard a reflection of what you said because what you said
wasn't really understood:

	http://marc.theaimsgroup.com/?l=linux-scsi&m=103669541704163&w=2


>For the record, both USB and PCI do similar things. USB creates procfs
>entries, and can create device nodes.

	Yes, these are other, similar examples.  I would like to be
able to load and unload usbdevfs through the generic driver API.


>IIRC, USB makes an explicit call to
>the function that does this. PCI makes an explicit call to create procfs 
>entries for each PCI device. They could all be implemented as 'drivers' 
>but it doesn't make sense to overload the objects to do it this way.

	I don't understand what you mean by "doesn't make sense."  If
you could express your point in terms of underlying advantages
(source code size, speed, memory footprint, etc.) it will save you
iterations of email.


>> >They're not the same, though. They may be similar, but they are 
>> >fundamentally different. 
>> 
>> 	There are also differences between USB and PCI, but that
>> doesn't mean that the part that is handled by drivers/base has to be
>> different.  The question is whether having separate implementations
>> for a set of differences make the code smaller, faster, more
>> functional, or delivers other real benefits that tip the trade-off.

>Why? Why try to micro-optimize the core now?

	Because it can be done in less programmer time now before more
code is ported to it, and, more importantly, it would enable or simplify
a number of facilities that I want to add.


>You'll gain much more by 
>converting bus and class drivers to use the driver model objects, and 
>reducing the replication in the dusty corners of the kernel. 

>> 	Perhaps it would help you to understand the impetus that made
>> me think about this.  I want to have a mechanism for race-free module
>> unloading without a new lowest level locking primitive (i.e., just by
>> using rw_semaphore).  To make its use transparent for most cases, I
>> want add a field to struct device_driver and add a couple of lines to
>> {,un}register_driver, and I see that if I have to duplicate this
>> effort if I want the same thing for, say, converting filesystems to
>> use the generic driver interface.  I don't see that duplication buying
>> any real improvement in speed, kernel footprint, source code size,
>> etc.  In other words, having two separate interfaces makes it harder
>> to write other facilities that are potentially generic to
>> driver/target rendezvous.

>Fine. That would be nice. You definitely have good intentions, but there 
>is much more work to be done, that is far less glamorous, that I am 
>concerned with. 

	If you see a long time horizon on one what I want to do, it's
only from maintainer inertia.  I'm not predicating my plans on any
maintainer doing more than integrating patches, or any other deveoper
doing more than occasionally reporting their experiences.  I have
posted some pseudo-code for this and several other facilities that
would rely on the genericness of drivers/base code:

Pseudo-code for raceless module unloading without a new locking primitive
(would have to duplicate for device_driver and device_interface):
	http://marc.theaimsgroup.com/?l=linux-kernel&m=103773401411324&w=2

Patch for preallocating dev->driver_private for many devices, mostly to
conslidate untested error legs (would have to duplicate for
device_driver and device_interface):
	http://marc.theaimsgroup.com/?l=linux-kernel&m=103626558708431&w=2

Likewise for the static DMA consistent memory area (might duplicate for
device_driver and device_interface or do without for device_interface):
	 http://marc.theaimsgroup.com/?l=linux-kernel&m=103636338527053&w=2

Pseudo-code for string-based generic device ID matching (would have
to duplicate for device_driver nd device_interface if things like
filesystems use device_interface rather than device_driver):
	http://marc.theaimsgroup.com/?l=linux-kernel&m=103828651528556&w=2


	Duplicating these facilities for struct device_driver and
struct device_interface adds unnecessarily to source and object size.
Also, if any similar facility is developed that wants to use multiple
operands that could be bus_type/device_classs or
device_driver/device_interface, then the size of its API may have
to grow exponentially.

	This is just stuff that I want to do imminently.  What other
people want to do or might want to do in the near future is probably
larger.  I think the only reason that we don't yet see many new
abstractions that use the generic driver code is because it's new.


>> >Consolidation is possible, but I would not recommend doing it by merging
>> >the structures. Look for other ways to create common objects that the two
>> >can share.
>> 
>> 	I'm thinking about this.  I just wonder if there would be any
>> remaining fields that would not be common. 

>Even if there are not, they have different purposes, and different 
>semantics for dealing with them. Please do not play God on them, they are 
>there for specific purposes.

	"Purpose" just refers to someone's state of mind at some point
in the past.  The optimal technical trade-offs are generally not
determined by that, and making those trade-offs is not "playing God",
even when it involves editing code that you wrote.  So far, you have
not identified any real benefit that this duplication delivers, much
less enough to tip the balance.

[...]
>I may not know the low-level details about many things, but
>I've spent enough of the last two years comparing and analyzing the
>behavior of drivers to mean it when I say I will not consider patches of 
>that type. :)

	Sophomore. :)

	Seriously, though, if embed a common structure in device_class
and bus_type and consolidate the code that way, that may suffice, at
least if I can add the equivalent of struct intf_data for device
drivers so that certain carefully written drivers to be allowed to
attach to devices that already have another device (and perhaps the
equivalent of intf_data might facilitate support for things like my
ATI All-In-Wonder conglomeration).

Adam J. Richter     __     ______________   575 Oroville Road
adam@yggdrasil.com     \ /                  Milpitas, California 95035
+1 408 309-6081         | g g d r a s i l   United States of America
                         "Free Software For The Rest Of Us."

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2002-12-21 10:35 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2002-12-19 19:36 RFC: bus_type and device_class merge (or partial merge) Adam J. Richter
2002-12-19 20:37 ` Patrick Mochel
2002-12-19 22:44   ` Adam J. Richter
2002-12-19 23:37     ` Greg KH
2002-12-20  4:29     ` Patrick Mochel
  -- strict thread matches above, loose matches on Subject: below --
2002-12-21  9:00 Adam J. Richter
2002-12-21 10:43 Adam J. Richter

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox