Improvements to AHCI driver and part of a IDE PIO driver.

This commit is contained in:
Ali Mashtizadeh 2014-07-05 18:46:59 -07:00
parent 696101f277
commit fdb5c1b2c8
4 changed files with 243 additions and 6 deletions

View File

@ -18,8 +18,9 @@ src_amd64 = [
"amd64/pmap.c", "amd64/pmap.c",
"amd64/lapic.c", "amd64/lapic.c",
"amd64/ioapic.c", "amd64/ioapic.c",
"dev/x86/vgacons.c",
"dev/x86/debugcons.c", "dev/x86/debugcons.c",
"dev/x86/vgacons.c",
"dev/x86/ide.c",
] ]
src_common = [ src_common = [

View File

@ -87,5 +87,6 @@ void Machine_Init()
IOAPIC_Init(); IOAPIC_Init();
PCI_Init(); PCI_Init();
IDE_Init();
} }

View File

@ -261,6 +261,18 @@ AHCI_Init(uint32_t bus, uint32_t slot, uint32_t func)
} }
} }
void
AHCI_Dump(AHCI *ahci)
{
volatile AHCIHostControl *hc = ahci->hc;
kprintf("CAP: 0x%08x\n", hc->cap);
kprintf("GHC: 0x%08x\n", hc->ghc);
kprintf("IS: 0x%08x\n", hc->is);
kprintf("PI: 0x%08x\n", hc->pi);
kprintf("VS: 0x%08x\n", hc->vs);
}
void void
AHCI_DumpPort(AHCI *ahci, int port) AHCI_DumpPort(AHCI *ahci, int port)
{ {
@ -351,6 +363,8 @@ AHCI_IdentifyPort(AHCI *ahci, int port)
kprintf("AHCI: Identify Succeeded Port %d\n", port); kprintf("AHCI: Identify Succeeded Port %d\n", port);
Debug_PrintHex((const char *)&ident, 512, 0, 512); Debug_PrintHex((const char *)&ident, 512, 0, 512);
AHCI_DumpPort(ahci, port); AHCI_DumpPort(ahci, port);
uint64_t val = (uint64_t)&ident;
Debug_PrintHex((const char *)&val, 8, 0, 8);
return; return;
} }
@ -377,6 +391,10 @@ AHCI_ResetPort(AHCI *ahci, int port)
} }
} }
// Reset interrupts
p->is = 0xFFFFFFFF;
p->is = 0x00000000;
// Reset error // Reset error
p->serr = 0xFFFFFFFF; p->serr = 0xFFFFFFFF;
p->serr = 0x00000000; p->serr = 0x00000000;
@ -406,9 +424,23 @@ void
AHCI_Reset(AHCI *ahci) AHCI_Reset(AHCI *ahci)
{ {
int port; int port;
volatile AHCIHostControl *hc = ahci->hc;
// Enable AHCI and Interrupts AHCI_Dump(ahci);
ahci->hc->ghc = AHCI_GHC_AE | AHCI_GHC_IE;
// Reset controller
uint32_t caps = hc->cap;
uint32_t pi = hc->pi;
hc->ghc |= AHCI_GHC_AE;
hc->ghc |= AHCI_GHC_HR;
while (1) {
if ((hc->ghc & AHCI_GHC_HR) == 0)
break;
}
hc->ghc |= AHCI_GHC_AE;
AHCI_Dump(ahci);
// Reset ports // Reset ports
for (port = 0; port < AHCI_MAX_PORTS; port++) for (port = 0; port < AHCI_MAX_PORTS; port++)
@ -417,12 +449,18 @@ AHCI_Reset(AHCI *ahci)
AHCI_ResetPort(ahci, port); AHCI_ResetPort(ahci, port);
} }
} }
// XXX: Clear interrupts
// Enable Interrupts
hc->ghc = AHCI_GHC_IE;
} }
void void
AHCI_Configure(PCIDevice dev) AHCI_Configure(PCIDevice dev)
{ {
AHCI *ahci = (AHCI *)PAlloc_AllocPage(); AHCI *ahci = (AHCI *)PAlloc_AllocPage();
volatile AHCIHostControl *hc;
PCI_Configure(&dev); PCI_Configure(&dev);
@ -445,10 +483,17 @@ AHCI_Configure(PCIDevice dev)
// XXX: Register IRQ // XXX: Register IRQ
// Setup // Setup
ahci->hc = dev.bars[AHCI_ABAR].base; hc = dev.bars[AHCI_ABAR].base;
ahci->hc = hc;
uint32_t ports = ahci->hc->pi; // Disable Interrupts
uint32_t vers = ahci->hc->vs; hc->ghc &= ~AHCI_GHC_IE;
// Enable AHCI Controller
hc->ghc |= AHCI_GHC_AE;
uint32_t ports = hc->pi;
uint32_t vers = hc->vs;
kprintf("AHCI: Version %d.%d, Ports: 0x%08x\n", kprintf("AHCI: Version %d.%d, Ports: 0x%08x\n",
vers >> 16, vers & 0xFFFF, ports); vers >> 16, vers & 0xFFFF, ports);

190
sys/dev/x86/ide.c Normal file
View File

@ -0,0 +1,190 @@
#include <stdbool.h>
#include <stdint.h>
#include <kassert.h>
#include <sga.h>
#include "ioport.h"
/*
* ATA Definitions
*/
typedef struct ATAIdentifyDevice
{
uint16_t _rsvd0[10]; // 0-9
uint8_t serial[20]; // 10-19 - Serial
uint16_t _rsvd1[3]; // 20-22
uint8_t firmware[8]; // 23-26 - Firmware
uint8_t model[40]; // 27-46 - Model
uint16_t _rsvd2[16]; // 47-62 X
uint16_t dmaMode; // 63 - DMA Mode
uint16_t _rsvd3[11]; // 64-74 X
uint16_t queueDepth; // 75 - Queue Depth
uint16_t sataCap; // 76 - SATA Capabilities
uint16_t ncqCap; // 77 - NCQ Capabilities
uint16_t _rsvd4[8]; // 78-85
uint16_t deviceFlags; // 86 - Device Flags (48-bit Addressing)
uint16_t deviceFlags2; // 87 - Device Flags 2 (SMART)
uint16_t udmaMode; // 88 - Ultra DMA Mode
uint16_t _rsvd5[11]; // 89-99
uint64_t lbaSectors; // 100-103 - User Addressable Logical Sectors
uint16_t _rsvd6[151]; // 104-254
uint16_t chksum; // 255 - Checksum
} ATAIdentifyDevice;
/*
* IDE Definitions
*/
#define IDE_PRIMARY_BASE 0x1F0
#define IDE_PRIMARY_DEVCTL 0x3F6
#define IDE_PRIMARY_IRQ 14
#define IDE_SECONDARY_BASE 0x170
#define IDE_SECONDARY_DEVCTL 0x376
#define IDE_SECONDARY_IRQ 15
// Port Offsets
#define IDE_DATAPORT 0
#define IDE_FEATURES 1
#define IDE_SECTORCOUNT 2
#define IDE_LBALOW 3
#define IDE_LBAMID 4
#define IDE_LBAHIGH 5
#define IDE_DRIVE 6
#define IDE_COMMAND 7 /* Write */
#define IDE_STATUS 7 /* Read */
// Drives
#define IDE_DRIVE_MASTER 0xA0
#define IDE_DRIVE_SLAVE 0xB0
// IDE Commands
#define IDE_CMD_READ
#define IDE_CMD_WRITE
#define IDE_CMD_IDENTIFY 0xEC
// Status
#define IDE_STATUS_ERR 0x01 /* Error */
#define IDE_STATUS_DRQ 0x08 /* Data Ready */
#define IDE_STATUS_SRV 0x10 /* Overlapped-mode Service Request */
#define IDE_STATUS_DF 0x20 /* Drive Fault Error */
#define IDE_STATUS_RDY 0x40 /* Ready */
#define IDE_STATUS_BSY 0x80 /* Busy */
#define IDE_CONTROL_SRST 0x04 /* Software Reset */
typedef struct IDE
{
uint16_t base; // Base Port
uint16_t devctl; // Device Control
} IDE;
bool IDE_HasController(IDE *ide);
void IDE_Reset(IDE *ide);
void IDE_Identify(IDE *ide, int drive);
void
IDE_Init()
{
IDE ide;
ASSERT(sizeof(ATAIdentifyDevice) == 512);
ide.base = IDE_PRIMARY_BASE;
ide.devctl = IDE_PRIMARY_DEVCTL;
if (!IDE_HasController(&ide)) {
kprintf("IDE: No controller detected\n");
return;
}
IDE_Reset(&ide);
IDE_Identify(&ide, 0);
}
bool
IDE_HasController(IDE *ide)
{
outb(ide->base + IDE_LBALOW, 0x41);
outb(ide->base + IDE_LBAMID, 0x4D);
if (inb(ide->base + IDE_LBALOW) != 0x41)
return false;
if (inb(ide->base + IDE_LBAMID) != 0x4D)
return false;
return true;
}
void
IDE_Reset(IDE *ide)
{
uint8_t status;
outb(ide->devctl, IDE_CONTROL_SRST);
outb(ide->devctl, 0);
inb(ide->devctl);
inb(ide->devctl);
inb(ide->devctl);
inb(ide->devctl);
// XXX: Timeout
while (1) {
status = inb(ide->devctl);
if ((status & (IDE_STATUS_RDY | IDE_STATUS_BSY)) == IDE_STATUS_RDY)
break;
}
}
void
IDE_Identify(IDE *ide, int drive)
{
uint8_t driveCode;
uint8_t status;
ATAIdentifyDevice ident;
ASSERT(drive == 0 || drive == 1);
if (drive == 0)
driveCode = IDE_DRIVE_MASTER;
else
driveCode = IDE_DRIVE_SLAVE;
outb(ide->base + IDE_DRIVE, driveCode);
outb(ide->base + IDE_SECTORCOUNT, 0x00);
outb(ide->base + IDE_LBALOW, 0x00);
outb(ide->base + IDE_LBAMID, 0x00);
outb(ide->base + IDE_LBAHIGH, 0x00);
outb(ide->base + IDE_COMMAND, IDE_CMD_IDENTIFY);
status = inb(ide->base + IDE_STATUS);
if (status == 0) {
kprintf("IDE: No drive %d\n", drive);
return;
}
kprintf("IDE: Waiting for ready! %08x\n", status);
// XXX: Need timeout
while (1) {
if ((status & IDE_STATUS_BSY) == 0)
break;
status = inb(ide->base + IDE_STATUS);
}
if ((status & IDE_STATUS_ERR) != 0) {
kprintf("IDE: Error trying to identify drive %d\n", drive);
return;
}
kprintf("IDE: Ready!\n");
insw(ide->base, (void *)&ident, 256);
kprintf("IDE: Ready!\n");
Debug_PrintHex((const char *)&ident, 512, 0, 512);
}