Abstract: The superio architecture for linuxbios has worked for the last 2 years but is being stretched to the limit by the changes in superio chips. The architecture depended on superio resources being relatively constant between chips, but this assumption no longer holds. In this document we propose several alternatives and solicit comments.
Overview: The superio architecture in linuxbios was developed over time, and modified as circumstances required. In the beginning it was relatively simple and assumed only one superio per mainboard. The latest version allows an arbitrary number of superios per mainboard, and allows complete specification of the superio base I/O address along with the specification of reasonable default valures for both the base I/O address and the superio parameters such as serial enable, baud rate, and so on.
Specification of superio control parameters is done by a configuration line such as:
nsuperio sis/950 com1={1} floppy=1 lpt=1
This fragment sets the superio type to sis/950; sets com1, floppy, and lpt to enabled; and leaves the defaults to com1 (baud rate, etc.) to the default values.
While it is not obvious, these configuration parameters are fragments of a C initializer. The initializers are used to build a statically initialized structure of this type:
struct superio { struct superio_control *super; // the ops for the device. unsigned int port; // if non-zero, overrides the default port // com ports. This is not done as an array (yet). // We think it's easier to set up from python if it is not an // array. struct com_ports com1, com2, com3, com4; // DMA, if it exists. struct lpt_ports lpt1, lpt2; /* flags for each device type. Unsigned int. */ // low order bit ALWAYS means enable. Next bit means to enable // LPT is in transition, so we leave this here for the moment. // The winbond chips really stretched the way this works. // so many functions! unsigned int ide, floppy, lpt; unsigned int keyboard, cir, game; unsigned int gpio1, gpio2, gpio3; unsigned int acpi,hwmonitor; };
These structures are, in turn, created and statically initialized by a config-tool-generated structure that defines all the superios. This file is called nsuperio.c, is created for each mainboard you build, only appears in the build directory, and looks like this:
=== extern struct superio_control superio_winbond_w83627hf_control;
struct superio superio_winbond_w83627hf= { &superio_winbond_w83627hf_control, .com1={1}, .com2={1}, .floppy=1, .lpt=1, .keyboard=1, .hwmonitor=1};
struct superio *all_superio[] = {&superio_winbond_w83627hf, };
unsigned long nsuperio = 1; ===
This example shows a board with one superio (nsuperio). The superio consists of a winbond w83627hf, with com1, com2, floppy, lpt, keyboard, and hwmonitor enabled. Note that this structure also allows for over-riding the default superio base, although that capability is rarely used.
The control structure is used to define how to access the superio for purposes of control. It looks like this: === struct superio_control { void (*pre_pci_init)(struct superio *s); void (*init)(struct superio *s); void (*finishup)(struct superio *s); unsigned int defaultport; /* the defaultport. Can be overridden * by commands in config */ // This is the print name for debugging char *name; }; ===
There are three methods for stages of hardwaremain. First is pre_pci_init (for chips like the acer southbridge that require you to enable some resources BEFORE pci scan); init, called during the 'middle' phase of hardwaremain; and finishup, called before the payload is loaded.
This approach was inspired by and borrows heavily on the Plan 9 kernel configuration tools.
The problem:
When the first version of the superio structure came out it was much smaller. It has grown and in the limit this structure is the union of all possibly superio chips. Obviously, in the long term, this is not practical: we can not anticipate all possible superio chips for all time.
The common PC BIOS solution to this type of problem is to continue with binary structures but add version numbers to them, so that all code that uses a given structure has to check the version number. Personally, I find this grotesque and would rather not work this way.
Using textual strings for configuration is something I find far more attractive. Plan 9 has shown that this approach has no real limits and suffices for configuration tasks. The Linux kernel does more limited use of strings for configuration, but still depends on them. Strings are easier to read and work with than binary structures, and more important, a lot easier to deal with when things start going wrong.
The proposed solution:
What follows are three possible ideas for specifying superio resources and their settings.
A common part of the new idea is to eliminate the common superio structure, due to the many variations in chips, and make it invisible outside a given superio source file -- the superio structure is now private to a given superio. Thus, sis/950/superio.c would contain its own superio structure definitions, and also might contain more than once instance of these structures (consider a board with 2 sis 950 chips).
The control structure would change as follows: struct superio_control { int (*create)(struct superio *s); void (*pre_pci_init)(struct superio *s); void (*init)(struct superio *s); void (*finishup)(struct superio *s); unsigned int defaultport; /* the defaultport. Can be overridden * by commands in config */ // This is the print name for debugging char *name; };
I.e. we add a new function for creating the superio.
Communication of superio settings from linuxbios to the superio would be via textual strings. The superio structure becomes this:
struct superio { struct superio_control *super; // the ops for the device. unsigned int port; // if non-zero, overrides the default port struct configuration *config; };
So now the question becomes, what is the configuration structure? There are several choices. The simplest, from my point of view, are keyword-value pairs: struct configuration { const char *keyword; const char *value; };
These get filled in by the config tool as before. The linuxbios libary can then provide a generic parsing function for the superios to use.
The remaining question is how should the superio command look in freebios2?
superio sis/950 "com1=115200,8n1 lpt=1 com2=9600"
or
superio sis/950 "com1baud=115200 lpt=1 com1chars=8n1"
or
superio sis/950 ((com1 115200 8n1) (lpt 1))
So, my questions:
1. Does this new scheme look workable. If not, what needs to change? 2. What should the 'struct configuration' be? does keyword/value work? 3. what should the superio command look like?
Comments welcome.
I'd like to adopt this "RFC" approach for freebios2 as much as we can. There was a lot of give-and-take in the early days of linuxbios about structure and it proved useful. There's a lot that will start happening in freebios2 now, and we need to try to make sure it will work for everyone.
Those of you who are doing mainboards, please look at freebios2 and see how it looks for you. There's a lot of good work that has been done (not by me so far, thanks Eric and Stefan), and more that needs to be done. Consider trying out romcc as an "assembly code killer". See how it fits together and if you can work with it or need changes. Bring comments back to this list.
thanks
ron
On Tue, May 13, 2003 at 08:11:46AM -0600, ron minnich wrote: [..snip..]
The remaining question is how should the superio command look in freebios2?
superio sis/950 "com1=115200,8n1 lpt=1 com2=9600"
The way to go! As long as keywords are documented just like in the kernel, this is excellent! Just the fact that people may recognize this approach from the kernel is IMHO reason enough.
superio sis/950 "com1baud=115200 lpt=1 com1chars=8n1"
Unneccessarily lengthy and 8n1 is related to 115200 so no need to separate them.
superio sis/950 ((com1 115200 8n1) (lpt 1))
Eww, lisp! Hehe. :)
So, my questions:
- Does this new scheme look workable. If not, what needs to change?
I think it looks very good and quite scalable. IANA LinuxBIOS expert though, so I might be overlooking things that are missing or unworkable.
- What should the 'struct configuration' be? does keyword/value work?
I think so. Then leave value parsing up to each module, and maybe create a couple of common primitives that can be used. How much is left to each superio also depends on the diversity of keyword/value pairs.
- what should the superio command look like?
See above.
//Peter
ron minnich wrote:
Abstract: The superio architecture for linuxbios has worked for the last 2 years but is being stretched to the limit by the changes in superio chips. The architecture depended on superio resources being relatively constant between chips, but this assumption no longer holds. In this document we propose several alternatives and solicit comments.
Another change in super i/o resources is the use of a microprocessor rather than a hardwired super i/o chip. In laptops and mobile devices the current and future trend is to use a 16 bit cpu with I/O ports (PS2, serial, parallel, keyboard scan, GPIO, SMbus) that interfaces to the chipset using LPC bus. The 16 bit cpu has internal flash for the firmware that may be reprogrammed in circuit via the LPC and/or other ports. This cpu is used as a system power keyboard controller as well as super i/o.
We have been working a bit on having open firmware for these as well.
The new super i/o structure of freebios2 should also account for these changes.
--Bari
On Tue, 13 May 2003, Bari Ari wrote:
The new super i/o structure of freebios2 should also account for these changes.
any suggestions on how this should look? I can see a src/superio/<vendor>/microprocessor, to which you pass all these parameters, and which talks to the microprocessor to set them up. Would that be sufficient? What new parameters would it need?
ron
ron minnich wrote:
On Tue, 13 May 2003, Bari Ari wrote:
The new super i/o structure of freebios2 should also account for these changes.
any suggestions on how this should look? I can see a src/superio/<vendor>/microprocessor, to which you pass all these parameters, and which talks to the microprocessor to set them up. Would that be sufficient? What new parameters would it need?
Besides just setting a few bits in registers to config the super i/o, one now has the option/ability to reload the binary firmware into the flash memory of the super i/o to customize the board. The binary may be 64KB for some cpu based super i/o's.
Some examples of cpu based super i/o's
http://www.renesas.com/eng/products/mpumcu/16bit/h8s/2100/index.html
Bari
The new super i/o structure of freebios2 should also account for these changes.
any suggestions on how this should look? I can see a src/superio/<vendor>/microprocessor, to which you pass all these parameters, and which talks to the microprocessor to set them up. Would that be sufficient? What new parameters would it need?
Besides just setting a few bits in registers to config the super i/o, one now has the option/ability to reload the binary firmware into the flash memory of the super i/o to customize the board. The binary may be 64KB for some cpu based super i/o's.
Some examples of cpu based super i/o's
http://www.renesas.com/eng/products/mpumcu/16bit/h8s/2100/index.html
In other words, it is an computer inside of computer.
in fact it seems to sort of change the whole firmware padagrim. we have
main pc bios PCI video : video bios super io : standalone firmware some pci card : pci bios.
what's significant here is that the superio is compiled with the super IO's cpu as target rather than main cpu being the compilation target.
As time go on I expect there to be more subcompoents go like this.
The very fact alone that the compilation target is differnet suggest it being removed from pc linuxbios main to large degree.
Adam, who actually did go over that 1000 page pdf.
Bari Ari bari@onelabs.com writes:
ron minnich wrote:
On Tue, 13 May 2003, Bari Ari wrote:
The new super i/o structure of freebios2 should also account for these changes.
any suggestions on how this should look? I can see a src/superio/<vendor>/microprocessor, to which you pass all these parameters, and which talks to the microprocessor to set them up. Would that be sufficient? What new parameters would it need?
Besides just setting a few bits in registers to config the super i/o, one now has the option/ability to reload the binary firmware into the flash memory of the super i/o to customize the board. The binary may be 64KB for some cpu based super i/o's.
Some examples of cpu based super i/o's
http://www.renesas.com/eng/products/mpumcu/16bit/h8s/2100/index.html
Actually if you look up the original keyboard controller it was also a cpu. Though a very limited one.
If you look you can find cpus in some of the strangest places.
As for the configuration process it is largely irrelevant. The important infrastructure piece is the call graph and some small hooks to allow the same drivers to be used in different hardware configurations.
Once your driver gets control it can do whatever makes sense. And that 64K blob I suspect is something you can just setup to be compiled in. If that is a reasonable way to do things.
Eric
On Tue, 13 May 2003, Bari Ari wrote:
Besides just setting a few bits in registers to config the super i/o, one now has the option/ability to reload the binary firmware into the flash memory of the super i/o to customize the board. The binary may be 64KB for some cpu based super i/o's.
This is like the case of the microcode update. I think we can accomodate this case.
ron
ron minnich wrote:
On Tue, 13 May 2003, Bari Ari wrote:
Besides just setting a few bits in registers to config the super i/o, one now has the option/ability to reload the binary firmware into the flash memory of the super i/o to customize the board. The binary may be 64KB for some cpu based super i/o's.
This is like the case of the microcode update. I think we can accomodate this case.
Just so this doesn't get left out or limited somehow ;-)
These are also being used in servers to take care of power and thermal management.
--Bari
I'm going to rewrite that RFC, with a proposal this time, taking into account your and Eric's comments.
ron
ron minnich wrote:
Abstract: The superio architecture for linuxbios has worked for the last 2 years but is being stretched to the limit by the changes in superio chips. The architecture depended on superio resources being relatively constant between chips, but this assumption no longer holds. In this document we propose several alternatives and solicit comments.
Another change in super i/o resources is the use of a microprocessor rather than a hardwired super i/o chip. In laptops and mobile devices the current and future trend is to use a 16 bit cpu with I/O ports (PS2, serial, parallel, keyboard scan, GPIO, SMbus) that interfaces to the chipset using LPC bus. The 16 bit cpu has internal flash for the firmware that may be reprogrammed in circuit via the LPC and/or other ports. This cpu is used as a system power keyboard controller as well as super i/o.
We have been working a bit on having open firmware for these as well.
The new super i/o structure of freebios2 should also account for these changes.
--Bari
Greetings,
That sounds interesting can you point me to a mainboard that uses one of those?
G'day, sjames
On Tue, 13 May 2003, Bari Ari wrote:
Another change in super i/o resources is the use of a microprocessor rather than a hardwired super i/o chip. In laptops and mobile devices the current and future trend is to use a 16 bit cpu with I/O ports (PS2, serial, parallel, keyboard scan, GPIO, SMbus) that interfaces to the chipset using LPC bus. The 16 bit cpu has internal flash for the firmware that may be reprogrammed in circuit via the LPC and/or other ports. This cpu is used as a system power keyboard controller as well as super i/o.
We have been working a bit on having open firmware for these as well.
The new super i/o structure of freebios2 should also account for these changes.
--Bari
Linuxbios mailing list Linuxbios@clustermatic.org http://www.clustermatic.org/mailman/listinfo/linuxbios
mostly laptops. for example
IBM ThinkPad T23 IBM ThinkPad T30
On Wed, 14 May 2003, steven james wrote:
Greetings,
That sounds interesting can you point me to a mainboard that uses one of those?
G'day, sjames
On Tue, 13 May 2003, Bari Ari wrote:
Another change in super i/o resources is the use of a microprocessor rather than a hardwired super i/o chip. In laptops and mobile devices the current and future trend is to use a 16 bit cpu with I/O ports (PS2, serial, parallel, keyboard scan, GPIO, SMbus) that interfaces to the chipset using LPC bus. The 16 bit cpu has internal flash for the firmware that may be reprogrammed in circuit via the LPC and/or other ports. This cpu is used as a system power keyboard controller as well as super i/o.
We have been working a bit on having open firmware for these as well.
The new super i/o structure of freebios2 should also account for these changes.
--Bari
Linuxbios mailing list Linuxbios@clustermatic.org http://www.clustermatic.org/mailman/listinfo/linuxbios
ron minnich rminnich@lanl.gov writes:
Abstract: The superio architecture for linuxbios has worked for the last 2 years but is being stretched to the limit by the changes in superio chips. The architecture depended on superio resources being relatively constant between chips, but this assumption no longer holds. In this document we propose several alternatives and solicit comments.
Overview: The superio architecture in linuxbios was developed over time, and modified as circumstances required. In the beginning it was relatively simple and assumed only one superio per mainboard. The latest version allows an arbitrary number of superios per mainboard, and allows complete specification of the superio base I/O address along with the specification of reasonable default valures for both the base I/O address and the superio parameters such as serial enable, baud rate, and so on.
Specification of superio control parameters is done by a configuration line such as:
nsuperio sis/950 com1={1} floppy=1 lpt=1
This fragment sets the superio type to sis/950; sets com1, floppy, and lpt to enabled; and leaves the defaults to com1 (baud rate, etc.) to the default values.
While it is not obvious, these configuration parameters are fragments of a C initializer. The initializers are used to build a statically initialized structure of this type:
struct superio { struct superio_control *super; // the ops for the device. unsigned int port; // if non-zero, overrides the default port // com ports. This is not done as an array (yet). // We think it's easier to set up from python if it is not an // array. struct com_ports com1, com2, com3, com4; // DMA, if it exists. struct lpt_ports lpt1, lpt2; /* flags for each device type. Unsigned int. */ // low order bit ALWAYS means enable. Next bit means to enable // LPT is in transition, so we leave this here for the moment. // The winbond chips really stretched the way this works. // so many functions! unsigned int ide, floppy, lpt; unsigned int keyboard, cir, game; unsigned int gpio1, gpio2, gpio3; unsigned int acpi,hwmonitor; };
These structures are, in turn, created and statically initialized by a config-tool-generated structure that defines all the superios. This file is called nsuperio.c, is created for each mainboard you build, only appears in the build directory, and looks like this:
=== extern struct superio_control superio_winbond_w83627hf_control;
struct superio superio_winbond_w83627hf= { &superio_winbond_w83627hf_control, .com1={1}, .com2={1}, .floppy=1, .lpt=1, .keyboard=1, .hwmonitor=1};
struct superio *all_superio[] = {&superio_winbond_w83627hf, };
unsigned long nsuperio = 1;
This last bit I really like because it falls out cleanly. Somewhere you need to specify what you take and what is a better definition than a structure definition.
And just generating a structure initializer from a few well defined rules fells very clean.
Structure initializes start getting wordy so we probably do not want to too much by hand. But with a convenient syntax for our purposes I don't see why we can't do something nice and clean.
This example shows a board with one superio (nsuperio). The superio consists of a winbond w83627hf, with com1, com2, floppy, lpt, keyboard, and hwmonitor enabled. Note that this structure also allows for over-riding the default superio base, although that capability is rarely used.
The control structure is used to define how to access the superio for purposes of control. It looks like this: === struct superio_control { void (*pre_pci_init)(struct superio *s); void (*init)(struct superio *s); void (*finishup)(struct superio *s); unsigned int defaultport; /* the defaultport. Can be overridden * by commands in config */ // This is the print name for debugging char *name; }; ===
There are three methods for stages of hardwaremain. First is pre_pci_init (for chips like the acer southbridge that require you to enable some resources BEFORE pci scan); init, called during the 'middle' phase of hardwaremain; and finishup, called before the payload is loaded.
This approach was inspired by and borrows heavily on the Plan 9 kernel configuration tools.
The problem:
When the first version of the superio structure came out it was much smaller. It has grown and in the limit this structure is the union of all possibly superio chips. Obviously, in the long term, this is not practical: we can not anticipate all possible superio chips for all time.
The common PC BIOS solution to this type of problem is to continue with binary structures but add version numbers to them, so that all code that uses a given structure has to check the version number. Personally, I find this grotesque and would rather not work this way.
Version numbers are the wrong thing. Devices supporting multiple interfaces and a way to query which interface you have is much cleaner. In this case it is just data but still.
Using textual strings for configuration is something I find far more attractive. Plan 9 has shown that this approach has no real limits and suffices for configuration tasks. The Linux kernel does more limited use of strings for configuration, but still depends on them. Strings are easier to read and work with than binary structures, and more important, a lot easier to deal with when things start going wrong.
The proposed solution:
What follows are three possible ideas for specifying superio resources and their settings.
A common part of the new idea is to eliminate the common superio structure, due to the many variations in chips, and make it invisible outside a given superio source file -- the superio structure is now private to a given superio. Thus, sis/950/superio.c would contain its own superio structure definitions, and also might contain more than once instance of these structures (consider a board with 2 sis 950 chips).
The control structure would change as follows: struct superio_control { int (*create)(struct superio *s); void (*pre_pci_init)(struct superio *s); void (*init)(struct superio *s); void (*finishup)(struct superio *s); unsigned int defaultport; /* the defaultport. Can be overridden * by commands in config */ // This is the print name for debugging char *name; };
I.e. we add a new function for creating the superio.
Communication of superio settings from linuxbios to the superio would be via textual strings. The superio structure becomes this:
struct superio { struct superio_control *super; // the ops for the device. unsigned int port; // if non-zero, overrides the default port struct configuration *config; };
So now the question becomes, what is the configuration structure? There are several choices. The simplest, from my point of view, are keyword-value pairs: struct configuration { const char *keyword; const char *value; };
These get filled in by the config tool as before. The linuxbios libary can then provide a generic parsing function for the superios to use.
The remaining question is how should the superio command look in freebios2?
superio sis/950 "com1=115200,8n1 lpt=1 com2=9600"
or
superio sis/950 "com1baud=115200 lpt=1 com1chars=8n1"
or
superio sis/950 ((com1 115200 8n1) (lpt 1))
So, my questions:
- Does this new scheme look workable. If not, what needs to change?
A) The problem domain is two small it should address all devices and configuration for interrupt lines.
We need to address the relative routes on how to get to devices.
In particular we need a way to specify which configuration goes to which devices. I.e. how do you configure a board when someone places 2 identical superio on the board. 2 identical nics are already common. In some contexts both the pci bus and the pci function are variable.
- What should the 'struct configuration' be? does keyword/value work?
My personal preference is actually much closer to the current scheme. But instead of 1 structure include things like struct com_ports n times, and struct lpt_ports n times. Have a linked list of the structures you need with a common header something like:
struct config_header { struct config_header *next; int config_type; };
And then we can have things like: #define SERIAL_CONFIG 1 struct serial_struct { struct config_header header; int baud_rate; };
- what should the superio command look like?
I'm not certain and how to specify the pieces in the config file. We need to specify both the device tree, and parameters for each device.
Possibly something like: (dev cpu0 (apic (initial_id 0))) (dev cpu1 (apic (initial_id 1))) (dev E7500 (bus pci0 (dev ich3 (bus lpc0 (dev sio0 (serial baud 115200) ) ) ) (dev pci-slot-1 (irqa 1) (irqb 2) (irqc 3) (irqd 4)) (dev pci-slot-2 (irqa 2) (irqb 3) (irqc 4) (irqd 1)) (dev pci-slot-3 (irqa 3) (irqb 4) (irqc 1) (irqd 2)) (dev pci-slot-4 (irqa 4) (irqb 1) (irqc 2) (irqd 3)) (dev pci-slot-5 (irqa 1) (irqb 2) (irqc 3) (irqd 4)) (dev pci-slot-6 (irqa 2) (irqb 3) (irqc 4) (irqd 1)) ) )
Where we have a shorthand easy way to specify devices and their configuration but at the same time have something that will generate structure initializers.
What I have is still way off but it begins to describe the idea. There is a lot of information that needs to be specified, and a lot of it has standardized components so it should use the same description from piece to piece.
I'd like to adopt this "RFC" approach for freebios2 as much as we can. There was a lot of give-and-take in the early days of linuxbios about structure and it proved useful. There's a lot that will start happening in freebios2 now, and we need to try to make sure it will work for everyone.
I mostly agree. But so far this is still a very formal request for discussion. A RFC contains a believed complete specification for an implementation. We need something similar for our external interfaces as well.
Look at hardwaremain in the freebios2 tree. I want that to be the interface that initializes everything and if anything I want to make it more general and simpler than it is now.
Eric