Sun Java Solaris Communities My SDN Account Join SDN
 
Documentation

General FCode FAQs

Please post any updates, additions, or questions on the developer forums at http://forum.sun.com

1.  Why does the amount of dictionary space vary with each version of OpenBoot?
2.  Is there a method of calculating exactly how much dictionary space is available per bus or plug-in slot?
3. My fcode driver incorrectly specifies the devices "reg" property or is missing some of the values of the "reg" property. In SunOS 4.x, I used to be able to work around this by manipulating the data in the dev_info structure. How can I fix this in SunOS 5.x?
4.  My fcode driver only creates a "name" property and doesn't create any "reg" property at all. Can I use "registers" wildcarding?
 

1. Why does the amount of dictionary space vary with each version of OpenBoot?

This happens because the amount of dictionary space must be fixed at compile time, and OBP necessarily uses that resource.  The "user available" dictionary space will vary for each new release because OBP may implement some new functionality, thus leaving *less* space for plug-in devices, but new releases may also employ more efficient methods of implementing some function than in previous releases, thus leaving *more* space for plug-in cards.
 

2. Is there a method of calculating exactly how much dictionary space is available per bus or plug-in slot? 

Dictionary space is not allocated per bus or slot, it is one large pool which is consumed on a "as probed" basis.  If your card is the only one in the system and you are running out of dictionary space then there is a major problem with the board/FCode.  However, if your card is one of the last to be probed, then it's possible that other cards are consuming "normal" amounts of the dictionary and that your card is just trying to get a little more than is left over.  It is also possible that the FCode on your card could be written inefficiently such that you could reduce its dictionary space requirements by some margin.  Below are a few suggestions on how you might reduce your dictionary usage;

  • Reduce your use of 'external' or 'headered' words wherever possible. (Instead use 'headerless'.)  Note that by default you will get 'headered' words.  If you think you'd like to keep a word for debug purposes only, but it's not normally needed, make it 'headered', thus you can see it when you need it if you set the "fcode-debug?" nvram var to 'true'.
  • Use instance definitions wherever possible.  It's probable that some   of the definitions may have to be left global, but judicious use of instance definitions of  'variable', 'constant', 'value' and other defining words will help.
     
  • Remove "frivolous" definitions.  For example, if there were many places in your code where you are adding 2 to another number, and you decided to create a word like : 2+ ( n1 -- sum ) 2 + ; , that might make sections of your code appear more compact, but the defined word may be using dictionary space.
     
  • Don't create properties that are unneeded.
     
  • Don't change properties after they're created, unless necessary.
     
  • If a property is to be created once, and never changed later, it's better to create it "in-line", rather than creating a word like "create-props" which is called later to create the properties.
     
3. My fcode driver incorrectly specifies the device's "reg" property or is missing some of the values of the "reg" property. In SunOS 4.x, I used to be able to work around this by manipulating the data in the dev_info structure. How can I fix this in SunOS 5.x?

As long as the fcode driver specifies at least one "reg" property, correctly or incorrectly for the device, you can use the "registers" property in the drivers hw.conf file to specify wildcarded values for any incorrectly specified "reg" properties. Here's how to do this in the driver.conf(4) file.

Example 1: 

Device has registers at offset 2000 for 100 bytes and a second set of registers at offset 10000 for 200 bytes. Device is an sbus device whose parent node is always an sbus. The fcode driver "forgot" to export the second set of registers.

name="foo" class="sbus" registers=-1,2000,100,-1,10000,200; 

Example 2: 

Device has registers at offset 3000 for 256 bytes. The fcode driver only specifies that the registers have 32 bytes. The device is an sbus device whose parent node is always an sbus.

name="foo" class="sbus" registers=-1,3000,256; 

In both of these examples, when the framework is creating internal data structures, the wildcarding will apply to all self-identifying devices with the same name, and the correct "sbus slot number" will be filled in to the "reg" property by the framework. The information specified in these examples *augments* the information provided by the fcode driver and overrides the fcode drivers specification of the "reg" property.

When using "registers", note that the external name of the device in the /devices tree will be the name as exported by the fcode drivers "reg" property. (So we can correctly mount root or use the device as a console, for example.) 

4. My fcode driver only creates a "name" property and doesn't create a "reg" property at all. Can I use "registers" wildcarding?

No, you must be able to fill in the correct slot number. If your device's fcode driver does not export even an incorrect "reg" property, Solaris cannot figure this information out and cannot complete the information.

In this case, the only thing you can do is to provide site specific driver.conf(4) files using the "reg" property with one line (one entry) for each instance of your card at that particular site. In this case, you will not be able to access other properties that may be correctly specified by the fcode driver, so you must include all of them (including interrupts and any other properties you might need defined) in the driver.conf(4) file.
 
 


PCI FCode FAQs 


