diff options
| author | Frans Kaashoek <kaashoek@mit.edu> | 2019-08-12 07:20:32 -0400 | 
|---|---|---|
| committer | Frans Kaashoek <kaashoek@mit.edu> | 2019-08-12 07:20:32 -0400 | 
| commit | e398a9815c8dc65d556333f9bb65c61ca5be2954 (patch) | |
| tree | 97328ea95fd1c41b5c399c570b3fb3ede815a369 | |
| parent | d96a8c5661ac27c82e577edc6714832b970586dc (diff) | |
| download | xv6-labs-e398a9815c8dc65d556333f9bb65c61ca5be2954.tar.gz xv6-labs-e398a9815c8dc65d556333f9bb65c61ca5be2954.tar.bz2 xv6-labs-e398a9815c8dc65d556333f9bb65c61ca5be2954.zip | |
Wrap state of disk driver in a struct so that it is easier to support
several disks (e.g., in a mount lab).
| -rw-r--r-- | kernel/virtio_disk.c | 140 | 
1 files changed, 71 insertions, 69 deletions
| diff --git a/kernel/virtio_disk.c b/kernel/virtio_disk.c index 14c718d..3cff024 100644 --- a/kernel/virtio_disk.c +++ b/kernel/virtio_disk.c @@ -20,36 +20,38 @@  // the address of virtio mmio register r.  #define R(r) ((volatile uint32 *)(VIRTIO0 + (r))) -struct spinlock vdisk_lock; - -// memory for virtio descriptors &c for queue 0. -// this is a global instead of allocated because it has -// to be multiple contiguous pages, which kalloc() -// doesn't support. -__attribute__ ((aligned (PGSIZE))) -static char pages[2*PGSIZE]; -static struct VRingDesc *desc; -static uint16 *avail; -static struct UsedArea *used; - -// our own book-keeping. -static char free[NUM];  // is a descriptor free? -static uint16 used_idx; // we've looked this far in used[2..NUM]. - -// track info about in-flight operations, -// for use when completion interrupt arrives. -// indexed by first descriptor index of chain. -static struct { -  struct buf *b; -  char status; -} info[NUM]; +static struct disk { + // memory for virtio descriptors &c for queue 0. + // this is a global instead of allocated because it must + // be multiple contiguous pages, which kalloc() + // doesn't support, and page aligned. +  char pages[2*PGSIZE]; +  struct VRingDesc *desc; +  uint16 *avail; +  struct UsedArea *used; + +  // our own book-keeping. +  char free[NUM];  // is a descriptor free? +  uint16 used_idx; // we've looked this far in used[2..NUM]. + +  // track info about in-flight operations, +  // for use when completion interrupt arrives. +  // indexed by first descriptor index of chain. +  struct { +    struct buf *b; +    char status; +  } info[NUM]; +   +  struct spinlock vdisk_lock; +   +} __attribute__ ((aligned (PGSIZE))) disk;  void  virtio_disk_init(void)  {    uint32 status = 0; -  initlock(&vdisk_lock, "virtio_disk"); +  initlock(&disk.vdisk_lock, "virtio_disk");    if(*R(VIRTIO_MMIO_MAGIC_VALUE) != 0x74726976 ||       *R(VIRTIO_MMIO_VERSION) != 1 || @@ -93,19 +95,19 @@ virtio_disk_init(void)    if(max < NUM)      panic("virtio disk max queue too short");    *R(VIRTIO_MMIO_QUEUE_NUM) = NUM; -  memset(pages, 0, sizeof(pages)); -  *R(VIRTIO_MMIO_QUEUE_PFN) = ((uint64)pages) >> PGSHIFT; +  memset(disk.pages, 0, sizeof(disk.pages)); +  *R(VIRTIO_MMIO_QUEUE_PFN) = ((uint64)disk.pages) >> PGSHIFT;    // desc = pages -- num * VRingDesc    // avail = pages + 0x40 -- 2 * uint16, then num * uint16    // used = pages + 4096 -- 2 * uint16, then num * vRingUsedElem -  desc = (struct VRingDesc *) pages; -  avail = (uint16*)(((char*)desc) + NUM*sizeof(struct VRingDesc)); -  used = (struct UsedArea *) (pages + PGSIZE); +  disk.desc = (struct VRingDesc *) disk.pages; +  disk.avail = (uint16*)(((char*)disk.desc) + NUM*sizeof(struct VRingDesc)); +  disk.used = (struct UsedArea *) (disk.pages + PGSIZE);    for(int i = 0; i < NUM; i++) -    free[i] = 1; +    disk.free[i] = 1;    // plic.c and trap.c arrange for interrupts from VIRTIO0_IRQ.  } @@ -115,8 +117,8 @@ static int  alloc_desc()  {    for(int i = 0; i < NUM; i++){ -    if(free[i]){ -      free[i] = 0; +    if(disk.free[i]){ +      disk.free[i] = 0;        return i;      }    } @@ -129,11 +131,11 @@ free_desc(int i)  {    if(i >= NUM)      panic("virtio_disk_intr 1"); -  if(free[i]) +  if(disk.free[i])      panic("virtio_disk_intr 2"); -  desc[i].addr = 0; -  free[i] = 1; -  wakeup(&free[0]); +  disk.desc[i].addr = 0; +  disk.free[i] = 1; +  wakeup(&disk.free[0]);  }  // free a chain of descriptors. @@ -142,8 +144,8 @@ free_chain(int i)  {    while(1){      free_desc(i); -    if(desc[i].flags & VRING_DESC_F_NEXT) -      i = desc[i].next; +    if(disk.desc[i].flags & VRING_DESC_F_NEXT) +      i = disk.desc[i].next;      else        break;    } @@ -168,7 +170,7 @@ virtio_disk_rw(struct buf *b, int write)  {    uint64 sector = b->blockno * (BSIZE / 512); -  acquire(&vdisk_lock); +  acquire(&disk.vdisk_lock);    // the spec says that legacy block operations use three    // descriptors: one for type/reserved/sector, one for @@ -180,7 +182,7 @@ virtio_disk_rw(struct buf *b, int write)      if(alloc3_desc(idx) == 0) {        break;      } -    sleep(&free[0], &vdisk_lock); +    sleep(&disk.free[0], &disk.vdisk_lock);    }    // format the three descriptors. @@ -201,67 +203,67 @@ virtio_disk_rw(struct buf *b, int write)    // buf0 is on a kernel stack, which is not direct mapped,    // thus the call to kvmpa(). -  desc[idx[0]].addr = (uint64) kvmpa((uint64) &buf0); -  desc[idx[0]].len = sizeof(buf0); -  desc[idx[0]].flags = VRING_DESC_F_NEXT; -  desc[idx[0]].next = idx[1]; +  disk.desc[idx[0]].addr = (uint64) kvmpa((uint64) &buf0); +  disk.desc[idx[0]].len = sizeof(buf0); +  disk.desc[idx[0]].flags = VRING_DESC_F_NEXT; +  disk.desc[idx[0]].next = idx[1]; -  desc[idx[1]].addr = (uint64) b->data; -  desc[idx[1]].len = BSIZE; +  disk.desc[idx[1]].addr = (uint64) b->data; +  disk.desc[idx[1]].len = BSIZE;    if(write) -    desc[idx[1]].flags = 0; // device reads b->data +    disk.desc[idx[1]].flags = 0; // device reads b->data    else -    desc[idx[1]].flags = VRING_DESC_F_WRITE; // device writes b->data -  desc[idx[1]].flags |= VRING_DESC_F_NEXT; -  desc[idx[1]].next = idx[2]; +    disk.desc[idx[1]].flags = VRING_DESC_F_WRITE; // device writes b->data +  disk.desc[idx[1]].flags |= VRING_DESC_F_NEXT; +  disk.desc[idx[1]].next = idx[2]; -  info[idx[0]].status = 0; -  desc[idx[2]].addr = (uint64) &info[idx[0]].status; -  desc[idx[2]].len = 1; -  desc[idx[2]].flags = VRING_DESC_F_WRITE; // device writes the status -  desc[idx[2]].next = 0; +  disk.info[idx[0]].status = 0; +  disk.desc[idx[2]].addr = (uint64) &disk.info[idx[0]].status; +  disk.desc[idx[2]].len = 1; +  disk.desc[idx[2]].flags = VRING_DESC_F_WRITE; // device writes the status +  disk.desc[idx[2]].next = 0;    // record struct buf for virtio_disk_intr().    b->disk = 1; -  info[idx[0]].b = b; +  disk.info[idx[0]].b = b;    // avail[0] is flags    // avail[1] tells the device how far to look in avail[2...].    // avail[2...] are desc[] indices the device should process.    // we only tell device the first index in our chain of descriptors. -  avail[2 + (avail[1] % NUM)] = idx[0]; +  disk.avail[2 + (disk.avail[1] % NUM)] = idx[0];    __sync_synchronize(); -  avail[1] = avail[1] + 1; +  disk.avail[1] = disk.avail[1] + 1;    *R(VIRTIO_MMIO_QUEUE_NOTIFY) = 0; // value is queue number    // Wait for virtio_disk_intr() to say request has finished.    while(b->disk == 1) { -    sleep(b, &vdisk_lock); +    sleep(b, &disk.vdisk_lock);    } -  info[idx[0]].b = 0; +  disk.info[idx[0]].b = 0;    free_chain(idx[0]); -  release(&vdisk_lock); +  release(&disk.vdisk_lock);  }  void  virtio_disk_intr()  { -  acquire(&vdisk_lock); +  acquire(&disk.vdisk_lock); -  while((used_idx % NUM) != (used->id % NUM)){ -    int id = used->elems[used_idx].id; +  while((disk.used_idx % NUM) != (disk.used->id % NUM)){ +    int id = disk.used->elems[disk.used_idx].id; -    if(info[id].status != 0) +    if(disk.info[id].status != 0)        panic("virtio_disk_intr status"); -    info[id].b->disk = 0;   // disk is done with buf -    wakeup(info[id].b); +    disk.info[id].b->disk = 0;   // disk is done with buf +    wakeup(disk.info[id].b); -    used_idx = (used_idx + 1) % NUM; +    disk.used_idx = (disk.used_idx + 1) % NUM;    } -  release(&vdisk_lock); +  release(&disk.vdisk_lock);  } | 
