lkml.org 
[lkml]   [2000]   [Nov]   [17]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
Date
From
SubjectRe: VGA PCI IO port reservations
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/

\
 
 \ /
  Last update: 2005-03-22 12:47    [from the cache]
©2003-2011 Jasper Spaans