david/ipxe
david
/
ipxe
Archived
1
0
Fork 0

[virtio] Split virtio-net.c into several files.

Signed-off-by: Laurent Vivier <Laurent.Vivier@bull.net>
This commit is contained in:
Laurent Vivier 2008-11-19 17:28:29 +01:00 committed by Michael Brown
parent 14a739ba6a
commit b48f37e69a
5 changed files with 252 additions and 207 deletions

View File

@ -0,0 +1,64 @@
/* virtio-pci.c - pci interface for virtio interface
*
* (c) Copyright 2008 Bull S.A.S.
*
* Author: Laurent Vivier <Laurent.Vivier@bull.net>
*
* some parts from Linux Virtio PCI driver
*
* Copyright IBM Corp. 2007
* Authors: Anthony Liguori <aliguori@us.ibm.com>
*
*/
#include "etherboot.h"
#include "gpxe/io.h"
#include "gpxe/virtio-ring.h"
#include "gpxe/virtio-pci.h"
int vp_find_vq(unsigned int ioaddr, int queue_index,
struct vring_virtqueue *vq)
{
struct vring * vr = &vq->vring;
u16 num;
/* select the queue */
outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_SEL);
/* check if the queue is available */
num = inw(ioaddr + VIRTIO_PCI_QUEUE_NUM);
if (!num) {
printf("ERROR: queue size is 0\n");
return -1;
}
if (num > MAX_QUEUE_NUM) {
printf("ERROR: queue size %d > %d\n", num, MAX_QUEUE_NUM);
return -1;
}
/* check if the queue is already active */
if (inl(ioaddr + VIRTIO_PCI_QUEUE_PFN)) {
printf("ERROR: queue already active\n");
return -1;
}
vq->queue_index = queue_index;
/* initialize the queue */
vring_init(vr, num, (unsigned char*)&vq->queue);
/* activate the queue
*
* NOTE: vr->desc is initialized by vring_init()
*/
outl((unsigned long)virt_to_phys(vr->desc) >> PAGE_SHIFT,
ioaddr + VIRTIO_PCI_QUEUE_PFN);
return num;
}

View File

@ -0,0 +1,134 @@
/* virtio-pci.c - virtio ring management
*
* (c) Copyright 2008 Bull S.A.S.
*
* Author: Laurent Vivier <Laurent.Vivier@bull.net>
*
* some parts from Linux Virtio Ring
*
* Copyright Rusty Russell IBM Corporation 2007
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*
*
*/
#include "etherboot.h"
#include "gpxe/io.h"
#include "gpxe/virtio-ring.h"
#include "gpxe/virtio-pci.h"
#define BUG() do { \
printf("BUG: failure at %s:%d/%s()!\n", \
__FILE__, __LINE__, __FUNCTION__); \
while(1); \
} while (0)
#define BUG_ON(condition) do { if (condition) BUG(); } while (0)
/*
* vring_free
*
* put at the begin of the free list the current desc[head]
*/
void vring_detach(struct vring_virtqueue *vq, unsigned int head)
{
struct vring *vr = &vq->vring;
unsigned int i;
/* find end of given descriptor */
i = head;
while (vr->desc[i].flags & VRING_DESC_F_NEXT)
i = vr->desc[i].next;
/* link it with free list and point to it */
vr->desc[i].next = vq->free_head;
wmb();
vq->free_head = head;
}
/*
* vring_get_buf
*
* get a buffer from the used list
*
*/
int vring_get_buf(struct vring_virtqueue *vq, unsigned int *len)
{
struct vring *vr = &vq->vring;
struct vring_used_elem *elem;
u32 id;
int ret;
BUG_ON(!vring_more_used(vq));
elem = &vr->used->ring[vq->last_used_idx % vr->num];
wmb();
id = elem->id;
if (len != NULL)
*len = elem->len;
ret = vq->vdata[id];
vring_detach(vq, id);
vq->last_used_idx++;
return ret;
}
void vring_add_buf(struct vring_virtqueue *vq,
struct vring_list list[],
unsigned int out, unsigned int in,
int index, int num_added)
{
struct vring *vr = &vq->vring;
int i, avail, head, prev;
BUG_ON(out + in == 0);
prev = 0;
head = vq->free_head;
for (i = head; out; i = vr->desc[i].next, out--) {
vr->desc[i].flags = VRING_DESC_F_NEXT;
vr->desc[i].addr = (u64)virt_to_phys(list->addr);
vr->desc[i].len = list->length;
prev = i;
list++;
}
for ( ; in; i = vr->desc[i].next, in--) {
vr->desc[i].flags = VRING_DESC_F_NEXT|VRING_DESC_F_WRITE;
vr->desc[i].addr = (u64)virt_to_phys(list->addr);
vr->desc[i].len = list->length;
prev = i;
list++;
}
vr->desc[prev].flags &= ~VRING_DESC_F_NEXT;
vq->free_head = i;
vq->vdata[head] = index;
avail = (vr->avail->idx + num_added) % vr->num;
vr->avail->ring[avail] = head;
wmb();
}
void vring_kick(unsigned int ioaddr, struct vring_virtqueue *vq, int num_added)
{
struct vring *vr = &vq->vring;
wmb();
vr->avail->idx += num_added;
mb();
if (!(vr->used->flags & VRING_USED_F_NO_NOTIFY))
vp_notify(ioaddr, vq->queue_index);
}