The following questions deal primarily with PCI FCode PROMs, even though some questions are generic and their answers may also be applicable to SBus FCode PROMs.

 1.  Can you describe the PCI FCode PROM Header Format?
 2.  Can you describe the PCI expansion PROM Header Format?
 3.  Can you describe the PCI expansion PROM data structure format?
 4.  I am using the tokenizer from DDK 2.5.1 CD. How do I add a PCI header to my PROM?
 5.  What is the format of a physical address in the reg property?
 6.  When I load my FCode, do I need to do anything special to access the configuration space registers of my device?
 7.  What address do I use to access the configuration registers on my PCI device?
 8.  When I load my FCode, I can't access memory space locations. How can I enable access to memory space locations on my PCI device?
 9.  I can't access my expansion FCode PROM. How can I enable access to my expansion FCode PROM?
10.  I don't know who sets various base address registers (in configuration space) for the PCI device, the FCode PROM or the Operating System? Some software needs to set them up before the driver takes over...
11.  Can you determine the cache line size of the machine from the FCode, to write into the cache-line-size configuration space register of my PCI device?
12. When I try to test a new version of my FCode program, I create a new package - How do I get rid of or override the original package so that the downloaded code is executed?
13. How can I access device registers or memory on my plug-in PCI card from OpenBoot?
14. I am trying to load FCode from ethernet. The code seems to load ok, but when I try to build the package I get an error:
15. Are there any debugging flags on Sun systems to debug FCode?
16. On my Sun Ultra-30 UPA/PCI, system there are two nodes related to PCI; /pci@1f,4000 and /pci@1f,2000 . I need to know which of these paths represents pcia and pcib, so that I can establish their relationship to the NVRAM configuration variables "pcia-probe-list" and "pcib-probe-list".
17. If the FCode PROM is not present in a PCI device, some properties are created by the motherboard CPU PROM from the information given in its configuration space registers. What are the names of those properties?
18. How can I find and use physical addresses to access, say, configuration space registers on Sun Ultra-30 UPA/PCI systems?
19. I am still testing my FCode, but when I use "select-dev" on my device I get errors. How do I debug my FCode/device in this case?
20. How can I control probing of pci slots on my Sun Ultra-30 UPA/PCI system?
21. What should I keep in mind when using 3.x tokenizer and 3.x CPU PROMs?
22. What is the required set of properties for the expansion ROM?
23. When the configuration software probes my PC I slot, does it read my PROM 32-bits at a time, or one byte at a time?
24. Beside the header, what is the minimum amount of FCode which is required?
25. In the past I've used tokenizer version 2.3 for SBus FCODE development - is it OK to use that same tokenizer for PCI FCode PROM development, or do I need new tokenizer?
26. I am writing FCode for a bootable device. It appears to me that there are 3 kinds of software that come into play during a boot: kernel, FCode and OS-driver. Can someone briefly explain what each does and the order in which they kick in?
27. What conventions should I follow in naming my devices using FCode proms?
28. Where can I find additional documentation?
 

1. Can you describe the PCI FCode PROM Header Format? 

PCI FCode PROM Header Format is as follows: 
 

                 ---------------------------------------------------
        a.out header 
        32 bytes (Needed by some utilities)
        ---------------------------------------------------
        PCI expansion PROM Header
        28 bytes
        ---------------------------------------------------
        PCI data struct.
        24 bytes
        ---------------------------------------------------
        FCode (8 Byte FCode header + FCode code bytes)
        ---------------------------------------------------

The above a.out header is also needed if you want to download your FCode image (e.g. during test/development of your FCode driver you may not want to use a physical PROM) using "dload" or "boot" on a Solaris 1.x (SunOS 4.x) system. In case you are "dload"ing or "boot"ing your FCode image on a Solaris 2.x system, you need to replace the a.out header with an ELF header. The fakeboot utility can add either an a.out or an ELF header, based on parameters you pass to fakeboot. The add_hdr utility can also add either an a.out or an ELF header, in addition to adding the PCI header and the PCI data structure.
 
 

2. Can you describe the PCI expansion PROM Header Format ?

PCI expansion PROM Header Format (28 bytes) is as follows:

     Byte offset value       description
        -----------------------------------------------
        00      55(h)           PROM signature byte one.
        -----------------------------------------------
        01      aa(h)           PROM signature byte two.
        -----------------------------------------------
        02-03   34 00 (h)       SPARC reserved value
        -----------------------------------------------
        04-17   00 00 ...       reserved for processor 
                                architecture unique data.
        -----------------------------------------------
        18-19   1c 00           Pointer to PCI data str.
                                (assuming PCI data str. follows
                                immediately after PCI expansion PROM Header)
        -----------------------------------------------
        1a-1b   00 00           pad bytes 
        -----------------------------------------------
 
 
 

3. Can you describe PCI expansion PROM data structure format?

