RFC:new superio proposal

ron minnich rminnich at lanl.gov
Tue May 13 09:36:01 CEST 2003


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




More information about the coreboot mailing list