Re: VGA PCI IO port reservations

From: Richard B. Johnson (root@chaos.analogic.com)
Date: Fri Nov 17 2000 - 13:06:30 EST


On Fri, 17 Nov 2000, Russell King wrote:

> Richard B. Johnson writes:
> > This can't be.
>
> Richard, before I read any further, I suggest that you get some
> documentation on a few PCI VGA cards and read up on the register
> addresses. You may want to change your assumptions about what can and
> can't be. ;)
>
> And I can definitely say that if you don't allow access to these "extended"
> VGA ports, BIOSes either enter infinite loops or else terminate without
> initialising the card. Trust me; I've been successfully running various
> PCI VGA card BIOSes under an x86 emulator on an ARM machine for the past
> few months.

If a board has the capability of snooping their own special addresses,
you don't have to do anything about them. They snoop <period>.

If you look as how I showed that the resources are allocated, you
will see that it works. The I/O addresses that are used (for everything),
start at the lowest __unaliased__ address. This means that if a board
is already snooping an address, it will appear to be aliased.

The code necessary to find the lowest unaliased address looks like
this:

;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
;
; This initializes memory and port allocation space for PCI
; device resource allocation.
;
ALIGN 4
INIT_PCI_RES:
        PUSH DS ; Save segment
        MOV AX,PCI_OBJ_ALLOC ; Segment address for storage
        MOV DS,AX ; Set segment
        MOV DWORD PTR DS:[PCI_MEM],(INSTALLED_MEM SHL 14H) ; For PCI
;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
;
; Find the lowest port address (above PCI_OFF) that doesn't have
; any devices responding at possible aliases.
;
        MOV EDX,0000F002H ; Highest possible even port
FPRT: SUB DX,02H ; Keep on a WORD boundary
        IN AX,DX ; See if anything there
        SLOW_IO ; Bus settle time for slow devices
        INC AX ; 0FFFFH -> 0000H
        JNZ SHORT PRTFND ; We found an alias
        CMP DX,PCI_OFF ; Lowest port
        JNC FPRT ; Continue
PRTFND: ADD DX,02H ; Last good port
        MOV DWORD PTR DS:[PCI_PRT], EDX
        POP DS ; Restore segment
        RET

The code necesary to allocate resources looks like this:

;
;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
;
; This allocates PCI-bus memory-space. Upon entry EAX contains
; the DWORD read from the PCI-bus memory address register. This
; can be zero (no memory to reserve). Upon exit, EAX contains
; the value to be written back to this register, including possibly
; zero.
;
ALIGN 4
ALLOC_PCI_ADDR:
        PUSH EBX ; Save nonvolatile registers
        PUSH DS ; Save segment
        PUSH PCI_OBJ_ALLOC ; Where we save last result
        POP DS ; DS = PCI_OBJ_ALLOC
        TEST EAX,1 ; IO port?
        JZ SHORT NOTIOP ; Not an IO port
;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
;
; This allocates an I/O port for the device. They are allocated on
; 16-byte boundaries even if we don't need the space.
;
        AND EAX,(NOT 3) ; Mask port/reserved bits
        JZ SHORT NOALOC ; No space required
        MOV ECX,EAX ; Start with first address bit
        NEG ECX ; ECX = length required
        CMP ECX,000000010H ; At least 16 bytes?
        JNC SHORT WAS16 ; Yes
        MOV ECX,000000010H ; At least 16 bytes
WAS16: MOV EBX,ECX ; Save allocation length
        MOV EAX,DWORD PTR DS:[PCI_PRT] ; Get present value
        ADD EAX,ECX ; New offset value
        DEC EAX ; Adjust for previous math
        NEG ECX ; Create a mask
        AND EAX,ECX ; N-byte boundary
        ADD EBX,EAX ; EBX = for this allocation
        MOV DWORD PTR DS:[PCI_PRT],EBX ; Ready next
        JMP SHORT NOALOC ; We are done
