L’evoluzione tecnologica richiede, con sempre, maggiore incisività, strumenti che possano garantire un aumento delle prestazioni. Per questa ragione il Bus PCI non ha potuto esimersi da questa responsabilità, tanto da offrire una versione enhanced in grado di assicurare nuovi requisiti prestazionali.
L’evoluzione tecnologica degli ultimi anni, e il conseguente aumento delle prestazioni, hanno incrementato in modo esponenziale la richiesta di banda tra i suoi diversi sottosistemi. Infatti, a questo riguardo sono state proposte numerose possibilità per superare i limiti dell’ormai limitato bus PCI e si è creata una certa confusione circa il posizionamento di queste nuove tecnologie e su come esse possano collaborare. A questo proposito, il bus PCI (Peripheral Component Interconnect), introdotto nei primi anni Novanta, è stato originariamente concepito come interfaccia di connessione tra i chip presenti sulle schede madri ma si è presto evoluto, costituendo prima un rimpiazzo per la tecnologia ISA e quindi il principale sistema di Input/Output su server e piattaforme di comunicazione. Il bus PCI, nella sua prima versione, operava a una frequenza di 33 MHz e comunicava mediante un canale a 32 bit: queste caratteristiche potevano permettere al bus di raggiungere una banda passante di 133 Mbyte/s, ma questa doveva però essere condivisa da tutte le unità presenti sul bus.
Successivamente, nel corso degli anni, quindi, la banda è stata portata a 533 Mbyte/s attraverso il raddoppio della frequenza di clock e dei bit trasmessi per ciclo: queste evoluzioni sono indirizzate principalmente per ambienti server che richiedono un’elevata capacità di comunicazione. L’attuale panorama tecnologico richiede, sempre con maggiore incisività, nuove richieste in termini di prestazioni, affidabilità e scalabilità tanto da trasformare il bus PCI in uno dei principali colli di bottiglia nei sistemi di comunicazione di oggi: i server devono rendere disponibili grandi quantità di dati a milioni di utenti non solo appartenenti alla rete locale ma anche connessi tramite Internet.
Con le ultime versioni dello standard PCI, ossia con la versione PCI Express 2.0, si è portato l’ampiezza di banda a 20 Gbps con connessione 16X. A questo riguardo, la tecnologia InfiniBand può rappresentare un’interessante applicazione; infatti, questo è un protocollo di comunicazione ad alta velocità per l’interconnessione fra un processore e diversi nodi. InfiniBand è fondato su un’architettura punto-punto basata su canali di comunicazione seriali. La rete a commutazione può avere come nodi server, canali in fibra, router e sistemi di storage. Ogni nodo può comunicare con gli altri in una configurazione a più collegamenti e le ridondanze possono essere utilizzate per incrementare la robustezza del sistema. Da un punto di vista fisico, un singolo canale InfiniBand ha una struttura molto simile a un’architettura PCI Express: sono presenti due linee per direzione in grado di fornire una banda di 2,5 Gbps (250 Mbyte al secondo utilizzando un metodo di codifica a 8/10 bit simile a quello di PCI Express). I canali possono essere aggregati lungo un collegamento in configurazioni da 1, 4 o 12 coppie di segnali. La banda massima raggiungibile è poco più di 90 Gbps per direzione, se si utilizza la modalità 12x. Sono supportati collegamenti sia in fibra sia in rame. La distanza massima tra due nodi connessi tramite fibra è di oltre 300 metri e ogni sottorete può gestire fino a 64.000 nodi.
SITUAZIONE PRIMA DEL PCI EXPRESS
Il bus PCI è uno dei bus più utilizzati in sistemi di interconnessione dei componenti periferici, probabilmente anche grazie al fatto che è stato progettato in maniera indipendente dall’architettura e questo ne ha permesso l’adozione in molti sistemi diversi. Secondo quanto si prevede, nello standard PCI in ogni sistema può esserci più di un bus, ognuno contenente più periferiche PCI che a loro volta possono possedere una o più funzioni. Nel bus PCI ogni funzione può essere identificata da un indirizzo di 16 bit che viene interpretato suddividendolo in tre blocchi. Dalla Figura 1 possiamo notare che i primi 8 bit sono letti come numero di bus: in ogni sistema è possibile far coesistere fino a 28 (ovvero 256) bus.
Il prossimo campo identifica un blocco di 5 bit come numero del dispositivo all’interno di un bus: possiamo avere al massimo 25 dispositivi per bus. Infine, l’ultimo valore, 3 bit, serve ad associare un massimo di 8 funzioni a ogni dispositivo. Una periferica PCI dispone di tre spazi di indirizzi, ossia spazio di I/O (attraverso le porte di I/O), spazio di memoria e spazio (o registri) di configurazione. Il canale di comunicazione del bus PCI usato per accedere ai primi due spazi di indirizzi è condiviso da tutte le periferiche collegate sullo stesso bus: questo determina la condivisione dei dati in transito e rende necessario un arbitraggio del canale per evitare collisioni. L’accesso ai registri di configurazione avviene invece attraverso un indirizzamento geografico, ovvero una periferica alla volta. In effetti, con il registro configurazione non c’è condivisione e non è necessario alcun arbitraggio. Ogni slot PCI ha 4 possibili linee di IRQ e ciascuna funzione usa una sola di queste linee: la scelta avviene in fase di configurazione, dove viene anche assegnato il numero di IRQ. In un bus PCI lo spazio di I/O è raggiunto mediante indirizzi fino a 32 bit, mentre per le locazioni di memoria sono possibili sia indirizzi a 32 bit, sia a 64 bit. Questi indirizzi vengono fissati durante la fase di inizializzazione della periferica da parte del firmware e quindi all’avvio del sistema oppure, nel caso di una periferica con supporto del tipo hot plug, durante il suo caricamento.
Questi indirizzi vengono scritti nei registri di configurazione PCI e permettono a uno sviluppatore di driver di leggerli semplicemente, evitando le complesse procedure di ricerca delle risorse. È bene ricordare che ogni funzione di un dispositivo PCI dispone del proprio spazio di configurazione: questo vuol dire che alcuni registri presenti sul dispositivo permettono, ad esempio, una facile identificazione della funzione e degli indirizzi delle risorse di cui quest’ultima dispone. Lo spazio di configurazione è raggiunto attraverso apposite istruzioni e non usa né lo spazio di indirizzi della memoria, né le porte di I/O; tipicamente viene utilizzato durante la fase di boot, ma rimane comunque sempre accessibile. Lo spazio di configurazione ha una dimensione minima di 256 byte: i primi 64 contengono un’intestazione comune a tutti i dispositivi e hanno un significato ben definito nello standard, mentre gli altri sono eventualmente decisi dalla casa produttrice e a questo riguardo la Tabella 1 mostra i diversi campi utilizzati. All’interno dell’intestazione stessa, solo i primi 16 byte assumono sempre lo stesso significato, mentre i restanti 48 byte dipendono dal tipo di funzione.
Il campo HT (Header Type) definisce il tipo di intestazione e conseguentemente determina il significato degli ultimi 48 byte, vedi Tabella 2.
IL PCI EXPRESS NON È UN BUS
La prima cosa da tener presente su PCI Express (PCIe) è che non si tratta di un PCI-X né di qualsiasi altra versione PCI. Le versioni precedenti PCI, PCI-X incluso, sono veri e propri bus, ossia connessioni parallele che raggiungono fisicamente diversi slot per le schede periferiche. In realtà, PCIe è come una rete dove ogni board è connessa a un commutatore di rete attraverso un insieme dedicato di fili: esattamente come una rete locale Ethernet. Non solo, la comunicazione assume la forma di pacchetti trasmessi su queste linee dedicate, con controllo di flusso, rilevazione di errore e ritrasmissioni. Non ci sono indirizzi MAC, ma abbiamo, invece, la posizione sulla rete. In effetti, in un sistema di questo tipo il PCI Express utilizza un data frame di tipo pacchetto allo scopo di comunicare le informazioni tra i componenti. I pacchetti sono strutturati in Transaction and Data Link Layer allo scopo di trasportare le informazioni dal componente trasmettente al componente ricevente. Per questa ragione la struttura dei pacchetti cambia in base alle informazioni addizionali che devono essere inserite: per similitudine è possibile affermare che un messaggio di questo tipo si può paragonare a una pila stack di rete. In questo modo, sul lato ricevente è necessario trasformare i pacchetti dalla loro rappresentazione fisica a quella definita come Data Link Layer. A questo riguardo la Figura 2 mostra la rappresentazione a pila dei dati mentre la Figura 3 pone in evidenza l’incapsulamento adottato.
TRANSACTION LAYER
La figura pone in evidenza che lo strato superiore dell’architettura è quello di transazione. La responsabilità primaria del livello Transaction è il montaggio e lo smontaggio di pacchetti di livello Transaction (TLP): questo strato si deve preoccupare di comunicare le transazioni, ossia le operazioni di lettura e scrittura, oltre ad alcuni tipi di eventi. Ogni pacchetto ha un identificatore unico che consente ai pacchetti di risposta di essere diretti verso il suo corretto destinatario. Il formato del pacchetto supporta diverse forme di indirizzamento a seconda del tipo di transazione (memoria, I/O, configurazione e Message). Il livello di transazione supporta quattro spazi di indirizzamento, quali i tre spazi di indirizzamento PCI (memoria, I/O e la configurazione) con uno spazio Message. Lo standard utilizza lo spazio dei messaggi per supportare tutti i segnali, quali Interrupt o Power Management. Si potrebbe pensare le transazioni PCI Express come messaggi composti da “virtual wires”, in quanto il loro effetto è quello di eliminare la vasta gamma di segnali di banda laterale attualmente utilizzati in una implementazione della piattaforma.
DATA LINK LAYER
Il Data Link Layer rappresenta lo strato intermedio della pila; in effetti, il Data Link Layer serve come uno stadio intermedio tra il livello delle transazioni e il Physical Layer. La responsabilità principale del Data Link Layer include la gestione dei collegamenti e l’integrità dei dati, incluso il rilevamento degli errori e la loro correzione. Il lato trasmissione del Data Link Layer accetta TLPs assemblati dallo strato di transazione, calcola e applica un codice di protezione dei dati e un numero di sequenza TLP, e li sottopone a livello fisico per la trasmissione attraverso il Link. La ricezione di questo strato si preoccupa di controllare l’integrità del TLPs ricevuto e la loro presentazione per lo strato di transazione per ulteriori elaborazioni. Il Data Link Layer genera e consuma i pacchetti che vengono utilizzati per le funzioni di gestione dei collegamenti. Per differenziare questi pacchetti da quelli utilizzati dallo strato Transaction (TLP) viene utilizzato il termine di Packet Data Link Layer (DLLP) e ci si riferisce ai pacchetti che vengono generati e consumati nel Data Link Layer.
TRASMISSIONE E RICEZIONE
Se volessimo inviare il dato 0x12345678 utilizzando un bus PCI Express sull’indirizzo fisico 0x0xfdaff040 con un 32-bit addressing, allora il pacchetto dovrebbe essere composto da quattro long word (32 bit, o 4 DWs Double Words) come messo in evidenza nella Figura 4.
Al contrario, vediamo che cosa succede quando la CPU vuole leggere da una periferica. Le operazioni di lettura mostrano che ci sono due pacchetti coinvolti: un TLP dalla CPU alla periferica, una richiesta per effettuare un’operazione di lettura e un TLP in ricezione con in dati. Questo vuol dire che, in termini PCIe, abbiamo una Requester (la CPU nel nostro caso) e una Completer (la periferica). Così, se la CPU desidera un unico DW (32 bit) da indirizzo Oxfdaff040 è necessario avviare un’operazione di lettura sul bus che condivide con il suo controller di memoria, contenente il suo Root Complex, il quale a sua volta genera un TLP da inviare attraverso il bus PCIe, Figura 5. Infatti, la Figura 5 mostra tre DW (Ox00000001, Ox00000c0f, Oxfdaff040) che chiedono di leggere dalla periferica un DW all’indirizzo Oxfdaff040.