PCI expansion PROM data struct. (24 bytes) looks as follows:

     Byte offset description /(Hex. value) 
        --------------------------------------------
        00-03   signature : P C I R (50 43 49 52)
        --------------------------------------------
        04-05   vendor id
        --------------------------------------------
        06-07   device id
        --------------------------------------------
        08-09   ptr to Vital Product Data 
        --------------------------------------------
        0A-0B   PCI data str. length (18 00) 
        --------------------------------------------
        0C      PCI data str.rev.       (0)
        --------------------------------------------
        0D-0F   class,subclass code
        --------------------------------------------
        10-11   image length in 512 bytes 
        --------------------------------------------
        12-13   rev. level of code/data
        --------------------------------------------
        14      code type (01) 
        --------------------------------------------
        15      indicator byte. For last image (80)
        --------------------------------------------
        16-17   reserved (00 00)
        --------------------------------------------

Following is a dump of initial bytes in a PCI FCode PROM, with the a.out header in the first 32 bytes.

      hex
    addr        hex value 
    -----------------------------------------------------
    00000      01 03 01 07 00 00 46 98 00 00 00 00 00 00 00 00 
    00010      00 00 00 00 00 00 40 00 00 00 00 00 00 00 00 00
    00020      55 aa 34 00 00 00 00 00 00 00 00 00 00 00 00 00
    00030      00 00 00 00 00 00 00 00 1c 00 00 00 50 43 49 52
    00040      8e 10 01 10 00 c0 18 00 00 00 00 02 7e 00 00 01
    00050      01 80 00 00 f1 03 18 6e 00 00 46 64 vv xx yy zz 

For above PROM, Vendor Id is 0x108e, Device Id is 0x1001,
Pointer to Vital Data Product is 0xc000, class/subclass
code is 0x020000, image length (in 512 bytes) is 0x7e, 
FCode length is 0x4664 bytes, vv ... are FCode data. 
 
 
 

4. I am using the tokenizer from DDK 2.5.1 CD. How do I add a PCI header to my PROM? 

You can put PCI vendor-id, device-id, class code, vpd-offset, code-revision in your PCI ROM data structure as follows: 
 

     tokenizer[

        h# 108e  h# 1001  h# 020000  pci-header
           ( vendor-id device-id class-code -- )
        h# c000                      pci-vpd-offset    ( w -- )
        0                            pci-code-revision ( w -- )

     ]tokenizer
     FCode-version3
        ....
        ....
     end0

