kern

changeset 86:379332fc1667

implementing ata read/write
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 07 Dec 2011 14:03:11 +0200
parents 5fb7ad5967a8
children 178d5a95e6de
files src/ata.c src/ata.h src/mutex.c src/mutex.h src/rbtree.h
diffstat 5 files changed, 157 insertions(+), 5 deletions(-) [+]
line diff
     1.1 --- a/src/ata.c	Wed Dec 07 06:58:05 2011 +0000
     1.2 +++ b/src/ata.c	Wed Dec 07 14:03:11 2011 +0200
     1.3 @@ -7,6 +7,7 @@
     1.4  #include "ata.h"
     1.5  #include "intr.h"
     1.6  #include "asmops.h"
     1.7 +#include "mutex.h"
     1.8  
     1.9  /* registers */
    1.10  #define REG_DATA		0	/* R/W */
    1.11 @@ -31,9 +32,14 @@
    1.12  
    1.13  /* device select bit in control register */
    1.14  #define DEV_SEL(x)		(((x) & 1) << 4)
    1.15 +#define DEV_LBA			(1 << 6)
    1.16  
    1.17  /* ATA commands */
    1.18  #define CMD_IDENTIFY	0xec
    1.19 +#define CMD_READ		0x20
    1.20 +#define CMD_READ48		0x24
    1.21 +#define CMD_WRITE		0x30
    1.22 +#define CMD_WRITE48		0x34
    1.23  
    1.24  
    1.25  struct device {
    1.26 @@ -69,7 +75,14 @@
    1.27   */
    1.28  #define MAX_IFACES		2
    1.29  #define MAX_DEV			(MAX_IFACES * 2)
    1.30 -static struct device dev[MAX_DEV];
    1.31 +static struct device devices[MAX_DEV];
    1.32 +
    1.33 +static int use_irq;
    1.34 +
    1.35 +/* This serves as a sync point for I/O. While the mutex is held,
    1.36 + * some process is doing I/O and all the others must wait.
    1.37 + */
    1.38 +static mutex_t pending;
    1.39  
    1.40  
    1.41  void init_ata(void)
    1.42 @@ -82,10 +95,87 @@
    1.43  		int iface = i / MAX_IFACES;
    1.44  		int id = i % MAX_IFACES;
    1.45  
    1.46 -		if(identify(dev + i, iface, id) == -1) {
    1.47 -			dev[i].id = -1;
    1.48 +		if(identify(devices + i, iface, id) == -1) {
    1.49 +			devices[i].id = -1;
    1.50  		}
    1.51  	}
    1.52 +
    1.53 +	/* init code done, from now on use the irq sleep/wakeup mechanism */
    1.54 +	use_irq = 1;
    1.55 +}
    1.56 +
    1.57 +int ata_read_pio(int devno, uint64_t sect, void *buf)
    1.58 +{
    1.59 +	int cmd, st, res = -1;
    1.60 +	uint32_t sect_low;
    1.61 +	struct device *dev = device + devno;
    1.62 +
    1.63 +	if(dev->id == -1) {
    1.64 +		return -1;
    1.65 +	}
    1.66 +
    1.67 +	if(use_irq) {
    1.68 +		/* wait for the interface to become available */
    1.69 +		mutex_lock(&pending);
    1.70 +	}
    1.71 +
    1.72 +	select_dev(dev);
    1.73 +
    1.74 +	/* LBA48 requires the high-order bits first */
    1.75 +	if(sect >= dev->nsect_lba) {
    1.76 +		uint32_t sect_high = (uint32_t)(sect >> 24);
    1.77 +		sect_low = (uint32_t)sect & 0xffffff;
    1.78 +
    1.79 +		if(sect >= dev->nsect_lba48) {
    1.80 +			goto end;
    1.81 +		}
    1.82 +		cmd = CMD_READ48;
    1.83 +
    1.84 +		write_reg8(dev, REG_COUNT, 0);
    1.85 +		write_reg8(dev, REG_LBA0, sect_high & 0xff);
    1.86 +		write_reg8(dev, REG_LBA1, (sect_high >> 8) & 0xff);
    1.87 +		write_reg8(dev, REG_LBA2, (sect_high >> 16) & 0xff);
    1.88 +	} else {
    1.89 +		cmd = CMD_READ;
    1.90 +		sect_low = (uint32_t)sect & 0xffffff;
    1.91 +	}
    1.92 +
    1.93 +	write_reg8(dev, REG_COUNT, 1);
    1.94 +	write_reg8(dev, REG_LBA0, sect_low & 0xff);
    1.95 +	write_reg8(dev, REG_LBA1, (sect_low >> 8) & 0xff);
    1.96 +	write_reg8(dev, REG_LBA2, (sect_low >> 16) & 0xff);
    1.97 +	write_reg8(dev, REG_DEVICE, ((sect_low >> 24) & 0xf) | DEV_LBA | DEV_SEL(dev->id))
    1.98 +	/* execute */
    1.99 +	write_reg8(dev, REG_CMD, cmd);
   1.100 +
   1.101 +	/* wait for the data to become available */
   1.102 +	do {
   1.103 +		if(use_irq) {
   1.104 +			/* also sleep on the mutex if we're called from userspace */
   1.105 +			wait(&pending);
   1.106 +		}
   1.107 +	} while((st = read_reg8(dev, REG_ALTSTAT)) & (ST_DRQ | ST_ERR) == 0);
   1.108 +
   1.109 +	if(st & ST_ERR) {
   1.110 +		print_error();
   1.111 +		goto end;
   1.112 +	}
   1.113 +
   1.114 +	/* read the data and we're done */
   1.115 +	read_data(dev, buf);
   1.116 +	res = 0;
   1.117 +end:
   1.118 +	if(use_irq) {
   1.119 +		mutex_unlock(&pending);
   1.120 +	}
   1.121 +	return res;
   1.122 +}
   1.123 +
   1.124 +int ata_write_pio(int devno, uint64_t sect, void *buf)
   1.125 +{
   1.126 +	if(dev[devno].id == -1) {
   1.127 +		return -1;
   1.128 +	}
   1.129  }
   1.130  
   1.131  static int identify(struct device *dev, int iface, int id)
   1.132 @@ -106,8 +196,6 @@
   1.133  	}
   1.134  
   1.135  	select_dev(dev);
   1.136 -	/* wait a bit to allow the device time to respond */
   1.137 -	iodelay(); iodelay(); iodelay(); iodelay();
   1.138  
   1.139  	write_reg8(dev, REG_CMD, CMD_IDENTIFY);
   1.140  
   1.141 @@ -161,6 +249,9 @@
   1.142  
   1.143  	/* set the correct device bit to the device register */
   1.144  	write_reg8(dev, REG_DEVICE, DEV_SEL(dev->id));
   1.145 +
   1.146 +	/* wait a bit to allow the device time to respond */
   1.147 +	iodelay(); iodelay(); iodelay(); iodelay();
   1.148  }
   1.149  
   1.150  static int wait_busy(struct device *dev)
     2.1 --- a/src/ata.h	Wed Dec 07 06:58:05 2011 +0000
     2.2 +++ b/src/ata.h	Wed Dec 07 14:03:11 2011 +0200
     2.3 @@ -3,4 +3,7 @@
     2.4  
     2.5  void init_ata(void);
     2.6  
     2.7 +int ata_read_pio(int devno, uint64_t sect, void *buf);
     2.8 +int ata_write_pio(int devno, uint64_t sect, void *buf);
     2.9 +
    2.10  #endif	/* ATA_H_ */
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/src/mutex.c	Wed Dec 07 14:03:11 2011 +0200
     3.3 @@ -0,0 +1,45 @@
     3.4 +#include <assert.h>
     3.5 +#include "mutex.h"
     3.6 +#include "sched.h"
     3.7 +#include "intr.h"
     3.8 +
     3.9 +void mutex_lock(mutex_t *m)
    3.10 +{
    3.11 +	int istate = get_intr_state();
    3.12 +	disable_intr();
    3.13 +
    3.14 +	/* sleep while the mutex is held */
    3.15 +	while(*m > 0) {
    3.16 +		wait(m);
    3.17 +	}
    3.18 +	/* then grab it... */
    3.19 +	(*m)++;
    3.20 +
    3.21 +	set_intr_state(istate);
    3.22 +}
    3.23 +
    3.24 +void mutex_unlock(mutex_t *m)
    3.25 +{
    3.26 +	int istate = get_intr_state();
    3.27 +	disable_intr();
    3.28 +
    3.29 +	assert(*m);
    3.30 +	/* release the mutex and wakeup everyone waiting on it */
    3.31 +	(*m)--;
    3.32 +	wakeup(m);
    3.33 +
    3.34 +	set_intr_state(istate);
    3.35 +}
    3.36 +
    3.37 +int mutex_trylock(mutex_t *m)
    3.38 +{
    3.39 +	int res = -1, istate = get_intr_state();
    3.40 +	disable_intr();
    3.41 +
    3.42 +	if(*m == 0) {
    3.43 +		(*m)++;
    3.44 +		res = 0;
    3.45 +	}
    3.46 +	set_intr_state(istate);
    3.47 +	return res;
    3.48 +}
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/src/mutex.h	Wed Dec 07 14:03:11 2011 +0200
     4.3 @@ -0,0 +1,11 @@
     4.4 +#ifndef MUTEX_H_
     4.5 +#define MUTEX_H_
     4.6 +
     4.7 +typedef unsigned int mutex_t;
     4.8 +
     4.9 +void mutex_lock(mutex_t *m);
    4.10 +void mutex_unlock(mutex_t *m);
    4.11 +
    4.12 +int mutex_trylock(mutex_t *m);
    4.13 +
    4.14 +#endif	/* MUTEX_H_ */
     5.1 --- a/src/rbtree.h	Wed Dec 07 06:58:05 2011 +0000
     5.2 +++ b/src/rbtree.h	Wed Dec 07 14:03:11 2011 +0200
     5.3 @@ -1,6 +1,8 @@
     5.4  #ifndef RBTREE_H_
     5.5  #define RBTREE_H_
     5.6  
     5.7 +#include <stdlib.h>	/* for size_t */
     5.8 +
     5.9  struct rbtree;
    5.10  struct rbnode;
    5.11