;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
;
; This allocates I/O memory-space. A defect (feature) of the
; PCI addressing scheme is that a N-byte allocation must start
; on a N-byte boundary. This means that a 4 megabyte allocation
; for a PCI screen-card wastes nearly 4 megabytes of address-space.
;
NOTIOP: AND EAX,0FFFFFFF0H ; Clear non-address bits
        JZ SHORT NOALOC ; No memory required
        MOV ECX,EAX ; Start with first address bit
        NEG ECX ; ECX = length required
        MOV EBX,ECX ; Save allocation length
        MOV EAX,DWORD PTR DS:[PCI_MEM] ; Get present value
        ADD EAX,ECX ; New offset value
        DEC EAX ; Adjust for previous math
        NEG ECX ; Create a mask
        AND EAX,ECX ; N-byte boundary
        ADD EBX,EAX ; EBX = for this allocation
        MOV DWORD PTR DS:[PCI_MEM],EBX ; Ready next
NOALOC: NEG ECX ; Return with length
        POP DS ; Restore segment
        POP EBX
        RET
;
;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
;
; This attempts to set up the PCI bus. This does a PCI
; snoop, finding PnP devices, allocating memory, and enabling
; them. Note that this machine has only one bridge so we
; don't have to check for bridges behind bridges.
;
ALIGN 4
SET_PCI:
        XOR SI,SI ; Start at device zero, the bridge.
        READ_PCI SI, 0 ; See if the bridge is there
        INC EAX ; 0xffffffff becomes zero
        JNZ SHORT BRIDGE ; There is a bridge
        RET ; Forget it, no bridge
;
BRIDGE: READ_PCI SI, PCI_CMD_STA ; Get command/status register
        OR AX,07H ; Enable I/O, Memory, Master
        WRITE_PCI SI, PCI_CMD_STA, EAX ; Enable it.
;
        READ_PCI SI, PCI_AMD ; AMD Specific PCI retry count
        MOV AL,80H ; Recommended value
        WRITE_PCI SI, PCI_AMD, EAX ; Set timeout value
;
        READ_PCI SI,PCI_LAT_CACHE ; Latency, etc.
        MOV AX,4008H ; Latency / cache line size
        WRITE_PCI SI, PCI_LAT_CACHE,EAX ; Set it (if possible)
;
PCIDEV: INC SI ; Ready next device
        READ_PCI SI, 0 ; Get device ID
        INC EAX ; Anybody home? 0xffffffff becomes 0
        JZ PCINXT ; Nope
;
        READ_PCI SI, PCI_CMD_STA ; Get command/status register
        OR AX,7 ; Enable I/O, Memory, Bus master
        WRITE_PCI SI, PCI_CMD_STA, EAX ; Enable it.
;
        READ_PCI SI,PCI_LAT_CACHE ; Latency, etc.
        MOV AX,4008H ; Latency / cache line size
        WRITE_PCI SI, PCI_LAT_CACHE,EAX ; Set it (if possible)
;
        MOV DI,PCI_BASE0 ; First base address offset
PCIRES: MOV EAX,0FFFFFFFFH ; All bits set
        WRITE_PCI SI, DI, EAX ; Try to set all bits
        READ_PCI SI, DI ; Get the results
        CALL ALLOC_PCI_ADDR ; Allocate resources
        WRITE_PCI SI, DI, EAX ; Write base address (could be zero)
        INC DI ; Ready next base address
        CMP DI,PCI_CARDBUS ; Check limits
        JC PCIRES ; Next possible address
;
        READ_PCI SI, PCI_INTER ; Interrupt pin
        TEST AX,0F00H ; Isolate interrupt pin
        JZ SHORT PCINOI ; No interrupt required
        CALL GET_IRQ ; Get IRQ value from table
PCINOI: OR EAX,18180000H ; Could be writable
        WRITE_PCI SI, PCI_INTER, EAX ; Set IRQ (could be zero)
PCINXT: CMP SI,PCI_MAX ; End of devices?
        JC PCIDEV ; Nope
        PARK_PCI ; Park on the bridge
        RET
;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

Cheers,
Dick Johnson

Penguin : Linux version 2.4.0 on an i686 machine (799.54 BogoMips).

"Memory is like gasoline. You use it up when you are running. Of
course you get it all back when you reboot..."; Actual explanation
obtained from the Micro$oft help desk.

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Thu Nov 23 2000 - 21:00:13 EST