Above code, after tokenizing, will generate header as follows:  (first 32 bytes shown are a.out header's bytes)

      hex
    addr        hex value
    ----------------------------------------------------------
    00000      01 03 01 07 00 00 46 98 00 00 00 00 00 00 00 00
    00010      00 00 00 00 00 00 40 00 00 00 00 00 00 00 00 00
    00020      55 aa 34 00 00 00 00 00 00 00 00 00 00 00 00 00
    00030      00 00 00 00 00 00 00 00 1c 00 00 00 50 43 49 52
    00040      8e 10 01 10 00 c0 18 00 00 00 00 02 7e 00 00 01
    00050      01 80 00 00 f1 03 18 6e 00 00 46 64 vv xx yy zz
    ----------------------------------------------------------

If you don't have tokenizer 3.1 , you can obtain it from the tools page on this site.
 
 
 

5. What is the format of a physical address in the reg property? 

For PCI, the reg property value has 5 32bit nos. - phys.hi,  phys.mid, phys.low, size.hi and size.low. size.hi and size.low are values for size of register whose address and  type are defined by phys.hi,phys.mid and phys.low.
 

Format of Physical address in reg property is as follows: 
       phys.hi cell:  npt000ss bbbbbbbb dddddfff rrrrrrrr
   phys.mid cell: hhhhhhhh hhhhhhhh hhhhhhhh hhhhhhhh
   phys.low cell: LLLLLLLL LLLLLLLL LLLLLLLL LLLLLLLL

where
   n is 0 if the address is relocatable, 1 otherwise
   p is 1 if the addressable region is "prefetchable", 0 otherwise
   t is 1 if the address is aliased (for non-relocatable I/O), below 
        1MB (for Memory), or below 64KB (for relocatable I/O)
   ss=00 ==> Configuration space
   ss=01 ==> I/O space
   ss=10 ==> 32 bit Memory space 
   ss=11 ==> 64 bit Memory space 
   bbbbbbbb is 8 bit bus no. (assigned by CPU PROM at probe time)
   ddddd is 5 bit device no. 
   fff is 3 bit function no. 
   rrrrrrrr is 8 bit reg. no. 
   hh..hh is a 32 bit unsigned number, most significant portion
   LL..LL is a 32 bit unsigned number, least significant portion
 
 
 

6. When I load my FCode, do I need to do anything special to access the configuration space registers of my device? 

No, access to configuration space registers can not be disabled on PCI devices. Configuration space registers are always accessible.
 
 

7. What address do I use to access the configuration registers on my PCI device? 

Look in the format for physical address of reg property.  You can use the phys.hi cell of the first entry in the reg property, as base address for configuration space.  The first entry in the reg property must be the config space entry (bbbb.bbbb.dddd.dfff.0000.0000 binary).  Using that (or any other method) obtain values of bbbb.bbbb, ddddd and fff for your device. Then use

      ok " <parent-pci-bus-node>" select-dev
      ok <bbbb.bbbb.dddd.dfff>XX config-l@
      (XX is offset for that particular configuration register)

   e.g. if bus no. is 1000.0001 (0x81)
        device no. is 0.0000 and function no. is 001 (0x01) then, you will use
         ok " /pci@1f,2000" select-dev
         ok 81.0100 config-l@  ( to read device id and vendor id)
         ok 81.0104 config-w@  ( to read command register )
         ok 81.0110 config-l@  ( to read Base Address Register0, at 0x10 )
         ok 81.0130 config-l@  ( to read Expansion PROM base address register )
 
 
 

8. When I load my FCode, I can't access memory space locations. How can I enable access to memory space locations on my PCI device?

Look in the format for physical address of reg property. Using that (or any other method) obtain values of bbbb.bbbb, ddddd and fff  for your device. Then use

             ok " <parent-pci-bus-node>" select-dev
         ok <bbbb.bbbb.dddd.dfff>04 dup config-w@ 3 or swap config-w! 

Above will write 3 to the command register in configuration space and thus will enable access to memory and I/O space. This sets bit[0] and bit[1] of the command register. You may similarly set other bits in the command register, if needed by your application.

   e.g. if bus no. is 1000.0001 (0x81)
        device no. is 0.0000 and function no. is 001 (0x01) then, you will use
         ok " /pci@1f,2000" select-dev
         ok 81.0104 dup config-w@ 3 or swap config-w! 

Normally the "open" routine of your FCode driver should enable such access. FCode can use the value returned by "my-space" and add offset of 4 to get the address of the command register and then set various bits in the command register to enable a particular access. The "close" routine should disable that access.
 
 

9. I can't access my expansion FCode PROM. How can I enable access to my expansion FCode PROM?

Look in the format for physical address of reg property. Using that  (or any other) method, obtain values of bbbb.bbbb, ddddd and fff  for your device. Then use

             ok " parent-pci-bus-node" select-dev
         ok <bbbb.bbbb.dddd.dfff>04 config-w@ 3
            or
            <bbbb.bbbb.dddd.dfff>04 config-w!
         ok <bbbb.bbbb.dddd.dfff>30 config-l@ 1
            or
            <bbbb.bbbb.dddd.dfff>30 config-l!

The above will first enable memory and I/O space access and then will read a value from the expansion PROM base address register in configuration space  (at offset 0x30) "or" 1 to it, and write this new value in the Expansion PROM base address register to enable access to your FCode PROM.  This sets bit[0] of the Expansion PROM base address register. 

   e.g. if bus no. is 1000.0001 (0x81)
        device no. is 00000 and function no. is 001 (0x01) then, you will use
         ok " /pci@1f,2000" select-dev
         ok 81.0104 config-w@ 3 or 81.0104 config-w!
         ok 81.0130 config-l@ 1 or 81.0130 config-l!

If for any reason, (e.g. to access Vital Product Data stored in PROM)  FCode needs to access PROM data, then FCode should enable access to PROM  by using value returned by "my-space" and adding an offset of 0x30 to it  as address of register. FCode should  read value from that address, "or" 1 and write it to that address. Also since FCode would have been copied in memory, devices' memory and  I/O space may not be enabled. So FCode needs to enable them as well. using FCode:

         ok my-space h# 30 + dup config-l@ 1 or swap config-l!
             ( enable PROM access )
        ok my-space h# 4 + dup config-w@ 3 or swap config-w!
             ( enable I/O, memory access )

Using above example, one can disable Expansion PROM access as:

         ok my-space h# 30 + dup config-l@ 1 invert and swap config-l!
             ( disable PROM access )
 
 

10. I don't know who sets various base address registers (in configuration  space) for the PCI device, the FCode PROM or the Operating System? Some software needs to set them up before the driver takes over...

The CPU PROM (not the PCI card's FCode PROM) allocates base address  for memory and/or I/O space on your PCI device and for the FCode PROM itself.  So the CPU boot PROM of the main system will initialize these base addresses. 
 
 
 

11. Can you determine the cache line size of the machine from the FCode, to write into the cache-line-size configuration space register of my PCI device? 

The cache-line-size register in configuration space refers to the cache line size supported by the PCI device.
 
 

12. When I try to test a new version of my FCode program, I create a new package as follows :

                  ok 4000 dload /stand/mydev.fcode
        ok 0 0 " 4,0"  " /pci@1f,2000" begin-package
        ok 4020 1 byte-load
        ok end-package

However, when I do an "ls", I find that I now have TWO  packages corresponding to my card:

        ok ls
        ffd70c00 pci108e,1001@4,0 
        ffd6e860 pci108e,1001@4,0
        ok

How do I get rid of or override the original package so that the downloaded code is executed?  Should I just remove the PROM from the card?
 

Remove the PROM for PCI card. CPU PROM will still create a device node for the card, but the "name" property will  have a value of the form "pci<DDDD>,<VVVV>".  Create a name property for your device in your downloaded code  with a value different than the one created by CPU PROM.  And then refer to your device by full device path. 
 
 

13. How can I access device registers or memory on my plug-in PCI card from OpenBoot? 

 FAQ #7 showed  how to access configuration space registers of a plug-in PCI device. Also, you will need to enable access to memory space (FAQ #8). 

To access device registers or memory, which is on PCI memory space,  find out which Base Address Register corresponds to the memory space. You can get this info. either from device hardware manual or by looking at "reg" property for that device and seeing which entry starts with 02cc.ccxx, where cccc refers to its config address.  (Base Addresses are at 0x10, 0x14, 0x18, 0x1c, 0x20, 0x24 in config. space, so xx will be one of above values.) Assuming memory space is controlled by the base address at offset 0x10, map that space as follows: 

    ok " <device-path>" begin-select-dev 
   ( now to map 0x3000 bytes and store its virtual address in mem-vaddr
   ok 0 value mem-vaddr
   ok 0 0 02cc.cc10 3000 " map-in" $call-parent to mem-vaddr
   ok mem-vaddr l@ .            ( will fetch and display 32 bit quantity at 
                                  offset 0 in memory space).
   ok mem-vaddr 30 + w@ .       ( will fetch and display 16 bit quantity at 
                                  offset 0x30 in memory space). 

If memory space is accessible contiguously, one can dump its content as follows: 

   ok mem-vaddr 40 + 70 dump    ( will dump 0x70 bytes from memory space
                                  starting at offset 0x40)
 
 

14. I am trying to load FCode from ethernet.  The code seems to load ok, but when I try to build the package I get an error:

ok 4000 dload /stand/cheerio.o
Boot device: /pci@1f,4000/network@1,1:,|stand|cheerio.o  File and args: 
ok 0 0 " 0,1" " /pci@1f,2000" begin-package
ok 4000 1 byte-load
Unimplemented FCode token before address 4004                      <----- message
 Warning: FCode sequence resulted in a net stack depth change of 1 <----- message
ok

An error is possibly occurring due to: 

1) PCI header attached to PROM image
   or
2) my-address is two 32 bit nos. for PCI and only one 32 bit no. for Sbus. 

To determine if #1 is the problem, dump the downloaded image, starting from 4000, e.g. "4000 60 dump", and see where "f1", (or "fd") starts. These
byte-codes indicate the beginning of the PROM image for byte-load, so use the address of the byte code in the byte-load command, e.g. "ok X 1 byte-load".  "f1" indicates the beginning of the FCode header, which is 8 bytes long, as:
       f1;tokenizer-version;2 reserved bytes/checksum;4bytes of FCode length;

If #2 is the problem, change your FCode to handle two numbers returned from "my-address". One way to do is: 

my-address      constant my-bus-addr-mid  constant my-bus-addr-low
: my-bus-addr (  --  paddr.low paddr.mid )
   my-bus-addr-low  my-bus-addr-mid
;

and then using "my-bus-addr" in creation of the reg property etc. 
 
 
 

15.  Are there any debugging flags on Sun systems to debug FCode? 

You can set NVRAM variable fcode-debug? to true for keeping the  headers for those words which are preceded with headers in your source.

Also, some CPU PROMS have a variable named "fcode-verbose?" to display  each FCode as it is being read by token interpreter at probe time of your FCode PROM. To turn it on do: (before you probe your FCode)

         ok true to fcode-verbose? 
         <probe-your-card>

   To set it from NVRAMRC, do 
         ok nvedit
         0: true to fcode-verbose? 
         ^C
         ok nvstore
         ok setenv use-nvramrc? true
         ok reset-all 

Some CPU PROMs have pcimsg? and probemsg?  variables to give additional  PCI related info. You can turn them ON in a way similar to above way. "pcimsg?" controls display of all accesses to PCI configuration space. "probemsg?" controls display of probing status information including physical allocation.

Note that not all CPU PROMs have pcimsg? and probemsg?. 
Also, in future PROMs, behavior of pcimsg?, probemsg? and fcode-verbose?  may change including complete disappearance of above variables. 
 
 

16. On my Sun Ultra-30 UPA/PCI, system there are two nodes related to PCI;  /pci@1f,4000 and /pci@1f,2000 .  I need to know which of these paths represents pcia and pcib, so that I can establish their relationship to the NVRAM configuration variables "pcia-probe-list" and "pcib-probe-list".

Each PCI bus has a property, slot-name, which gives some information about slots on that PCI bus, and which may sometimes give a clue as to which NVRAM variable corresponds to it. To get a human readable value for slot-name, do following:

         ok " /pci-bus-node" select-dev
         ok " slot-name" get-my-property drop decode-int .h cr  type

   e.g. for pci bus at /pci@1f,2000:
         ok " /pci@1f,2000" select-dev
         ok " slot-name" get-my-property drop decode-int .h cr  type

   will display something like:
         6 
         pcia slot 1pcia slot 2 

This is an indication that devices under /pci@1f,2000 relate to  "pcia".

In Sun Ultra-30 UPA/PCI with 4 plug in PCI slots, only slot#  is physically present for pci@1f,2000 and it can also support 66 Mhz.,  64 bit PCI devices.

         ok " /pci@1f,4000" select-dev
         ok " slot-name" get-my-property drop decode-int .h cr  type
         34
         pcib slot 2pcib slot 4pcib slot 5

This is an indication that devices under /pci@1f,4000 relate to "pcib". In Sun Ultra-30 UPA/PCI with 4 plug in PCI slots: 

       a) slots 2, 4 and 5, under /pci@1f,4000 support 33 Mhz., 32 bit PCI devices. 
   b) Slot 3 under /pci@1f,4000 is for on-board scsi device.

