u64 _vp_read(struct vp_cap *cap, u32 offset, u8 size)
{
- u64 var;
+ u64 var = 0;
- if (cap->is_io) {
+ switch (cap->mode) {
+ case VP_ACCESS_IO:
+ {
u32 addr = cap->ioaddr + offset;
switch (size) {
case 8:
case 1:
var = inb(addr);
break;
- default:
- var = 0;
}
- } else {
+ break;
+ }
+
+ case VP_ACCESS_MMIO:
+ {
void *addr = cap->memaddr + offset;
switch (size) {
case 8:
case 1:
var = readb(addr);
break;
- default:
- var = 0;
}
+ break;
+ }
+
+ case VP_ACCESS_PCICFG:
+ {
+ u32 addr = cap->baroff + offset;
+ pci_config_writeb(cap->bdf, cap->cfg +
+ offsetof(struct virtio_pci_cfg_cap, cap.bar),
+ cap->bar);
+ pci_config_writel(cap->bdf, cap->cfg +
+ offsetof(struct virtio_pci_cfg_cap, cap.offset),
+ addr);
+ pci_config_writel(cap->bdf, cap->cfg +
+ offsetof(struct virtio_pci_cfg_cap, cap.length),
+ (size > 4) ? 4 : size);
+ switch (size) {
+ case 8:
+ var = pci_config_readl(cap->bdf, cap->cfg +
+ offsetof(struct virtio_pci_cfg_cap, pci_cfg_data));
+ pci_config_writel(cap->bdf, cap->cfg +
+ offsetof(struct virtio_pci_cfg_cap, cap.offset),
+ addr + 4);
+ var |= (u64)pci_config_readl(cap->bdf, cap->cfg +
+ offsetof(struct virtio_pci_cfg_cap, pci_cfg_data)) << 32;
+ break;
+ case 4:
+ var = pci_config_readl(cap->bdf, cap->cfg +
+ offsetof(struct virtio_pci_cfg_cap, pci_cfg_data));
+ break;
+ case 2:
+ var = pci_config_readw(cap->bdf, cap->cfg +
+ offsetof(struct virtio_pci_cfg_cap, pci_cfg_data));
+ break;
+ case 1:
+ var = pci_config_readb(cap->bdf, cap->cfg +
+ offsetof(struct virtio_pci_cfg_cap, pci_cfg_data));
+ break;
+ }
+ }
}
dprintf(9, "vp read %x (%d) -> 0x%llx\n", cap->ioaddr + offset, size, var);
return var;
void _vp_write(struct vp_cap *cap, u32 offset, u8 size, u64 var)
{
dprintf(9, "vp write %x (%d) <- 0x%llx\n", cap->ioaddr + offset, size, var);
- if (cap->is_io) {
+
+ switch (cap->mode) {
+ case VP_ACCESS_IO:
+ {
u32 addr = cap->ioaddr + offset;
switch (size) {
case 4:
outb(var, addr);
break;
}
- } else {
+ break;
+ }
+
+ case VP_ACCESS_MMIO:
+ {
void *addr = cap->memaddr + offset;
switch (size) {
case 4:
writeb(addr, var);
break;
}
+ break;
+ }
+
+ case VP_ACCESS_PCICFG:
+ {
+ u32 addr = cap->baroff + offset;
+ pci_config_writeb(cap->bdf, cap->cfg +
+ offsetof(struct virtio_pci_cfg_cap, cap.bar),
+ cap->bar);
+ pci_config_writel(cap->bdf, cap->cfg +
+ offsetof(struct virtio_pci_cfg_cap, cap.offset),
+ addr);
+ pci_config_writel(cap->bdf, cap->cfg +
+ offsetof(struct virtio_pci_cfg_cap, cap.length),
+ size);
+ switch (size) {
+ case 4:
+ pci_config_writel(cap->bdf, cap->cfg +
+ offsetof(struct virtio_pci_cfg_cap, pci_cfg_data),
+ var);
+ break;
+ case 2:
+ pci_config_writew(cap->bdf, cap->cfg +
+ offsetof(struct virtio_pci_cfg_cap, pci_cfg_data),
+ var);
+ break;
+ case 1:
+ pci_config_writeb(cap->bdf, cap->cfg +
+ offsetof(struct virtio_pci_cfg_cap, pci_cfg_data),
+ var);
+ break;
+ }
+ }
}
}
{
if (vp->use_modern) {
u32 offset = vq->queue_notify_off * vp->notify_off_multiplier;
- if (vp->notify.is_io) {
+ switch (vp->notify.mode) {
+ case VP_ACCESS_IO:
outw(vq->queue_index, vp->notify.ioaddr + offset);
- } else {
+ break;
+ case VP_ACCESS_MMIO:
writew(vp->notify.memaddr + offset, vq->queue_index);
+ break;
+ case VP_ACCESS_PCICFG:
+ pci_config_writeb(vp->notify.bdf, vp->notify.cfg +
+ offsetof(struct virtio_pci_cfg_cap, cap.bar),
+ vp->notify.bar);
+ pci_config_writel(vp->notify.bdf, vp->notify.cfg +
+ offsetof(struct virtio_pci_cfg_cap, cap.offset),
+ vp->notify.baroff + offset);
+ pci_config_writel(vp->notify.bdf, vp->notify.cfg +
+ offsetof(struct virtio_pci_cfg_cap, cap.length),
+ 2);
+ pci_config_writew(vp->notify.bdf, vp->notify.cfg +
+ offsetof(struct virtio_pci_cfg_cap, pci_cfg_data),
+ vq->queue_index);
}
dprintf(9, "vp notify %x (%d) -- 0x%x\n",
vp->notify.ioaddr, 2, vq->queue_index);
{
u8 cap = pci_find_capability(pci, PCI_CAP_ID_VNDR, 0);
struct vp_cap *vp_cap;
- u32 offset, mul;
+ const char *mode;
+ u32 offset, base, mul;
+ u64 addr;
u8 type;
memset(vp, 0, sizeof(*vp));
case VIRTIO_PCI_CAP_DEVICE_CFG:
vp_cap = &vp->device;
break;
+ case VIRTIO_PCI_CAP_PCI_CFG:
+ vp->common.cfg = cap;
+ vp->common.bdf = pci->bdf;
+ vp->notify.cfg = cap;
+ vp->notify.bdf = pci->bdf;
+ vp->isr.cfg = cap;
+ vp->isr.bdf = pci->bdf;
+ vp->device.cfg = cap;
+ vp->device.bdf = pci->bdf;
+ vp_cap = NULL;
+ dprintf(1, "pci dev %x:%x virtio cap at 0x%x type %d [pci cfg access]\n",
+ pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf),
+ cap, type);
+ break;
default:
vp_cap = NULL;
break;
offsetof(struct virtio_pci_cap, bar));
offset = pci_config_readl(pci->bdf, cap +
offsetof(struct virtio_pci_cap, offset));
- u32 bar = PCI_BASE_ADDRESS_0 + 4 * vp_cap->bar;
- if (pci_config_readl(pci->bdf, bar) & PCI_BASE_ADDRESS_SPACE_IO) {
- vp_cap->is_io = 1;
- u32 addr = pci_enable_iobar(pci, bar);
+ base = PCI_BASE_ADDRESS_0 + 4 * vp_cap->bar;
+ addr = pci_config_readl(pci->bdf, base);
+ if (addr & PCI_BASE_ADDRESS_SPACE_IO) {
+ addr &= PCI_BASE_ADDRESS_IO_MASK;
+ vp_cap->mode = VP_ACCESS_IO;
+ } else if ((addr & PCI_BASE_ADDRESS_MEM_TYPE_MASK) ==
+ PCI_BASE_ADDRESS_MEM_TYPE_64) {
+ addr &= PCI_BASE_ADDRESS_MEM_MASK;
+ addr |= (u64)pci_config_readl(pci->bdf, base + 4) << 32;
+ vp_cap->mode = (addr > 0xffffffffll) ?
+ VP_ACCESS_PCICFG : VP_ACCESS_MMIO;
+ } else {
+ addr &= PCI_BASE_ADDRESS_MEM_MASK;
+ vp_cap->mode = VP_ACCESS_MMIO;
+ }
+ switch (vp_cap->mode) {
+ case VP_ACCESS_IO:
+ {
+ u32 addr = pci_enable_iobar(pci, vp_cap->bar);
if (!addr)
return;
vp_cap->ioaddr = addr + offset;
- } else {
- vp_cap->is_io = 0;
- void *addr = pci_enable_membar(pci, bar);
+ mode = "io";
+ break;
+ }
+ case VP_ACCESS_MMIO:
+ {
+ void *addr = pci_enable_membar(pci, vp_cap->bar);
if (!addr)
return;
vp_cap->memaddr = addr + offset;
+ mode = "mmio";
+ break;
+ }
+ case VP_ACCESS_PCICFG:
+ mode = "pcicfg";
+ vp_cap->baroff = offset;
+ break;
+ default:
+ mode = "Huh?";
+ break;
}
- dprintf(3, "pci dev %pP virtio cap at 0x%x type %d "
- "bar %d at 0x%08x off +0x%04x [%s]\n",
- pci, vp_cap->cap, type, vp_cap->bar, vp_cap->ioaddr, offset,
- vp_cap->is_io ? "io" : "mmio");
+ dprintf(1, "pci dev %x:%x virtio cap at 0x%x type %d "
+ "bar %d at 0x%08llx off +0x%04x [%s]\n",
+ pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf),
+ vp_cap->cap, type, vp_cap->bar, addr, offset, mode);
}
cap = pci_find_capability(pci, PCI_CAP_ID_VNDR, cap);
vp->legacy.ioaddr = pci_enable_iobar(pci, PCI_BASE_ADDRESS_0);
if (!vp->legacy.ioaddr)
return;
- vp->legacy.is_io = 1;
+ vp->legacy.mode = VP_ACCESS_IO;
}
vp_reset(vp);