C H A P T E R  13

PCI FCode Driver Example

This example of a PCI FCode driver illustrates how to handle PCI-related registers in FCode.

 


CODE EXAMPLE 13-1 PCI FCode Driver Example
id: %Z%%M% %I% %E%
purpose: A sample network PCI FCode driver showing use of Vital Product Data and
access to ROM.
copyright: Copyright 1994-1998 Sun Microsystems, Inc.  All Rights Reserved
 
\ Each sample PCI card will define one hme device node:
\
\			pci
\			 |
\			 |
\			 |
\			hme
\
\ The general pathname (after pci) for a hme node is
\       hme@D,1
\ where D is Device#.
\

\ name    hme
\         Phys.hi    Phys.mid   Phys.lo    Size.hi    Size.lo
\         -------    ---------  ---------  ---------  ---------
\ reg     00BB.XX00  0000.0000  0000.0000  0000.0000  0000.0000  (Cfg) 
\         02BB.XX10  0000.0000  0000.0000  0000.0000  0000.7020  (memory) 
\
\         where "BB" = PCI Bus #
\         where "XX" = PCI Device # | Function #
\
 
Fcode-version3
 
 
hex
 
\ 3.x token interpreter extends bit[31] all the way to bit[63].
\ To create numbers with bit[31] set, but not extended to bit[63],
\ we need to use x-num
ff ff ff ff bljoin constant num-32
: x-num ( n -- l )  num-32 and ;
: and ( a b -- a-and-b ) and    x-num  ;
: or ( a b -- a-or-b )   or     x-num  ;
: lshift ( x n -- x' )   lshift x-num  ;
: rshift ( x n -- x' )   rshift x-num  ;
 
f200.0000 x-num constant xreg-mask
\ my-address gives two 32 bit numbers for PCI case.
my-address      constant my-bus-addr-mid  constant my-bus-addr-low
my-space        constant my-bus-space
2  constant pci-hme-intr       \ for PCI card
 
: my-bus-addr (  --  paddr.low paddr.mid )
   my-bus-addr-low  my-bus-addr-mid
;

...
...
 
\ for mac id on the fcode prom itself
h# 24 constant vpdp-loc
h# c000 value vpd-base
0 value cheer-rombase
0 value vpd-addr
h# 1.0000 value /cheer-rom
 
\ HappyMeal Enet Address Map
hex
000.0000	constant	global-regs-offset
7020     	constant        /total-reg-space
 
h# 4000	    constant max-frame-size		( d# 1536 for le )
d# 48	    constant address-bits
h# 10       constant cfg-bar0
h# 4       constant cfg-cmd-reg
h# 30       constant cfg-rom-base
h# 200.0000 constant 32-bit-mem-ss
 
 
: encode-ints  ( nn .. n1 n -- adr len ) 
   0 0 encode-bytes   rot  0  ?do  rot encode-int encode+  loop
;
 
: xdrreg  ( addr space size -- adr len )
   >r encode-phys  r> 0 2 encode-ints  encode+
;
 
: offset>physical-addr  ( offset -- paddr.lo paddr.mid paddr.hi )
   my-bus-addr >r + r> my-bus-space
   32-bit-mem-ss or cfg-bar0  or  \ OR in "ss" = memory, base reg=10
;
 
: create-hme-attributes  ( -- )
 
" SUNW,hme"      name		
   " SUNW,cheerio" encode-string  " model" property" SUNW,hme" 
   " pci108e,1001" encode-string " pciclass,-60000" encode-string
			encode+ " compatible" proerty

  my-bus-addr my-bus-space 0  xdrreg
   global-regs-offset offset>physical-addr  /total-reg-space
   xdrreg encode+
   " reg" property
 
max-frame-size encode-int " max-frame-size" property
   address-bits encode-int " address-bits" property
   pci-hme-intr  encode-int  " interrupts"  property
   " network" device-type
   " %I%" encode-string " version" property	 \ FCode PROM version
;
 
: enable-cheer-cmd-reg ( -- )
   \ PCI Command Register Settings
   \ h# 100  = SERR# Enable
   \ h#  40  = Parity Error Enable
   \ h#   4  = Mastering Enable
   \ h#   2  = Memory Access Enable
   my-bus-space cfg-cmd-reg +  " config-w@" $call-parent   ( cmd-reg )
   \ Set PCI Command bits
   h# 146  or
   my-bus-space cfg-cmd-reg +  " config-w!" $call-parent
;
 
: enable-cheer-rom ( -- )
   my-bus-space cfg-rom-base +  " config-l@" $call-parent   ( cmd-reg )
   \ enable rom accesses
   h# 1  or
   my-bus-space cfg-rom-base +  " config-l!" $call-parent
;
 
: disable-cheer-rom ( -- )
   my-bus-space cfg-rom-base +  " config-l@" $call-parent   ( cmd-reg )
   \ disable rom accesses
   h# 1 invert and
   my-bus-space cfg-rom-base +  " config-l!" $call-parent
;
: map-cheer-rom ( --  )
   0 0 my-bus-space 32-bit-mem-ss or cfg-rom-base or /cheer-rom
   " map-in" $call-parent to cheer-rombase
;

 : unmap-cheer-rom ( --  )
   cheer-rombase /cheer-rom " map-out" $call-parent
   0 to cheer-rombase
;
 
 
\ the Vital Product Data for sample ethernet card looks like this:
\
\ (Offsets are in decimal.)
\ Offset		Item		Value
\   0	Large Resource Type VPD Tag (0x10)	  0x90
\   1	Length			0x0009
\   3	VPD Keyword			"NA"
\   5	Length			6
\   6	Ethernet Address			0x080020.??????
\  12 	Small Resource Type End Tag (0xf)	   0x79
\  13	Data (nominally checksum)		           0
\
\
 
: uw@ ( adr -- w )  dup c@ swap 1+ c@ swap bwjoin ;
: set-vpdp-value ( -- )		\ set pointer to vpd
   enable-cheer-cmd-reg
   map-cheer-rom
   enable-cheer-rom		
   cheer-rombase vpdp-loc +  rw@ cheer-rombase + to vpd-addr
;
 
: unset-vpdp-value ( -- )
   disable-cheer-rom
   unmap-cheer-rom
   0 to vpd-addr
;
: get-macid-header  	(  -- tag len1 keyword len2  )
   vpd-addr  dup c@ 	( tag )
   swap 1+ dup uw@ 	( tag len1 )
   swap 2+ dup uw@ 	( tag len1 keyword )
   swap 2+ c@ 		( tag len1 keyword len2 )
;

: verify-macid-header-ok?   ( tag len1 keyword len2 -- ok? )
   h# 6 <>  if 2drop drop false exit then
   ( tag len1 keyword )
   ( "NA" ) h# 4e41  <>  if  2drop false exit then
   ( tag len1 )
   h# 9  <>  if  drop false exit then
   h# 90  <>  if  false else  true  then
;
6 buffer: my-loc-mac-addr
 
: loc-mac-prop ( addr -- )
   6 encode-bytes " local-mac-address" property
 
;
: make-loc-mac ( -- )    my-loc-mac-addr  loc-mac-prop  ;
: get-macid ( -- valid? )
   get-macid-header
   verify-macid-header-ok?  if
     vpd-addr 6 + my-loc-mac-addr 6 cmove
     true
   else
     diagnostic-mode?  if
       ." Wrong Vital Product Data/Network Address header" cr
     then
     false
   then
;
: make-macid ( -- )
   get-macid  if
     make-loc-mac
   then
;
 
: create-macid ( -- )
   set-vpdp-value
   make-macid
   unset-vpdp-value
;
create-hme-attributes   \ Create ENET port device node.
create-macid
...

...
headers
: do-map-in ( offset slot# #bytes -- virtual ) " map-in" $call-parent  ;
: do-map-out  ( adr len -- )  " map-out" $call-parent  ;
: do-dma-map-in  ( vaddr n cache? -- devaddr ) " dma-map-in" $call-parent  ;
: do-dma-map-out  ( vaddr devaddr n -- )  " dma-map-out" $call-parent  ;
: do-dma-alloc ( size -- addr )  " dma-alloc" $call-parent  ;
: do-dma-free ( addr size -- )  " dma-free" $call-parent  ;
 
: do-dma-sync ( virt-adr dev-adr size -- )
   " dma-sync" ['] $call-parent  catch  if
      3drop 2drop
   then
;
 
...
...
 
0 instance value obp-tftp       \ Contain ihandle of TFTP package.
 
: init-obp-tftp  ( -- okay? )
   " obp-tftp" find-package  if         ( phandle )
      my-args rot open-package          ( ihandle )
   else  0
   then
   dup to obp-tftp                      ( ihandle | 0 )
   dup 0=  if
      ." Can't open OBP standard TFTP package"  cr
   then
;
 
...
...
 
 

: write  ( buf len -- actual-len )
   ...
   ...
;
: seek  ( -- okay? )
   ." Unimplemented driver procedure: seek "  cr  0
;
 
: selftest  ( -- failed? )      \ Flag 0 if passes test.
   ...
   ...
;
 
: watch-net  ( -- )		\ to watch network activity
   ...
   ...
;
 
: close  ( -- )
   ...
   ...
   obp-tftp ?dup  if  close-package  then
   ...
   ...
;
 
: open  ( -- okay? )		\ return true on successful open
   ...
   ...
 
init-obp-tftp 0=  if  close false exit  then
   true
;
 
: load  ( adr -- len )
   " load" obp-tftp $call-method
;
 
end0