View File

@ -45,8 +45,6 @@ struct eth_frame {
unsigned char data[ETH_FRAME_LEN];
};
typedef unsigned char virtio_queue_t[PAGE_MASK + vring_size(MAX_QUEUE_NUM)];
/* TX: virtio header and eth buffer */
static struct virtio_net_hdr tx_virtio_hdr;
@ -66,205 +64,8 @@ enum {
QUEUE_NB
};
struct vring_virtqueue {
virtio_queue_t queue;
struct vring vring;
u16 free_head;
u16 last_used_idx;
u16 vdata[MAX_QUEUE_NUM];
/* PCI */
int queue_index;
};
static struct vring_virtqueue virtqueue[QUEUE_NB];
/*
* Virtio PCI interface
*
*/
static int vp_find_vq(unsigned int ioaddr, int queue_index,
struct vring_virtqueue *vq)
{
struct vring * vr = &vq->vring;
u16 num;
/* select the queue */
outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_SEL);
/* check if the queue is available */
num = inw(ioaddr + VIRTIO_PCI_QUEUE_NUM);
if (!num) {
printf("ERROR: queue size is 0\n");
return -1;
}
if (num > MAX_QUEUE_NUM) {
printf("ERROR: queue size %d > %d\n", num, MAX_QUEUE_NUM);
return -1;
}
/* check if the queue is already active */
if (inl(ioaddr + VIRTIO_PCI_QUEUE_PFN)) {
printf("ERROR: queue already active\n");
return -1;
}
vq->queue_index = queue_index;
/* initialize the queue */
vring_init(vr, num, (unsigned char*)&vq->queue);
/* activate the queue
*
* NOTE: vr->desc is initialized by vring_init()
*/
outl((unsigned long)virt_to_phys(vr->desc) >> PAGE_SHIFT,
ioaddr + VIRTIO_PCI_QUEUE_PFN);
return num;
}
/*
* Virtual ring management
*
*/
static void vring_enable_cb(struct vring_virtqueue *vq)
{
vq->vring.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT;
}
static void vring_disable_cb(struct vring_virtqueue *vq)
{
vq->vring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
}
/*
* vring_free
*
* put at the begin of the free list the current desc[head]
*/
static void vring_detach(struct vring_virtqueue *vq, unsigned int head)
{
struct vring *vr = &vq->vring;
unsigned int i;
/* find end of given descriptor */
i = head;
while (vr->desc[i].flags & VRING_DESC_F_NEXT)
i = vr->desc[i].next;
/* link it with free list and point to it */
vr->desc[i].next = vq->free_head;
wmb();
vq->free_head = head;
}
/*
* vring_more_used
*
* is there some used buffers ?
*
*/
static inline int vring_more_used(struct vring_virtqueue *vq)
{
wmb();
return vq->last_used_idx != vq->vring.used->idx;
}
/*
* vring_get_buf
*
* get a buffer from the used list
*
*/
static int vring_get_buf(struct vring_virtqueue *vq, unsigned int *len)
{
struct vring *vr = &vq->vring;
struct vring_used_elem *elem;
u32 id;
int ret;
BUG_ON(!vring_more_used(vq));
elem = &vr->used->ring[vq->last_used_idx % vr->num];
wmb();
id = elem->id;
if (len != NULL)
*len = elem->len;
ret = vq->vdata[id];
vring_detach(vq, id);
vq->last_used_idx++;
return ret;
}
static void vring_add_buf(struct vring_virtqueue *vq,
struct vring_list list[],
unsigned int out, unsigned int in,
int index, int num_added)
{
struct vring *vr = &vq->vring;
int i, avail, head, prev;
BUG_ON(out + in == 0);
prev = 0;
head = vq->free_head;
for (i = head; out; i = vr->desc[i].next, out--) {
vr->desc[i].flags = VRING_DESC_F_NEXT;
vr->desc[i].addr = (u64)virt_to_phys(list->addr);
vr->desc[i].len = list->length;
prev = i;
list++;
}
for ( ; in; i = vr->desc[i].next, in--) {
vr->desc[i].flags = VRING_DESC_F_NEXT|VRING_DESC_F_WRITE;
vr->desc[i].addr = (u64)virt_to_phys(list->addr);
vr->desc[i].len = list->length;
prev = i;
list++;
}
vr->desc[prev].flags &= ~VRING_DESC_F_NEXT;
vq->free_head = i;
vq->vdata[head] = index;
avail = (vr->avail->idx + num_added) % vr->num;
vr->avail->ring[avail] = head;
wmb();
}
static void vring_kick(struct nic *nic, struct vring_virtqueue *vq,
int num_added)
{
struct vring *vr = &vq->vring;
wmb();
vr->avail->idx += num_added;
mb();
if (!(vr->used->flags & VRING_USED_F_NO_NOTIFY))
vp_notify(nic->ioaddr, vq->queue_index);
}
/*
* virtnet_disable
*
@ -325,7 +126,7 @@ static int virtnet_poll(struct nic *nic, int retrieve)
list[1].length = ETH_FRAME_LEN;
vring_add_buf(&virtqueue[RX_INDEX], list, 0, 2, token, 0);
vring_kick(nic, &virtqueue[RX_INDEX], 1);
vring_kick(nic->ioaddr, &virtqueue[RX_INDEX], 1);
return 1;
}
@ -373,7 +174,7 @@ static void virtnet_transmit(struct nic *nic, const char *destaddr,
vring_add_buf(&virtqueue[TX_INDEX], list, 2, 0, 0, 0);
vring_kick(nic, &virtqueue[TX_INDEX], 1);
vring_kick(nic->ioaddr, &virtqueue[TX_INDEX], 1);
/*
* http://www.etherboot.org/wiki/dev/devmanual
@ -423,7 +224,7 @@ static void provide_buffers(struct nic *nic)
/* nofify */
vring_kick(nic, &virtqueue[RX_INDEX], i);
vring_kick(nic->ioaddr, &virtqueue[RX_INDEX], i);
}
static struct nic_operations virtnet_operations = {

View File

@ -91,4 +91,7 @@ static inline void vp_del_vq(unsigned int ioaddr, int queue_index)
outl(0, ioaddr + VIRTIO_PCI_QUEUE_PFN);
}
int vp_find_vq(unsigned int ioaddr, int queue_index,
struct vring_virtqueue *vq);
#endif /* _VIRTIO_PCI_H_ */