Note that the value contained in slot-name is different for different systems.  For some systems, the contents of slot-name may not indicate a relationship between the device paths ad PCI busses "pcia" and "pcib". Also, in different releases of a PROM for the same system, the value of  slot-name may change.  You may need to refer to system documentation to determine details about the PCI busses on a particular system.

Alternatively, by setting nvram variables to different values and/or by plugging pci card(s) in different slot(s), one can determine which nvram configuration variable refers to which pci bus.
 
 

17. If the FCode PROM is not present in a PCI device, some properties are  created by the motherboard CPU PROM from the information given in its configuration space registers.  What are the names of those properties? 

If the FCode PROM is not present on a PCI plug-in card, the CPU PROM will generate the following properties in the device node for the PCI device; vendor-id, device-id, revision-id, class-code, name, reg, compatible and devsel-speed from information in configuration space  registers.  The interrupts property is present if the Interrupt Pin  register is non-zero.

The following properties will be present only if the corresponding capability is available from the device or that corresponding value was non-zero, as indicated in configuration space registers:
   66mhz-capable, udf-supported, cache-line-size, fast-back-to-back
   subsystem-id and subsystem-vendor-id.

The CPU PROM also creates min-grant and max-latency properties, unless the header type is 01. The CPU PROM also creates the assigned-addresses property, with entries for each base address register for which an address was assigned.
 
 

