AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
dma.c
Go to the documentation of this file.
1
14
15#include <core/system.h>
16#include <core/string.h>
17#include <cpu/io.h>
18#include <mm/mm.h>
19#include <sys/sched.h>
20#include <aquila/errno.h>
21
22#include <ata.h>
23
24/* the bus master's registers, from its base */
25#define BM_CMD 0
26#define BM_STATUS 2
27#define BM_PRDT 4
28
29#define BM_CMD_START 0x01
30#define BM_CMD_READ 0x08 /* from the drive to memory */
31
32#define BM_ST_ACTIVE 0x01
33#define BM_ST_ERROR 0x02
34#define BM_ST_IRQ 0x04
35
36#define DMA_BUF_SIZE (64 * 1024)
37#define DMA_MAX_SECTORS (DMA_BUF_SIZE / 512)
38
40struct prd {
42 uint16_t size; /* 0 is 64 KiB */
44} __packed;
45
46#define PRD_EOT 0x8000
47
48/* each channel's descriptor and buffer, in the kernel image, so that their
49 * physical address is LMA() */
50static struct prd prdt[2] __aligned(16);
52
54static int channel_index(struct ata_drive *drive)
55{
56 return drive->id / 2;
57}
58
61static void dma_complete(struct ata_channel *ch, uint8_t bm_status)
62{
63 ch->status = io_in8(&ch->base, ATA_REG_STATUS);
64 ch->bm_status = bm_status;
66 ch->done = 1;
67}
68
76void dma_irq(struct ata_channel *ch)
77{
78 uint8_t bm_status = ch->bm.addr ? io_in8(&ch->bm, BM_STATUS) : 0;
79
80 /* not from a DMA transfer: reading the status acknowledges it */
81 if (!(bm_status & BM_ST_IRQ)) {
83 return;
84 }
85
86 dma_complete(ch, bm_status);
88}
89
93static int dma_transfer(struct ata_drive *drive, uint64_t lba, size_t count, int write)
94{
95 struct ata_channel *ch = drive->channel;
96 int c = channel_index(drive);
97
98 prdt[c].addr = (uint32_t) (uintptr_t) LMA(&dma_buf[c][0]);
99 prdt[c].size = (count * 512) & 0xFFFF;
100 prdt[c].flags = PRD_EOT;
101
102 /* stop the bus master, set the direction and the descriptor table,
103 * and clear its interrupt and error bits */
104 io_out8(&ch->bm, BM_CMD, write ? 0 : BM_CMD_READ);
105 io_out32(&ch->bm, BM_PRDT, (uint32_t) (uintptr_t) LMA(&prdt[c]));
107
108 ata_setup(drive, lba, count);
109 ch->done = 0;
110
111 if (drive->mode == ATA_MODE_LBA48)
113 else
115
116 io_out8(&ch->bm, BM_CMD, (write ? 0 : BM_CMD_READ) | BM_CMD_START);
117
118 /* a process sleeps until the interrupt; before there are processes
119 * (mounting the root, loading init at boot), the status is polled */
120 while (!ch->done) {
121 if (sched_running && curthread) {
123 } else {
125
126 if (bm_status & BM_ST_IRQ)
128 }
129 }
130
131 io_out8(&ch->bm, BM_CMD, 0);
132
133 if ((ch->bm_status & BM_ST_ERROR) || (ch->status & (ATA_STATUS_ERR | ATA_STATUS_DF))) {
134 printk("ata%d: DMA %s error, status 0x%x, bus master 0x%x\n", drive->id,
135 write ? "write" : "read", ch->status, ch->bm_status);
136 return -EIO;
137 }
138
139 return 0;
140}
141
144static ssize_t dma_read(struct ata_drive *drive, uint64_t lba, size_t count, void *buf)
145{
146 char *cbuf = buf;
147
148 while (count) {
149 size_t n = MIN(count, DMA_MAX_SECTORS);
150 int err;
151
152 if ((err = dma_transfer(drive, lba, n, 0)))
153 return err;
154
155 memcpy(cbuf, dma_buf[channel_index(drive)], n * 512);
156
157 lba += n;
158 count -= n;
159 cbuf += n * 512;
160 }
161
162 return 0;
163}
164
167static ssize_t dma_write(struct ata_drive *drive, uint64_t lba, size_t count, void *buf)
168{
169 char *cbuf = buf;
170
171 while (count) {
172 size_t n = MIN(count, DMA_MAX_SECTORS);
173 int err;
174
175 memcpy(dma_buf[channel_index(drive)], cbuf, n * 512);
176
177 if ((err = dma_transfer(drive, lba, n, 1)))
178 return err;
179
180 lba += n;
181 count -= n;
182 cbuf += n * 512;
183 }
184
185 return 0;
186}
187
195int dma_init(struct ata_drive *drive)
196{
197 if (!drive->channel->bm.addr || !(drive->capabilities & ATA_CAP_DMA))
198 return -ENODEV;
199
200 drive->read = dma_read;
201 drive->write = dma_write;
202 return 0;
203}
static void io_out32(struct ioaddr *io, uintptr_t off, uint32_t val)
Definition io.h:54
static uint8_t io_in8(struct ioaddr *io, uintptr_t off)
Reads an 8-, 16- or 32-bit register.
Definition io.h:28
static void io_out8(struct ioaddr *io, uintptr_t off, uint8_t val)
Writes an 8-, 16- or 32-bit register.
Definition io.h:44
#define LMA(obj)
Definition mm.h:37
void ata_setup(struct ata_drive *drive, uint64_t lba, size_t count)
Writes the registers of a command on count sectors from lba: the drive, the address and the count.
Definition ata.c:155
void dma_irq(struct ata_channel *channel)
Handles a channel's interrupt.
Definition dma.c:76
#define ATA_CAP_DMA
Definition ata.h:95
#define ATA_CMD_WRITE_DMA_EXT
Definition ata.h:52
#define ATA_REG_STATUS
Definition ata.h:34
#define ATA_CMD_WRITE_DMA
Definition ata.h:51
#define ATA_CMD_READ_DMA_EXT
Definition ata.h:50
#define ATA_MODE_LBA48
Definition ata.h:101
int dma_init(struct ata_drive *drive)
Sets a drive up for DMA, if both the drive and its channel's controller can do it.
Definition dma.c:195
#define ATA_CMD_READ_DMA
Definition ata.h:49
#define ATA_REG_CMD
Definition ata.h:33
#define ATA_STATUS_DF
Definition ata.h:64
#define ATA_STATUS_ERR
Definition ata.h:69
static int channel_index(struct ata_drive *drive)
Returns which channel a drive is on: 0 (primary) or 1 (secondary).
Definition dma.c:54
static int dma_transfer(struct ata_drive *drive, uint64_t lba, size_t count, int write)
Transfers up to DMA_MAX_SECTORS sectors between the drive and the channel's buffer,...
Definition dma.c:93
#define BM_STATUS
Definition dma.c:26
#define BM_ST_ERROR
Definition dma.c:33
#define PRD_EOT
Definition dma.c:46
static ssize_t dma_read(struct ata_drive *drive, uint64_t lba, size_t count, void *buf)
Reads count sectors from lba on, through the channel's buffer.
Definition dma.c:144
static char dma_buf[2][DMA_BUF_SIZE]
Definition dma.c:51
#define DMA_MAX_SECTORS
Definition dma.c:37
#define BM_CMD_READ
Definition dma.c:30
#define BM_CMD
Definition dma.c:25
#define DMA_BUF_SIZE
Definition dma.c:36
static struct prd prdt[2]
Definition dma.c:50
static ssize_t dma_write(struct ata_drive *drive, uint64_t lba, size_t count, void *buf)
Writes count sectors from lba on, through the channel's buffer.
Definition dma.c:167
#define BM_CMD_START
Definition dma.c:29
#define BM_ST_IRQ
Definition dma.c:34
static void dma_complete(struct ata_channel *ch, uint8_t bm_status)
Ends a transfer: keeps what the controller and the drive say about it, which also acknowledges the in...
Definition dma.c:61
#define BM_PRDT
Definition dma.c:27
#define __packed
Definition system.h:30
#define MIN(a, b)
Definition system.h:11
#define __aligned(n)
Definition system.h:31
void * memcpy(void *dst, const void *src, size_t n)
Copies n bytes; dst and src must not overlap.
Definition libc.c:11
int printk(const char *fmt,...)
Writes a kernel message, to the message buffer and the consoles.
Definition printk.c:249
int sched_running
Definition sched.c:367
#define curthread
Definition sched.h:12
__SIZE_TYPE__ uintptr_t
Definition stddef.h:12
unsigned int uint32_t
Definition stddef.h:22
unsigned char uint8_t
Definition stddef.h:20
unsigned long long int uint64_t
Definition stddef.h:23
unsigned short int uint16_t
Definition stddef.h:21
An IDE channel, with the master and slave drives on it.
Definition ata.h:107
struct ioaddr base
the command block's registers, and the bus master's for DMA (whose address is 0 if the controller has...
Definition ata.h:110
struct ioaddr bm
Definition ata.h:111
volatile int done
Definition ata.h:121
struct waitq irq_wait
the DMA transfer waiting for the interrupt, and what it found
Definition ata.h:120
uint8_t status
Definition ata.h:122
uint8_t bm_status
Definition ata.h:122
A drive on a channel.
Definition ata.h:126
uint8_t id
Definition ata.h:131
struct ioaddr base
Definition ata.h:127
ssize_t(*) read(struct ata_drive *drive, uint64_t lba, size_t count, void *buf)
Definition ata.h:147
struct ata_channel * channel
Definition ata.h:129
uint16_t capabilities
Definition ata.h:141
ssize_t(*) write(struct ata_drive *drive, uint64_t lba, size_t count, void *buf)
Definition ata.h:148
uint8_t mode
Definition ata.h:132
uintptr_t addr
Definition io.h:97
A physical region descriptor: one piece of memory to transfer.
Definition dma.c:40
uint16_t size
Definition dma.c:42
uint32_t addr
Definition dma.c:41
uint16_t flags
Definition dma.c:43
long int ssize_t
Definition types.h:12
void waitq_wakeup_nopoll(struct waitq *waitq)
Wakes up every thread sleeping on a wait queue, but not the threads polling it.
Definition waitq.c:196
void waitq_sleep_unint(struct waitq *waitq)
Puts the current thread to sleep on a wait queue until it is woken up, whatever signals come meanwhil...
Definition waitq.c:67