View File

@ -58,6 +58,24 @@ struct vring {
struct vring_used *used;
};
#define vring_size(num) \
(((((sizeof(struct vring_desc) * num) + \
(sizeof(struct vring_avail) + sizeof(u16) * num)) \
+ PAGE_MASK) & ~PAGE_MASK) + \
(sizeof(struct vring_used) + sizeof(struct vring_used_elem) * num))
typedef unsigned char virtio_queue_t[PAGE_MASK + vring_size(MAX_QUEUE_NUM)];
struct vring_virtqueue {
virtio_queue_t queue;
struct vring vring;
u16 free_head;
u16 last_used_idx;
u16 vdata[MAX_QUEUE_NUM];
/* PCI */
int queue_index;
};
struct vring_list {
char *addr;
unsigned int length;
@ -90,10 +108,35 @@ static inline void vring_init(struct vring *vr,
vr->desc[i].next = 0;
}
#define vring_size(num) \
(((((sizeof(struct vring_desc) * num) + \
(sizeof(struct vring_avail) + sizeof(u16) * num)) \
+ PAGE_MASK) & ~PAGE_MASK) + \
(sizeof(struct vring_used) + sizeof(struct vring_used_elem) * num))
static inline void vring_enable_cb(struct vring_virtqueue *vq)
{
vq->vring.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT;
}
static inline void vring_disable_cb(struct vring_virtqueue *vq)
{
vq->vring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
}
/*
* vring_more_used
*
* is there some used buffers ?
*
*/
static inline int vring_more_used(struct vring_virtqueue *vq)
{
wmb();
return vq->last_used_idx != vq->vring.used->idx;
}
void vring_detach(struct vring_virtqueue *vq, unsigned int head);
int vring_get_buf(struct vring_virtqueue *vq, unsigned int *len);
void vring_add_buf(struct vring_virtqueue *vq, struct vring_list list[],
unsigned int out, unsigned int in,
int index, int num_added);
void vring_kick(unsigned int ioaddr, struct vring_virtqueue *vq, int num_added);
#endif /* _VIRTIO_RING_H_ */