Writing FCode 3.x Programs
검색에만이 책은
PDF로 이 문서 다운로드

PCI FCode Driver Example

13

This example 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  
       " pci108e,1001" encode-string " pciclass,060000" encode-string  
                            encode+ " compatible" property  


    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  
  ;  
  
  ...  
  ...  
  
  external  
  : read  ( buf len -- actual-len )  
     ...  
  
  ;  


  : 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