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.

 ```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 ```