18. How can I find and use physical addresses to access, say, configuration space registers on Sun Ultra-30 UPA/PCI systems? 

It is probably easiest to use physical addressing if you simply do MMU bypassing with the choice of the correct ASI space.  The arguments for the space{c,d,w,l,x} command includes an address and ASI code (and data for a write operation.) 
 

On Sun Ultra-30 UPA/PCI systems, config registers of a pci device  are viewed using the following addr: 1fe.0100.0000   +  X 
where the 32bit value of X represented in bit format is as: 
        bbbb.bbbb.dddd.dfff.rrrr.rrrr 

   where bbbb.bbbb is eight bit bus no. 
   dddd.d is five bit device no. 
   fff is three bit function no. 
   rrrr.rrrr is register no.

So, if bus no. is 81, device no. is 0 and function no. is 1, then  X will be 81.0100, giving you the base of the configuration registers.  You'd then access the 0th config register at 1f0.0181.0100 (physical address).
 

On Sun Ultra-30 UPA/PCI systems, you can use ASI 0x15 for non-cacheable address being accessed via MMU bypass.  If you are accessing a little endian device use ASI 0x1d.
 

You can get bus no., device no. and function no. from "my-space" after  selecting that device, or from value of the reg property for that device. Look in IEEE 1275/PCI binding for the format of reg.

In general for any system, to get the physical addresses for registers in any space (config space, 32 bit memory space, etc.) use the "map-in" command, which requires the phys.lo,phys.mid,phys.hi and length arguments. Phys.lo,phys.mid,phys.hi numbers can be taken right from the corresponding reg property.  For configuration space it is easy to get the physical address since phys.lo and phys.mid are always zero.  Phys.hi is just the config space address.

We'll use onboard ethernet on a Sun Ultra-30 UPA/PCI system as an example for getting the physical address of configuration space registers.

       ok " /pci@1f,4000/network@1,1" begin-select-dev
   ok pwd
   /pci@1f,4000/network@1,1

   ok .properties
   .
   .
   reg  (Config Space ---->)       00000900 00000000 00000000 00000000 00000000 
        (32bit memory space ---->) 02000910 00000000 00000000 00000000 00007020 

   .
   .
   .
   .

   ok 0 0 900 100 " map-in" $call-parent constant my-cfg-vaddr
   ok my-cfg-vaddr . 
   fff80900 
   ok my-cfg-vaddr map? 
   VA:fff80900 
   G:0 W:1 P:1 E:1 CV:0 CP:0 L:0 Soft1:1 PA[40:13]:ff00800 PA:1fe01000000 
   Diag:0 Soft2:0 IE:0 NFO:0 Size:0 V:1 
   PA:1fe01000900 

