.. _z3-casinodev: ========================== Urządzenie CasinoDev ========================== .. contents:: Urządzenie ========== Urządzenie jest podłączane do komputera przez szynę PCI -- identyfikator producenta to ``0x0666``, a identyfikator urządzenia to ``0x777``. Urządzenie nie posiada własnej pamięci i operuje na buforach w głównej pamięci komputera przez bezpośredni dostęp do pamięci (DMA). Ponieważ główna pamięć komputera podlega fragmentacji, a urządzenie może używać całkiem dużo pamięci, urządzenie wykonuje dostęp do pamięci przez tablicę stron w swoim własnym formacie. Urządzenie jest zaprojektowane tak, by można było je obsługiwać z minimalną ingerencją jądra w przesyłane polecenia — wszystkie polecenia są walidowane przez urządzenie i operują tylko tylko na adresach wirtualnych, tłumaczonych przez tabele stron — użytkownik przygotowujący bufor poleceń nie ma możliwości zawieszenia urządzenia ani dostępu do nie swojej pamięci. Co najwyżej, może spowodować zgłoszenie błędu przez urządzenie, który może być obsłużony przez jądro systemu. Urządzeniem steruje się przez rejestry wejścia/wyjścia zmapowane do pamięci (MMIO). Ten obszar MMIO jest pierwszym i jedynym obszarem BAR używanym przez urządzenie (BAR0). Urządzenie wykorzystuje również jedną linię przerwania PCI. Obszar MMIO ma wielkość 64kiB, ale tylko niektóre bajty z tego zakresu są używane na rejestry. Wszystkie udokumentowane rejestry są 32-bitowe w formacie little-endian i powinny być używane tylko przez wyrównane 32-bitowe odczyty i zapisy. Bufory i blok stronicowania =========================== Wszystkie dane i polecenia używane przez urządzenie są zawarte w stronicowanych buforach. Urządzenie może jednocześnie używać do 16 buforów — blok stronicowania ma 16 "slotów" (identyfikowane przez liczby 0..15), w które można wpiąć bufor za pomocą polecenia ``BIND_SLOT``. Każdy slot ma następujące atrybuty, wybierane przy wpięciu bufora: - ``ENABLED``: jeśli ustawiony, do slota wpięty jest bufor, ma tabelę stron, i może być użyty przez urządzenie; jeśli nie jest ustawiony, każda próba użycia tego slotu spowoduje błąd - ``TYPE``: Określa typ talii wpiętej w bufor (52 lub 24 karty) - ``PT_ADDR``: adres fizyczny tabeli stron - ``SEED``: używany do losowego generowania kart Urządzenie używa 40-bitowych adresów fizycznych (zarówno dla buforów jak i dla tabel stron), 22-bitowych adresów wirtualnych w ramach bufora, i stron o rozmiarze 4kiB. Tabele stron używane przez urządzenie są jednopoziomowe: - jądro podaje urządzeniu adres fizyczny katalogu stron przy podpinaniu bufora - bity 12-21 adresu wirtualnego wybierają wpis w tabeli stron (page table), który zawiera adres fizyczny strony - bity 0-11 adresu wirtualnego to offset wewnątrz strony Tabele stron mają rozmiar 4kiB (taki jak strona) i składają się z 1024 wpisów, gdzie każdy wpis jest 32-bitowym słowem w formacie little-endian. Wpis w tabeli stron ma następujący format: - bit 0: ``PRESENT`` — jeśli ustawiony, dany wpis jest obecny i może być użyty. Jeśli wyzerowany, wpis jest nieobecny i użycie go spowoduje błąd braku strony (``MEM_ERROR``). - bity 4-31: ``PA`` — bity 12-39 adresu fizycznego strony (bity 0-11 adresu są zawsze równe 0 — strony muszą być wyrównane). Katalog stron wybiera się, podając bity 12-39 jego adresu fizycznego (czyli adres przesunięty w prawo o 12 bitów). Jeśli urządzenie napotka niepoprawny adres wirtualny (bez flagi ``PRESENT``), zgłaszane jest przerwanie ``MEM_ERROR``. Wysyłanie poleceń ================= Urządzenia używa się przez wysyłanie mu poleceń. Polecenia składają się ze zmiennej liczby 32-bitowych słów w formacie little-endian. Istnieje 6 różnych typów poleceń, rozróżnianych po niskich 4 bitach pierwszego słowa. Wszystkie nieużywane pola muszą być ustawione na 0 — w przeciwnym wypadku, zachowanie urządzenia nie jest zdefiniowane. Urządzenia mogą być wysyłane do urządzenia ręcznie przez zapis kolejnych słów polecenia do rejestru MMIO urządzenia. Ręczne wysyłanie poleceń ------------------------ Polecenia można wysyłać do urządzenia bezpośrednio przez MMIO, używając następujących rejestrów: ``BAR0 + 0x008c: CMD_MANUAL_FREE`` Rejestr tylko do odczytu. Odczytana wartość jest liczbą wolnych miejsc w kolejce poleceń (tyle słów można natychmiast zapisać do ``CMD_MANUAL_FEED`` bez obaw o ``FEED_OVERFLOW``). Kolejka ta ma maksymalną pojemność 255 słów. Można założyć, że ten rejestr będzie równy 255 bezpośrednio po resecie urządzenia bądź gdy zostaną przetworzone wszystkie wcześniej wysłane polecenia. ``BAR0 + 0x008c: CMD_MANUAL_FEED`` Rejestr tylko do zapisu. Każdy zapis do tego rejestru wysyła jedno słowo do kolejki poleceń. Jeśli kolejka jest już pełna (``CMD_MANUAL_FREE == 0``), zamiast tego wyzwalane jest przerwanie ``FEED_ERROR``. Polecenie ``NOP`` ----------------- Nic nie robi. Składa się z 1 słowa. Może być użyte do zapchania nieużywanych słów w buforze poleceń, jeśli czujemy taką potrzebę. - słowo 0: nagłówek - bity 0-3: typ polecenia (``0x0``) Polecenie ``BIND_SLOT`` ----------------------- Służy do wpięcia bufora do slotu. Składa się z 2 słów: - słowo 0: nagłówek - bity 0-3: typ polecenia (``0x1``) - bity 4-7: ``SLOT`` — numer slotu, który przepinamy - bity 12-27: ``SEED`` — inicjalny SEED bufora - bity 28-31: ``TYPE``— typ talii - słowo 1: - bity 0-31: ``PA``: pierwsze 32 bity pełnego fizycznego adresu tabeli stron - słowo 2: - bity 0-31: ``PA``: ostatnie 32 bity pełnego fizycznego adresu tabeli stron Polecenie ``GET_CARDS`` ----------------------- Służy do pobrania zadanej liczby kart. Składa się z 1 słowa: - słowo 0: nagłówek - bity 0-3: typ polecenia (``0x2``) - bity 4-19: ``NUM`` — liczba kart które chcemy pobrać - bity 20-23: ``OUTPUT_TYPE`` — Typ pobrania kart: ``FAIR`` (karty są uczciwie losowane) lub ``GOOD`` / ``BAD`` aby celowo zwracać lepsze i gorsze karty. - bity 24-27: ``SLOT``— Numer slotu z buforem w którym zwracamy karty, ustawiane przez sterownik. Polecenie ``FENCE`` ------------------- Służy do powiadamiania sterownika o zakończeniu wykonywania wszystkich poprzednich poleceń. Składa się z 1 słowa. - słowo 0: nagłówek - bity 0-3: typ polecenia (``0x3``) - bity 4-31: ``VAL`` — parametr; nie ma zdefinowanej semantyki przez urządzenie, zalecamy użycie go jako numeru kolejnej serii poleceń (modulo ``2**28``). To polecenie ma następujące efekty: 1. Oczekuje na pełne zakończenie wykonania wszystkich wcześniejszych poleceń. 2. Ustawia wartość rejestru ``CMD_FENCE_LAST`` na parametr ``VAL`` 3. Jeśli parametr ``VAL`` jest równy rejestrowi ``CMD_FENCE_WAIT``, wyzwala przerwanie ``FENCE_WAIT``. ``BAR0 + 0x0090: CMD_FENCE_LAST`` 28-bitowy rejestr do odczytu i zapisu, ustawiany na parametr ``VAL`` przy wykonaniu polecenia ``FENCE``. Może być użyty do ustalenia, które polecenia już zostały wykonane. Zalecamy zapisanie go ze sterownika dokładnie raz, przed uruchomieniem urządzenia, aby nadać mu wartość początkową. ``BAR0 + 0x0094: CMD_FENCE_WAIT`` Rejestr do odczytu i zapisu, służy do wyzwolenia przerwania gdy podane polecenie ``FENCE`` zostanie wykonane. - bity 0-27: ``VAL``, wartość na którą sterownik czeka. Gdy zostanie wykonane polecenie ``FENCE`` z równą wartością, zostaje wyzwolone przerwanie ``FENCE_WAIT``. Polecenie ``NEW_DECK`` ----------------------- Służy do wygenerowania i przetasowania nowej talii. Składa się z 1 słowa: - słowo 0: nagłówek - bity 0-3: typ polecenia (``0x4``) - bity 4-7: ``SLOT``— Numer slotu z buforem w którym zwracamy karty, ustawiane przez sterownik. Polecenie ``UNBIND_SLOT`` ----------------------- Służy do odpięcia nieużywanego slotu. Składa się z 1 słowa: - słowo 0: nagłówek - bity 0-3: typ polecenia (``0x5``) - bity 4-7: ``SLOT``— Numer slotu który zwalniamy po stronie urządzenia. Rejestry sterujące ================== Poza wcześniej opisanymi rejestrami urządzenie używa również: ``BAR0 + 0x0008: ENABLE`` Rejestr kontrolujący pracę pozostałych bloków, dostępny do odczytu i zapisu. Jeśli jego wartość to 0 to komendy nie są przetwarzane. ``BAR0 + 0x000c: INCREMENT_SEED`` Rejestr odpowiadający za funkcjonalność inkrementacji seedów buforów przy nowym losowaniu, dostępny do odczytu i zapisu. Domyślnie jest ustawiony na 0 (m.in. dla łatwiejszego testowania), ale praktyczne zastosowanie urządzenia zakłada jego przestawienia na 1. ``BAR0 + 0x0010: PROC_STATE`` Rejestr odpowiadający za stan obsługi wczytanych poleceń, dostępny do odczytu i zapisu. Przerwania ---------- Urządzenie wewnętrznie używa 5 przerwań (które są agregowane w jedno przerwanie PCI): - ``FENCE_WAIT`` — przerwanie używane do powiadomienia sterownika o wykonaniu wybranego polecenia ``FENCE`` przez blok ``CMD``. - ``FEED_ERROR`` — użycie rejestru ``CMD_MANUAL_FEED``, gdy nie ma miejsca w kolejce - ``CMD_ERROR`` — wyzwalane, gdy urządzenie otrzyma niepoprawne polecenie - ``MEM_ERROR`` — wyzwalane, gdy urządzenie otrzyma nieprawidłowy dostęp do pamięci - ``SLOT_ERROR`` — wyzwalane, gdy urządzenie otrzyma zapytanie używające nieaktywnego slotu Każde z powyższych przerwań może być w danej chwili aktywne bądź nie. Przerwanie staje się aktywne, gdy zajdzie odpowiednie zdarzenie. Przerwanie staje się nieaktywne, gdy sterownik zapisze 1 do odpowiedniego bitu w rejestrze ``INTR``. Aby sprawdzić, które przerwania są aktywne, należy przeczytać rejestr ``INTR``. Niezależnie, każde z powyższych przerwań może być w danej chwili włączone bądź nie. Sterownik może ustawić włączony podzbiór przerwań przez zapis odpowiedniej maski do rejestru ``INTR_ENABLE``. Urządzenie zgłasza przerwanie na swojej linii przerwań PCI wtedy i tylko wtedy, gdy istnieje włączone i aktywne przerwanie. ``BAR0 + 0x0000: INTR`` Rejestr statusu przerwań. Ma 5 bitów, każdy odpowiadający jednemu rodzajowi przerwań: - bit 0: ``FENCE_WAIT``, - bit 1: ``FEED_ERROR``, - bit 2: ``CMD_ERROR``, - bit 3: ``MEM_ERROR``, - bit 4: ``SLOT_ERROR`` Odczyt tego rejestru zwróci 1 dla aktywnych przerwań, 0 dla nieaktywnych. Zapis spowoduje wyzerowanie (ustawienie na nieaktywne) wszystkich przerwań, dla których został zapisany bit 1. ``BAR0 + 0x0004: INTR_ENABLE`` Rejestr włączania przerwań, dostępny do odczytu i zapisu. Ma takie same bity jak ``INTR``. 1 oznacza przerwanie włączone, a 0 — przerwanie wyłączone. Przy resecie maszyny, rejestr zostaje ustawiony na 0, blokując możliwość zgłaszania przerwania PCI przez urządzenie do momentu załadowania sterownika. Uruchomienie urządzenia ----------------------- Poprawna procedura uruchamiania urządzenia jest następująca (użycie dowolnej innej procedury spowoduje utratę gwarancji i brak możliwości zwrotu urządzenia): - wyzerować ``INTR`` - włączyć używane przez nas przerwania w ``INTR_ENABLE``, - włączyć wszystkie bloki urządzenia w ``ENABLE``. - zainicjować ``CMD_FENCE_LAST`` i ``CMD_FENCE_WAIT``, jeśli czujemy taką potrzebę. Żeby wyłączyć urządzenie, wystarczy zapisać 0 do ``ENABLE`` oraz ``INTR_ENABLE``. W przypadku zgłoszenia błędu przez urządzenie, należy je zresetować w sposób analogiczny do uruchamiania urządzenia.