5.11 Milan PCI Hardware 2 Sonder-Edition PCI-BIOS MILAN
Sonder-Edition PCI-BIOS Stand: 09. 07.1998
Von:
Der PCI-Bus (Part 1)
Allgemeines:
Der Peripheral Components Interconnect (PCI) Bus wurde
ursprünglich für IBM-kompatible PCs entwickelt, da dringend
die Notwendigkeit eines schnellen, prozessorunabhängigen
Bussystems bestand. Seither hat sich dieser Bus auch ür andere
Rechnerwelten etabliert (wie z.B. die aktuellen Macintosh-Modelle auf
Basis des PowerPC, diverse Workstations mit DECs Alpha-Prozessor oder
aber auch die aktuelle UltraSparc von SUN). Auch die Entwickler des
Hades und des Milan haben an diese wirklich universelle Schnittstelle
gedacht. Diese Entwicklung führte dahin, daß man nun
tatsächlich dieselben Erweiterungskarten auf unterschiedlichen
Rechnerplattformen nutzen kann - sofern jeweils Treiber ür das
betreffende System verügbar sind. Daher ist es längst an der
Zeit, sich einmal näher mit dem PCI-Bus zu beschäftigen.
Diese erste Folge soll einen überblick der Möglichkeiten des
PCI-Bus schaffen, die zweite Folge beschreibt dann die einzelnen
Register für die Initialisierung und Konfiguration von
PCI-Karten, und die abschließende dritte Folge befaßt sich
dann mit der Portierung und Implementierung des vom PC her bekannten
PCI-BIOS für ATARI-kompatible Rechner am Beispiel von Hades und
Milan. Der PCI-Bus ist für 32 Bit breite Daten bei maximal 33 MHz
spezifiziert und ist optional auf 64 Bit und/oder 66 MHz erweiterbar.
Der Takt darf aber im Prinzip einen beliebigen Wert zwischen 0 und 33
MHz annehmen. Bei 33 MHz und 32 Bit Datenbreite sind theoretische
Übertragungsraten von bis zu 132 MB/s möglich, und in der
Praxis sind tatsächlich Werte nahe diesem theoretischen Maximum
erreichbar. Nach der elektrischen Spezifikation künnen an einem
PCI-Bus bis zu vier Slots neben dem Hostsystem untergebracht sein.
über eine PCI-Bridge läßt sich dann noch ein weiterer
Bus anhängen. Falls dies wieder ein PCI-Bus ist, kann man das
Spiel auch mehrfach wiederholen. Jedes PCI-Gerät kann mehrere
unabhängige Funktionen beinhalten (multifunction devices), die
sich auch unabhängig über den Bus ansprechen lassen. Die
meisten derzeit erhältlichen Geräte sind allerdings
sogenannte 'single function devices'. Multi function devices verhalten
sich prinzipiell wie mehrere single function devices, nur, daß
eben die Configuration Bereiche der einzelnen Funktionen dieser Karten
anders angesprochen werden. Bei den Multifunktionskarten kann man zwei
von Grund auf verschiedene Versionen unterscheiden:
Die PCI-Hardware:
Für die grundlegenden Funktionen des PCI-Bus werden insgesamt
47 Pins für Slave-Adapter sowie 49 Pins für Master-Adapter
benötigt. Dazu kommen die Anschlüsse der
Versorgungsspannung. Auf eine Aufzählung aller Signale finden Sie
ganz am Anfang dieses Artikels, eine genaue Beschreibung aller Signale
erfolgt hier noch nicht, da diese den Artikel sichtlich sprengen
würden. Deshalb sollen nur die wichtigsten, in den Abbildungen
verwendeten Signale näher erläutert werden:
DMA am PCI-Bus:
Grundsätzlich kann jedes beliebige PCI-Gerät als
Busmaster auftreten. Als Busmaster kann dieses PCI-Gerät dann
selbständig Daten aus seinem eigenen Speicherbereich in den
Systemspeicher des Host-Rechners übertragen. Diese Art der
Hintergrundverarbeitung entlastet den Prozessor des Host-Rechners sehr
stark. Deshalb sollten alle PCI-Geräte, die große
Datenmengen zu transportieren haben, oder aber schnelle Transfers
erfordern, als Busmaster auftreten künnen. Die DMA-Fähigkeit
des PCI-Bus benutzen z.B. SCSI-Controller oder auch moderne
Netzwerkkarten, um Daten schnell in den oder aus dem Hauptspeicher zu
transportieren. Die Vorteile bei Verwendung eines
busmasterfähigen PCI-Gerätes zeigen sich ganz besonders bei
'echten' Multitasking-Betriebssystemen, da dort die gesparte
Rechenzeit anderen Prozessen zur Verfügung gestellt werden kann.
Unter Single-Tasking unterliegt es dem Geschick des Programmierers,
aus der Busmaster-Fähigkeit eines PCI-Gerätes Vorteile zu
ziehen. Ein Zugriff, der nur auf das Ende einer übertragung
wartet, ist zwar einfacher zu implementieren, verschenkt durch
Leerlauf des Prozessors aber wieder die gewonnene Zeit. Das
busmasterfähige PCI-Gerät fordert den Bus durch Setzen
seiner /REQLeitung an. Ein Master darf /REQ allerdings nurfür
seinen aktuellen Zugriff benutzen, nicht aber, um sich den Bus auf
Dauer zu sichern. Der Bus Arbiter des Host-Rechners teilt diesem
Gerät den Bus durch Setzen des entsprechenden /GNT-Signals zu.
Nachdem dem PCI-Gerät der Bus zugeteilt wurde, kann dieses seinen
DMA-Zugriff durchühren. Wenn das PCI-Gerät nicht innerhalb
einer bestimmten Zeit den Bus wieder freigibt, kann der Host-Rechner
durch das Wegnehmen der /GNT-Leitung den Bus auch wieder frei
bekommen. Der Busmaster muß dann nämlich augenblicklich den
Zugriff beenden.
Interrupts am PCI-Bus:
Auf dem PCI-Bus sind insgesamt vier "pegel"-getriggerte
Interrupt-Leitungen vorhanden (INTA...INTD). Alle Geräte mit nur
einer Funktion dürfen nur INTA verwenden, die anderen drei
Leitungen sindfür den Betrieb sogenannter 'multi function
devices' vorgesehen. In der PCI-Spezifikation selbst ist die weitere
Verarbeitung der Interrupts nicht definiert und wird somit dem
jeweiligen Boardhersteller überlassen. Die Interruptleitungen der
einzelnen Slots künnen daher entweder als
"durchgeschleifte" Busleitung (open drain) in jeder nur
erdenklichen Kombination verbunden sein, oder aber sie werden von
jedem Slot einzeln an den entsprechenden Interrupt Controller
herangeührt. Nach einer Interruptanforderung ist dann der
jeweilige Treiber dieses PCI-Gerätes daür verantwortlich,
die Ursache der Unterbrechungsanforderung zu beheben. Im Gegensatz zum
recht kranken Design des ISA-Busses ist es daher beim PCI-Bus
müglich, daß sich mehrere Karten eine Interruptleitung
teilen (shared interrupt) - Engpässe, wie man sie früher von
den DOSen her kannte, werden damit vermieden. Allerdings müssen
dann die eingesetzten Softwaretreiberfür die PCI-Karten auch
Interrupts bearbeiten künnen, bei denen sich mehrere Geräte
eine Interruptleitung teilen. Mehr zu diesem Thema gibt es dann bei
der Vorstellung des PCI-BIOS.
Die Implementation des PCI-Bus im Milan:
Auch der Milan hat einen PCI-Bus mit einer Datenbreite von 32 Bit
bei maximal 33 MHz. Die Anbindung an die CPU erfolgt über eine
PCI-Bridge der Firma PLX. Es sind insgesamt 4 Interruptleitungen
vorhanden, die zyklisch zwischen den Slots getauscht sind - dadurch
bekommt bei single function devices jede Karte einen eigenen
Interrupt, und erst bei multi function devices wird es nütig,
Interrupts gemeinsam zu benutzen. Interrupts werden über die
Intel PCI-ISA-Bridge und die darin vorhandenen Interrupt-Controller
bearbeitet und als Autovektor-Interrupt an die CPU weitergemeldet. Die
Busarbitrierung für die DMA-Zugriffe erfolgt in einem der
Glue-Chips - alle Slots (sowie die Onboard-Peripherie) sind
busmasterfähig. Es wird eine Arbitrierung mit rotierender
Priorität verwendet, bei der die Karte, die gerade den Bus
besitzt, die niedrigste Priorität hat, so daß eine Karte
den Bus nicht komplett blockieren kann. Wenn niemand den Bus
anfordert, wird er bei dem Gerät, welches ihn zuletzt
besaß, geparkt - das spart Zeit, wenn danach das gleiche
Gerät den Bus wieder anfordert.
Erweiterungs-ROM auf PCI-Karten: Die PCI-Spezifikation beschreibt auch einen Mechanismus, mit dem
ein PCI-Gerät einen exekutierbaren ROM-Code für eine
gerätespezifische Initialisierung usw. anbieten kann. Dieses ROM
kann dabei mehrere verschiedene ROM-Images beinhalten, um die
verschiedensten Rechner und Prozessorarchitekturen zu
unterstützen. Der OPENBOOT Standard für PCI sieht
Fortran-Programme im ROM vor, so daß der ROM-Code zwar langsam
(weil interpretiert), aber daür prozessorunabhängig ist. Die
andere Müglichkeit sind native ROM-Images (ür die jeweilige
zu unterstützende Plattform), wovon die Hersteller aber keinen
Gebrauch machen (wohl weil sich dann nur noch schwer begründen
ließe, warum z.B. dieselbe Grafikkartefür einen PowerMac
meist 100% teurer ist als für den Intel PC). Natürlich
künnen OPENBOOT-Images und native Images gemeinsam in einem ROM
untergebracht werden. Am ATARI werden die ROMs auf den Karten im
Moment zwar noch nicht genutzt, aber dieser Umstand wird sich schon
demnächst ändern.
Ein paar Worte zu Plug'n'Play:
Das Zauberwort 'Plug and Play' ist sehr eng mit dem PCI-Bus
verbunden. Denn erst hier ist das leidige Thema der Ressourcenvergabe
für die Hardware über ein geeignetes BIOS (PCI-BIOS) elegant
lösbar. Im Idealfall sieht die Installation einer neuen PCI-Karte
also folgendermaßen aus (im Gegensatz zum PC ist bei
ATARI-kompatiblen ein nochmaliges (oder gar mehrmaliges) Booten
während der Installation NICHT notwendig ;-)
* Karte in einen freien Slot reinstecken
* Rechner starten, das PCI-BIOS konfiguriert die Karte
* Softwaretreiber für die PCI-Karte starten und fertig
Der PCI-Bus ist eigentlich selbstkonfigurierend definiert.
Dafür beinhaltet jedes PCI-Gerät einen Satz von Registern,
die während des Boot-Vorgangs ausgelesen werden künnen.
Enthalten sind hier neben Informationen über das Gerät
selbst (Hersteller, Gerät, Typenklasse, Müglichkeiten,
Waitstates, Interrupt, ...) auch die benütigten Speicherbereiche.
Damit ist es dem BIOS müglich, die Karte korrekt ins System
einzubinden, ohne daß Ressourcenkonflikte auftreten oder sich
der Benutzer mit DIPSchaltern, Jumpern etc. herumschlagen muß.
Am Macintosh-Sektor (NuBus) und am Amiga-Sektor (Zorro II/III-Bus) ist
z.B. das Problem der Autokonfigurierung übrigens bereits seit der
Existenz der jeweiligen Bussysteme (also seit über 10 Jahren)
gelüst! Der PCI-Standard sieht mittlerweile auch optional die
"Hot-Plug-Fähigkeit" vor, so daß PCI-Karten sogar
im Betrieb gewechselt werden künnen. Das darf aber in keinem Fall
am Hades oder Milan gemacht werden, da dies zur Zerstürung des
Mainboards oder der Karte ühren kann (ür dieses Feature sind
spezielle Voraussetzungen erforderlich).
Sonder-Edition PCI-BIOS, Part 2 Stand: 09. 07. 1998
Von:
Wie bereits im ersten Teil dieser Serie erwähnt wurde, hat
jedes PCI-Gerät einen eigenen Registersatz. Ein Zugriff auf
diesen Konfigurationsbereich erfolgt immer durch paralleles Setzen der
IDSEL-Leitung des ensprechenden Slots und dem Anlegen der
Registeradresse und des Buskommandos Configuration Read oder
Configuration Write auf den Leitungen /C/BE[0..3]. Die IDSEL-Leitung
ist dabei für jeden Slot separat vorhanden und wird vom
Motherboard auskodiert. Nur mit dieser Art der Steuerung ist ein
Zugriff auf die einzelnen Karten direkt nach dem Reset
möglich, da zu diesem Zeitpunkt noch keine
Adreßräume zugeteilt wurden. Der Zugriff auf diese
Register wird auf dem PC vom PCI-BIOS über die Befehle
Configuration Read / Configuration Write bereitgestellt. Und in der
nächsten Folge möchte ich dann sämtliche
Möglichkeiten eines ATARI PCI-BIOS vorstellen
Der PCI Configuration Bereich:
Jede PCI-Karte enthält einen Satz von definierten Registern,
die Informationen über die Karte bereitstellen und die die
automatische Vergabe von Ressourcen überhaupt erst
ermöglichen. Der Registerbereich ist 256 Bytes lang und teilt
sich in einen von der PCI-SIG (PCI - Special Interest Group)
vordefinierten und in einen kartenspezifischen Bereich. Dabei
müssen in den jeweiligen PCI-Geräten von den beiden
Bereichen nur die notwendigen Register implementiert werden Das
Speicherlayout des 64 Byte langen, vordefinierten Bereichs selbst
muß aber von jeder PCI-Karte eingehalten werden und
beinhaltet die Identifikationsdaten der Karte und die
Möglichkeiten zur generellen Kontrolle über die Karte. Die
folgenden 192 Bytes sind nicht durch die PCI-Spezifikation vorgegeben,
sondern können mit herstellerspezifischen Informationen
gefüllt und danach vom Softwaretreiber ausgewertet werden.
Die Register werden während der Initialisierung des
PCI-Busses ausgewertet und müssen daher schon direkt nach dem
Reset gültige Werte enthalten. Auch später müssen die
Register im freien Zugriff verbleiben, da zum Beispiel die
Systemsoftware (PCI-BIOS) die Informationen über die
Adreßräume benötigt und eventuelle
Statusinformationen abgefragt werden müssen.
Um herauszufinden, welche Karten nun am PCI-Bus angeschlossen
sind, kann man die Vendor ID in jedem der im System vorhandenen Slots
auslesen. Die Hostsystem muß daher Zugriffe auf die
Konfigurationsbereiche nicht vorhandener Karten (ohne Fehlermeldung)
unterstützen. Da für eine Vendor ID der Wert FFFFhex nicht
erlaubt ist, reicht es daher völlig, wenn die Systemhardware bei
Lesezugriffen auf den Konfigurations-Bereich nicht vorhandener Karten
eben diesen Wert zurückliefert.
Jedes PCI-Gerät muß Schreibzugriffe auf reservierte
oder nicht unterstützte Register ignorieren, d.h. der
Schreibzugriff muß am PCI-Bus ohne Fehlermeldung abgeschlossen
werden. Die Daten selbst werden allerdings von der Karte verworfen.
Lesezugriffe auf reservierte oder nicht implementierte Register
müssen ebenfalls ohne Fehlermeldung am Bus abgeschlossen, und ein
Wert von 0000hex zurückgegeben werden.
Tabelle 1 zeigt das Layout des von der PCI-SIG definierten
64Byte-Bereichs, das jede Karte unterstützen muß. Jedem
PCI-Gerät ist es natürlich freigestellt, weitere
gerätespezifischen Register im nachfolgenden Bereich abzulegen.
Alle Felder, bestehend aus mehr als einem Byte, liegen dem Little
Endian (Intel)-Format zugrunde, d.h. die niederwertigere Adresse
beinhaltet auch das niederwertigere Byte. Die Treibersoftware
muß mit bitcodierten Feldern sorgsam umgehen, da diese zumeist
reservierte Bitpositionen für eine etwaige spätere
Verwendung beinhalten. Die Software muß daher bei Lesezugriffen
Masken verwenden um die verwendeten Bits zu extrahieren, und darf sich
keinesfalls auf bestimmte Werte in reservierten Bits verlassen. Bei
Schreibzugriffen muß die Software sicherstellen, daß die
Werte von reservierten Bits nicht verändert werden, d.h. ihr Wert
muß vorher ausgelesen und zum gewünschten Wert der anderen
Bits 'gemerged' werden. Auch dieser von der PCI-SIG vordefinierte
Bereich gliedert sich in zwei Bereiche. Der erste 16 Bytes lange
Bereich gilt für alle Arten von PCI-Geräten und ist immer
gleich. Den verbleibenden 48 Bytes können in Abhängigkeit
von der Funktion des PCI-Geräts verschiedene Layouts zugewiesen
werden. Das Feld 'Header Type' an Adresse 0Ehex legt fest, um welches
Layout es sich in diesem zweiten Bereich handelt. Alle PCI-Geräte
müssen die Register für Vendor ID, Device ID, Command und
Status implementieren. Die Implementierung der anderen Register ist
optional und hängt wieder einmal mehr von der Funktionalität
des PCI-Geräts ab. Nicht implementierte Register können vom
PCI-Gerät wie reservierte Register behandelt werden. Wenn
allerdings ein PCI-Gerät eine Funktion beinhaltet, deren
Verhalten durch eines der definierten Register festgelegt wird, so
muß das PCI-Gerät dieses Register an der dafür
definierten Stelle mit dem definierten Verhalten zur Verfügung
stellen.
Bedeutung der Konfigurations-Register:
Der PCI-Bus hat das Potential, die Konfiguration von Zusatzkarten
wesentlich zu vereinfachen. Dazu müssen aber diese
PCI-Geräte bestimmte Funktionen (über Register) der
Konfigurationssoftware (PCI-BIOS) zur Verfügung stellen. Im
folgenden werden also die Register dieses vordefinierten
Konfigurations-Bereichs vorgestellt. Das exakte Format der Register
(d.h. die Anzahl der implementierten Bits usw.) hängt wiederrum
vom jeweiligen PCI-Gerät ab. Jedoch müssen einige allgemeine
Regeln beachtet werden. So müssen alle Register die
Möglichkeit bieten, die eingestellten Werte zurückzulesen,
und diese gelesenen Daten müssen einen Wert repräsentieren,
den die Karte für die aktuellen Einstellungen gerade verwendet.
Die Konfigurationsregister werden zur Konfiguration, Initialisierung
und für die Behandlung schwerer Fehler verwendet, und sollten nur
von der Initialisierungssoftware (d.h. PCI-BIOS) und eventuellen
Fehlerbehandlungsroutinen verwendet werden. Die Gerätetreiber
selbst sollen nur Zugriffe auf I/O und/oder Memory Bereiche verwenden,
um gerätespezifische Register und damit die Funktionalität
des PCI-Geräts zu manipulieren.
Die Identifikationsregister
Fünf Felder im vordefinierten Bereich sind für die
Identifikation des Geräts vorgesehen. Alle PCI-Geräte
müssen diese Felder unterstützen. Die Konfigurationssoftware
kann somit leicht feststellen, welche Geräte am PCI-Bus des
Rechners verfügbar sind. Alle diese Register sind 'read only'.
Vendor ID: Dieses Feld identifiziert den Hersteller des
PCI-Geräts. Gültige Kennungen werden von der PCI-SIG an
zahlende (!) Mitglieder vergeben, um eine Eindeutigkeit zu
gewährleisten. Diese Herstellerkennung ist 16 Bit breit, wobei
der Wert FFFFhex eine ungültige Vendor ID darstellt und vom
Motherboard bei einem nicht belegten Slot zurückgeliefert wird.
Anhand dieses Wertes kann also das PCI-BIOS unterscheiden, ob in dem
betreffenden Slot eine Karte vorhanden ist oder nicht
Device ID: Dieses Feld identifiziert ein spezielles
Gerät. Die Kennung wird vom Hersteller der Karte selbst vergeben,
und dient zusammen mit der Vendor ID dem Softwaretreiber zum
eindeutigen Erkennen eines PCI-Gerätes. Die Funktion
FindPCIDevice eines PCI-BIOS macht von dieser Möglichkeit
Gebrauch. Ein spezielles Problem ergibt sich aber bei der Verwendung
von Standard Interface Chips wie dem PCI9060. Verwendet man
nämlich z.B. auf einer selbst gebauten Karte einen solchen
Interface Chip, so meldet sich dieser mit seiner eigenen Vendor und
Device ID und zu einer eindeutigen Erkennung und Unterscheidung
solcher Karten ist daher noch eine Subsystem Vendor ID sowie eine
Subsystem Device ID notwendig. Mit diesem Thema wird sich zu einem
späteren Zeitpunkt ein weiterer Artikel beschäftigen.
Revision ID: Dieses Register beinhaltet eine
gerätespezifische Revisionsnummer. Der Wert selbst wird wieder
vom Hersteller der Karte vergeben, wobei auch die Revisionsnummer
00hex erlaubt ist. Dieses Feld sollte daher als herstellerspezifische
Erweiterung zur Device ID angesehen werden.
Header Type: Dieses Byte legt sowohl das Layout der
Bytes 10hex bis 3Fhex des Konfigurationsbereiches fest, als auch die
Information, ob das Gerät weitere Funktionen beinhaltet. Bit 7
dieses Registers wird dazu verwendet, um sogenannte multi function
devices zu kennzeichnen. Ist das Bit 0, so handelt es sich bei diesem
Gerät um ein single function device, ist es hingegen gesetzt, so
hat dieses Gerät mehrere Funktionseinheiten. Bits 6..0 legen
schließlich das Format des zweiten Teils des
Konfigurationsbereiches fest. Das in Tabelle 1 gezeigt Layout gilt
für Standard-Geräte und ist mit Header Type 00hex
gekennzeichnet. Zur Zeit ist noch Header Type 01hex für PCI to
PCI-Bridges definiert.
Class Code: Das Class Code Register ist ebenfalls nur
'read only' und wird dazu verwendet, um die 'Gattung' (die generelle
Funktion) eines PCI-Gerätes festzulegen, sowie in einigen wenigen
Fällen ein Register Interface. Das Register ist dazu in 3 Bytes
unterteilt. Das oberste Byte (an Adresse 0Bhex) stellt die Basisklasse
dar, welche die Funktion dieser Karte ganz allgemein beschreibt. Das
mittlere Byte (an Adresse 0Ahex) ist eine Subklasse, welches die in
der Basisklasse definierte Funktion genauer beschreibt. Im Falle von
Basisklasse 02hex für Network Controller wird hier z.B. weiter
zwischen Ethernet, Token Ring, FDDI und anderen Arten unterschieden.
Das niedrigste Byte (an Adresse 09hex) ist schließlich das
gerätespezifische Register Interface, über das
geräteunabhängige Software mit dem Gerät kommunizieren
kann. Tabelle 2 zeigt die definierten Werte für die Basisklasse.
Der Class Code selbst ermöglicht überhaupt erst die
Zusammenarbeit von geräteunabhängiger Software mit
Standardkomponenten wie etwa einer Grafikkarte, da es eben eine
Fülle an verschiedenen Herstellern (Vendor ID) und verschiedenen
kompatiblen Grafikkarten (Device ID) gibt, die ein Treiber sonst alle
implementieren müßte.
Die Basisklasse 00 hex
Diese Basisklasse wurde definiert, um
Abwärtskompatibilität für diejenigen PCI-Geräte zu
gewährleisten, die bereits vor der Definition der Basisklassen
gebaut wurden. Neue Geräte dürfen diesen Wert nicht mehr
verwenden, und ältere Geräte sollten soweit als möglich
auf einen aussagekräftigeren Wert umsteigen. Für diese
Basisklasse existieren nur zwei Subklassen, alle anderen Werte sind
reserviert.
Diese Basisklasse wurde für alle möglichen
Massenspeicher-Anwendungen definiert. Bisher sind für diese
Geräte keinerlei Register Interfaces definiert
Die Basisklasse 02 hex (Network controller
Diese Basisklasse wurde für die verschiedensten Arten an
Netzwerkkarten definiert. Auch hier gibt es bisher noch keine
definierten Register Interfaces.
Die Basisklasse 03 hex (Display controller)
Diese Basisklasse wurde für alle Arten an Grafikkarten
definiert. Dazu gibt es einige Subklassen, zu denen jeweils ein
eigenes Register Interface existiert.
Die Basisklasse 04 hex (Multimedia device)
Diese Basisklasse definiert die möglichen Typen von
Multimedia Geräten,für die aber keinerlei spezifische
Register Interfaces definiert sind.
Die Basisklasse 05 hex (Memory controller)
Diese Basisklasse definiert alle möglichen Arten an Memory
controllern. Es sind keine spezifischen Register Interfaces definiert.
Die Basisklasse 06 hex (Bridge Device)
Diese Basisklasse definiert alle möglichen Arten von
"Bridge Devices". Eine solche PCI-Bridge ist ein
PCI-Gerät, das PCI-Ressourcen (Memory ode I/O) von der einen
Seite dieses Gerätes auf die andere Seite des Gerätes mappt.
Es gibt mehrere Subklassen und es sind keine spezifischen Register
Interfaces definiert.
Die Kontrollregister
Command:
Status:
Verschiedene Funktionen
Cache Line Size
Latency Timer
Built-in Self Test (BIST)
Interrupt Line:
Interrupt Pin:
MIN_GNT und MAX_LAT
Basis-Addressen:
Memory-Bereiche: (!nl!) Register, die einen Memory-Bereich
anfordern, müssen Bit 0 auf den Wert 0 setzen. Die Register
selbst sind dabei entweder 32 bit oder aber auch 64 bit breit. Zur
Auskodierung der Basisadresse verwendet das PCI-Gerät allerdings
nur Bit 4 bis Bit 31 bzw. Bit63, d.h. Memory-Bereiche beginnen stets
an 16 Byte - Grenzen. Die anderen Bits sind 'read only'. In Bit 3 des
Registers wird mitgeteilt, ob der Adressbereich 'prefetchable' ist,
und in Bit 2 und Bit 1 steht die gewünschte Art des Memory
mappings in der Initialisierungsphase
I/O-Bereiche:
Insgesamt ist im Konfigurationsbereich Platz für sechs
Adreßregister. Das erste Adreßregister beginnt immer an
Offset 10hex. Die Lage des zweiten Adreßregisters hängt
dann allerdings von der Größe (32/64 Bit) des ersten
Registers ab, und beginnt demnach an Offset 14hex bzw. 18hex.
Grafikkarten fordern typischerweise einen I/O-Bereich für die
Kontrollregister und einen Memory-Bereich für den Grafikspeicher
an. Wenn ein PCI-Gerät seine Kontrollregister in den Memory- und
in den I/O-Bereich legen will, muß es dafür auch zwei
Adreßregister 'spendieren'. Grundsätzlich sollten es alle
PCI-Geräte ermöglichen, Kontrollregister in den
Memory-Bereich zu mappen. Das ist aus der Unzulänglichkeit der
PC's entstanden, die einen viel zu kleinen I/O-Bereich besitzen.
Anforderung von Adreßräumen
Milan-Homepage: http://www.milan-computer.de
Letzte Änderung am 08. JuLi 1998, 13:07
Sonder-Edition PCI-BIOS, Part3 Stand: 09. 07. 1998
Das PCI-BIOS 3
Die Idee
Die Idee zum PCI-BIOS für die ATARI-kompatiblen Rechner
entstand aus der Notwendigkeit der Zuordnung von Speicherbereichen zu
den I/O- und Memory-Bereichen der PCI-Geräte. Auf PC's und
Kompatiblen wird die PCI-Funktionalität über eine
Bios-Erweiterung (das PCI-BIOS) standardisiert zur Verfügung
gestellt. Das Bios hat zwei wesentliche Aufgaben. Zum einen die
Bereitstellung einer Schnittstelle für die Software für den
Zugriff auf die PCI-Geräte, zum anderen die Initialisierung und
die Verteilung der Resourcen der einzelnen PCI-Geräte. Die
Initialisierung läuft ohne Eingriffsmöglichkeiten des
Benutzers direkt nach dem Reset ab.
Der Bootvorgang
Nach dem Reset fragt das Hostsystem zuerst das Vorhandensein der
installierten PCI-Geräte ab. Dies erfolgt durch den Zugriff auf
ein definiertes Register (Vendor ID). Zu diesem Zeitpunkt sind
Zugriffe auf die noch unbekannten Karten nur mit den Befehlen
Configuration Read und Configuration Write möglich. Nachdem das
System herausbekommen hat, ob und wo Karten im Rechner stecken, werden
bei allen PCI-Geräten die benötigten Adreßräume
ermittelt. Dies geschieht wie bereits erwähnt durch das Schreiben
des Wertes FFFF'FFFFhex in das jeweilige Adreßregister. Jedes
PCI-Gerät kann maximal 6 Speicherbereiche anfordern. Dabei wird
der jeweils benötigte Adreßbereich im Adreßregister
bitweise ausmaskiert. Werden zur Kodierung zum Beispiel Bit 0 bis Bit
9 verwendet (auskodieren mit FFFF'FC00hex), ist der Bereich 2^10, also
1024 Bytes groß. Es besteht die Wahl zwischen I/O-gemappten und
Memory-gemappten Bereichen (siehe Artikel in Ausgabe 5/98). Für
ein PCI-Gerät unterscheiden sich die beiden Bereiche nur durch
die unterschiedlichen Kommandos an /C/BE[0..3]. Als Antwort teilt das
Hostsystem (BIOS) den einzelnen Geräten jeweils
Adreßbereiche zu - sofern im Adreßraum genug Platz
vorhanden ist. Hier hat z.B. der Hades im Vergleich zum PC einiges
mehr zu bieten, da im PC der I/O-Bereich sehr begrenzt ist. Der Hades
bietet in unserem Fall 256 MB I/O-Bereich und 512 MB Memory-Bereich
an. Das sollte für den Anfang wirklich genügen ;-) Nach der
Anmeldung sind die PCI-Geräte dann selbst für die
Auskodierung ihrer Adreßräume verantwortlich. Die
zugeteilten Adreßräume lassen sich für die
späteren Zugriffe auf I/O- und Memory-Bereich aus den
Konfigurationsregistern der Geräte auch wieder auslesen. In einem
Register des definierten Konfigurationsbereiches (Interrupt Pin) wird
von jedem PCI-Gerät die jeweils benutzte Interrupt-Leitung
mitgeteilt. Das BIOS vergibt daraufhin einen der vorhandenen
Interrupts und stellt die weitere Funktionalität über
BIOS-Routinen zur Verfügung.
Wie sag' ich's meiner PCI-Karte
Der Treiber einer installierten PCI-Hardware durchläuft
demnach folgende Schritte für die Initialisierung und
anschließende Verwendung eines PCI-Boards:
Die PCI-Funktionen
Im folgenden wird also das Software-Interface beschrieben, das von
den PCI-Gerätetreibern und anderer Systemsoftware genutzt werden
kann, um Zugriff auf die PCI-Karten in ATARI-kompatiblen Systemen zu
erhalten. Dieser Artikel soll zunächst das Konzept und die
prinzipiellen Möglichkeiten aufzeigen, daher werden fürs
Erste auch nicht sämtliche vom PCI-BIOS zur Verfügung
gestellten Routinen beschrieben. Die restliche Funktionalität und
weitere Einzelheiten können in der jeweils aktuellen Ausgabe der
ATARI PCI BIOS Specification nachgelesen werden. Aller Vorraussicht
nach wird man diese in naher Zukunft unter
http://www.milan-computer.de finden. Das PCI-Bios installiert einen
"_PCI"-Cookie, über den die BIOS-Routinen lokalisiert
und angesprochen werden können. Für Programmierer gibt es
hierfür bereits eine PCI-Library, die diese Aufgaben erledigt,
und damit einen sehr einfachen Zugriff erlaubt. Die jeweils aktuellen
Versionen des PCI-BIOS für den Hades und die entsprechende
PCI-Library sind unter http://www.wvnet.at/privat/97021702/ zu finden.
Weiters gibt es an dieser Stelle auch ein C-Beispielprogramm zur
Verwendung dieser Library. Sobald die allgemein gültige ATARI PCI
BIOS Specification im Internet erhältlich ist, wird es hier auch
einen Link darauf geben. Beim Milan werden die BIOS-Routinen in einer
der nächsten Versionen des Milan-TOS fix integriert sein, ein
entsprechendes Programm im AUTO-Ordner ist im Gegensatz zum Hades also
dann nicht mehr nötig. Ob und wann dies eventuell auch beim Hades
der Fall sein wird, kann zu diesem Zeitpunkt noch nicht gesagt werden.
Die PCI-BIOS Fehlercodes
Die folgende Fehlercodes können im Fehlerfall von den
BIOS-Routinen zurückgeliefert werden.
Tabelle 1: Fehlercodes der BIOS-Routinen
Die folgenden beiden Fehlercodes werden zwar nicht von den
BIOS-Routinen selbst verwendet, sind aber für eine PCI-Library
reserviert.
Tabelle 2: Fehlercodes der PCI-Library
Find PCI device
Diese Funktion dient dazu, ein bestimmtes PCI-Gerät (eine
PCI-Karte selbst kann ja wiederrum mehrere Funktionseinheiten =
Geräte beherbergen) über Device und Vendor ID zu suchen.
Damit findet ein Softwaretreiber also seine zugehörige Hardware,
sofern sie auch im Rechner installiert wurde. Sollte eine Hardware
mehrfach im System vorhanden sein, oder sich zwei Karten mit den
gleichen IDs melden, so werden die einzelnen Karten über ihren
Index abgefragt. Man beginnt dabei mit Index 0 und erhöht ihn
dann solange, bis die Routine den Fehlercode PCI_DEVICE_NOT_FOUND
zurückliefert.
Eingang:
D0.L Device ID in den Bits 31..16 (0 - $FFFF), Vendor ID in den
Bits 15..0 (0 - $FFFE)
D0.L Geräte-Handle oder PCI-BIOS Fehlercode
LONG handle = find_pci_device (ULONG id, UWORD index)
Find PCI Classcode
Eingang:
Flags:
Bit 26 Base class 0:vergleichen 1:ignorieren
Bit 25 Sub class 0:vergleichen 1:ignorieren
Bit 24 Progr. interface: 0:vergleichen 1:ignorieren
Mit den Bits 24..26 kann man also angeben, welche Teile des
Classcodes
LONG handle = find_pci_classcode (ULONG class, UWORD
index)
class: Classcode des PCI-Gerätes
Diese drei Funktionen erlauben Lesezugriffe auf die
Konfigurationsregister eines PCI-Gerätes, dessen
Geräte-Handle zuvor mittels find_pci_device oder
find_pci_classcode ermittelt wurde.
Aufruf in Assembler:
Eingang:
D0.L Geräte-Handle des gewünschten PCI-Gerätes
Ausgang:
D0.L PCI-BIOS Fehlercode
LONG errorcode = read_config_byte (LONG handle, UBYTE reg, UBYTE
*adresse)
Diese drei Funktionen erlauben das Lesen von Registern im Konfigurationsbereich ohne aufwendige Fehler- und Plausibilitätschecks und sind daher auch etwas schneller als
ihre 3 Schwestern (daher besonders geeignet für
Interrupt-Routinen und wenn man ganz genau weiß, was man tut
;-). Der Registerinhalt wird im Returnwert abgelegt. Dadurch
können diese Funktionen in C-Programmen noch einfacher angewendet
werden.
Aufruf in Assembler:
D0.L Geräte-Handle des gewünschten PCI-Gerätes
Ausgang:
D0 gelesener Wert (8, 16 oder 32 Bits)
UBYTE value = fast_read_config_byte (LONG handle, UBYTE reg)
Beispiele:
1) device_vendor = fast_read_config_longword (handle, 0)
Aufruf in Assembler:
LONG errorcode = write_config_byte (LONG handle, UBYTE reg, UBYTE
val)
Aufruf in Assembler:
LONG value = interrupt_handler (LONG *value, LONG internal)
Aufruf in Assembler:
Eingang:
D0.L Geräte-Handle des gewünschten PCI-Gerätes
Aufruf in C:
dies ist ein vom Treiber frei zu wählender Wert, der bei
jedem Aufruf des Handlers vom BIOS mitübergeben wird. Dadurch
könnte ein einziger Interrupt-Handler auch mehrere baugleiche
PCI-Geräte bedienen.
Aufruf in Assembler:
D0.L Geräte-Handle des gewünschten PCI-Gerätes
Get Resource Data
D0.L Zeiger auf ersten Resource Deskriptor bzw. PCI-BIOS
Fehlercode
BIOS-interne Daten, dürfen nicht verändert werden
Um den Deskriptor der nächsten Resource des PCI-Gerätes
zu ermitteln, muß man zur Startadresse des aktuellen Deskriptors
das Feld next addieren. Das Feld start gibt den Beginn der
entsprechenden Resource im PCI-Adreßbereich an. Falls diese
Resource nicht direkt ansprechbar sein sollte, so steht in diesem Feld
die Adresse 0. Über length kann man schließlich die
Länge dieser Resource bestimmen. Der PCI-Adreßbereich ist
im allgemeinen nicht mit der von der CPU aus gesehenen Adresse
gleichzusetzen. Der Adreß-Offset, der zur PCI-Adresse zu
addieren ist, um die physikalische Adresse für die CPU zu
ermitteln, ist im Feld offset abgelegt.Der Eintrag dmaoffset gibt
schließlich den Offset an, der zur PCI-Adresse addiert werden
muß, wenn es sich um DMA-Transfers handelt.
Tabelle 4: Die Flags im Resource-Deskriptor
Quellenverzeichnis:
[1] PCI Local Bus Specification Revision 2.0
Vielen Dank an Konstantin Woller für diese Infos.
Copyright © Robert Schaffner (doit@doitarchive.de) Letzte Aktualisierung am 23. Mai 2004 |