Hence the physical address for the base of the configuration registers is 1fe.0100.0900 for this device. For plug in PCI devices, the physical address of registers may vary if the device is plugged into a different slot or if other devices are present.  Similarly, using the reg entry for memory or I/O space, one can find the physical addresses for those spaces.

To map and examine the contents of the expansion ROM of the above PCI device, use the following:
         ok 0 0 900 200.0030 or 1.0000
               " map-in" $call-parent constant my-rom-vaddr

         ok my-rom-vaddr map? 
         VA:fef7a000 
         G:0 W:1 P:1 E:1 CV:0 CP:0 L:0 Soft1:1 PA[40:13]:ff80800 PA:1ff01000000 
         Diag:0 Soft2:0 IE:0 NFO:0 Size:0 V:1 
         PA:1ff01000000 
 
 
 

19. I am still testing my FCode, but when I use "select-dev" on my device I get errors. How do I debug my FCode/device in this case?

Add a dummy "open" method to your device node's FCode if you want to be able to select (open) the device, so you can map the device in at the ok prompt and look at the device registers etc.:

      ok cd /pci..../<device-node>
      ok : open true ; ( this may give a message about "open" not being unique)
      ok device-end

Now you can use "select-dev" to open/select your device. Then use " map-in" $call-parent to map in the device registers etc, and examine them. (Remember that endianness may not be what you think, so look at how the device is mapped (with "map?"), and how rl@, etc, are defined.)
 
 
 

20. How can I control probing of pci slots on my Sun Ultra-30 UPA/PCI system? 
On Sun Ultra-30 UPA/PCI system, there are NVRAM variables which indicate to CPU PROM  which slots to probe and in what order during normal system initialization.  On Sun Ultra-30 UPA/PCI system they are: pcia-probe-list and pcib-probe-list.

The default value for pcia-probe-list is 1,2 and the default value for pcib-probe-list is 5,4,3,2 .

If you don't want slot 4 on pcib probed during normal initialization (which occurs after a reset), change pcib-probe-list as follows:
        ok setenv pcib-probe-list 5,3,2
Then later, after a reset, if you wanted to probe slot 4 on pcib manually, you could run the following command:
         ok 4 probe-pci-slot /pci@1f,4000

Note that not all CPU PROMs have the above command. Also, in future PROMs, the behavior of the above command may change, including complete disappearance of the command.
 
 

21. What should I keep in mind when using 3.x tokenizer and 3.x CPU PROMs? 

Here are some points to be aware of while using 3.x tokenizer;
While testing FCode under 3.x versions of CPU OpenBoot PROMs, make sure that you have OpenBoot version 3.1 or later PROMs. 

pre 3.1 PROMs will need the following nvram patch: 
 

             ok nvedit
         0:  : nl-move ( src dst len -- )  rot n->l rot n->l rot n->l (move) ; 
         1: ['] nl-move is move
         2: ['] l>>a     2   la+   dup   l@   h# 1000  invert  and   swap  l!
         3: ['] lrshift  2   la+   dup   l@   h# 1000  invert  and   swap  l!
         4: ^C

         ok nvstore
         ok setenv use-nvramrc? true
         ok reset-all

Another thing to note is:
   (While using 2.x or 3.x tokenizer), literals / numbers that have bit 31 set to 1 will have the bit (1) extended all the way through bit 63 when
   running on systems with 3.x CPU PROMs.  For example,
       8000.0000 constant xxx will be really giving a value as:  ffff.ffff.8000.0000 (on 3.x CPU PROMs)

It is best that when such words/constants are used, especially in address  manipulation, that your code clips them to a 32 bit value as:

   Get a real 8000.0000 by: 
         ff ff ff ff bljoin constant x-num
         : clip-num ( n -- l )  x-num and ; 
         8000.0000 clip-num constant  xxx 
  or 

        use " xxx clip-num " wherever " xxx " is being used.
 
 
 

22. What is the required set of properties for the expansion ROM?

 Strictly speaking, nothing is "required".  But the practical minimum is name and reg.  Several other PCI Config reg properties will be created by the OBP during probe time.
 
 
 

23. When the configuration software probes my PCI slot, does it read my PROM 32-bits at a time, or one byte at a time?

The configuration space is read 32 bits at a time, but it is the option of the target to read it as 8-bit chunks. OBP reads the PCI ROM one byte-at-a-time on byte offsets. This is done partly to avoid any endianness issue.  Note that on SBus, it was possible for the ROM to be wired for byte, halfword or word (32 bit) access (i.e. one valid byte per 32 bits).
The card's FCode would use the start0, start1, start2 or start4 FCode to signal to the host OBP how to address successive bytes when interpreting FCode.  On PCI, the Expansion ROM is expected to be wired for byte access. The PCI ROM Header is accessed that way.  Thus, when you get to the FCode image, the OBP pulls in the FCode one byte at a time, on byte boundaries.
 

24: Beside the header, what is the minimum amount of FCode which is required?
     Currently, all I have is this:

     tokenizer[

        h# 108e  h# 1001  h# 020000  pci-header ( vendor-id device-id class-code -- )
        h# c000                      pci-vpd-offset    ( w -- )
        0                            pci-code-revision ( w -- )

     ]tokenizer

     FCode-version3         \ My FCode starts from here.
        hex
        " test,pci"   xdrstring  " name"    attribute
     end0
 

The PCI ROM Header resides in locations 0 - 19 hex.

Usually, the first image will be aligned to start at 1c.  The PCI data structure (starting at 1c) then takes up next 17 hex locations. (See PCI System Architecture - Pages 366-367 - Third Edition - Feb printing)

 In the code above, code fragment tokenizer[  .....  ]tokenizer produces PCI ROM Header and PCI data structure. Note that  "[" and "]" above are required.

Finally, the FCode image starts. Technically, the minimum FCode image is 9 bytes: 

        - FCode Header (8 bytes including start code, checksum (2 bytes), and
                        image length (4 bytes).
        - FCode Body (can be length 0)
        - End byte-code (1 byte)

 Usually, the minimum you will want is a body program including the name and reg properties.  Without the reg entry, the OBP will not assign any base address regs nor will you get a unit address. Without a name, you will find it more difficult to reference the node in the device tree.

       So, the minimum FCode might be:

          FCode-version3
          " test,pci"   encode-string  " name"    property
          my-address my-space encode-phys
          0 encode-int encode+
          0 encode-int encode+ " reg" property
          end0

       With comments:

          FCode-version3         \ My FCode starts from here.
          " test,pci"   encode-string  " name"    property
          my-address            ( phys.lo phys.mid )
          my-space              ( phys.lo phys.mid phys.hi )
          encode-phys           ( adr len )
          0                     ( adr len  size.hi )
          encode-int encode+    ( adr' len' )
          0                     ( adr' len'  size.lo )
          encode-int encode+    ( adr' len' )
          " reg" property
          end0
 
 

25. In the past I've used tokenizer version 2.3 for SBus FCODE development - is it OK to use that same tokenizer for PCI FCode PROM development, or do I need new tokenizer?

Tokenizer Version 2.3 will work, but if you need to write 1275 source compatible FCode for PCI, you'll need version 3.1 or later.  Also, for pre 3.1 versions of tokenizer, you'll need to use some utility to add the PCI header.  Use the Tokenizer (version 3.1) from this site's Tools page.   See /opt/SUNWddk/ddk_3.1/tokenizer/README.
 
 

26. I am writing FCode for a bootable device.  It appears to me that there are 3 kinds of software that come into play during a boot: kernel, FCode and OS-driver.  Can someone briefly explain what each does and the order in which they kick in?

At power-on the CPU PROM begins execution. It probes all on-board devices  and plug-in cards and thus interprets the code in all FCode PROMs.  During the FCode probing process, some FCode PROMs will execute some commands like resetting the device, and so on. But generally, FCode PROMs will generate device properties for their respective devices. 

When the actual boot begins, the CPU PROM boots over the specified boot-device (and uses the device's FCode boot driver). The CPU PROM loads the bootblk (or
inetboot for network booting) and passes control to the bootblk code. The bootblk code in turn loads kernel modules and passes control to the kernel. Somewhere afterwards the kernel starts using the OS-device driver. This then is the scenario for a normal Solaris boot. 

In summary, the order is: CPU PROM, FCode PROM, bootblk, kernel and then the OS-driver.
 
 

27. What conventions should I follow in naming my devices using FCode proms? 
Refer to "Generic Naming Recommended Practices" available on the webpage of the Open Firmware (1275) Working group for details.

   Open Firmware (1275) Homepage is at http://playground.sun.com/1275/

   Look under http://playground.sun.com/1275/practice/#gnames based on working  group proposal #251.
 
 

28. Where can I find additional documentation? 
For writing PCI FCode, you need to have IEEE 1275/PCI bindings. The Open Firmware (1275) Homepage is at http://playground.sun.com/1275/  . The IEEE 1275/PCI bindings are at  http://playground.sun.com/1275/bindings/pci/

    "Writing FCode 3.x Programs" manual is available on the Publications page of this site.

    IEEE 1275 Standard for Boot Firmware is available from IEEE.
         Phone: 1-800-701-4333

  "PCI Local Bus specification rev 2.2"  and other specifications are available from  the 
        PCI Special Interest Group.

   In the  OpenBoot Collection
        OpenBoot 3.x Command Reference manual 
        OpenBoot 3.x Quick Reference 
        OpenBoot 2.x Command Reference manual 
        OpenBoot 2.x Quick Reference 
        Writing FCode 3.x Programs 
 

Back to Top