socsvn commit: r302902 - soc2016/iateaca/bhyve-hda-head/usr.sbin/bhyve

iateaca at FreeBSD.org iateaca at FreeBSD.org
Sat May 14 13:53:43 UTC 2016


Author: iateaca
Date: Sat May 14 13:53:42 2016
New Revision: 302902
URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=302902

Log:
  add pci_hda in bhyve
  probe the HDA controller - set the PCI configuration space, allocate BAR0 memory addresses and request IRQ
  add HDA Controller Register Set offsets
  add HDA controller stream in and out registers
  design the layout of registers, implement the read and write access to the registers
  
  A    bhyve/pci_hda.c

Added:
  soc2016/iateaca/bhyve-hda-head/usr.sbin/bhyve/pci_hda.c

Added: soc2016/iateaca/bhyve-hda-head/usr.sbin/bhyve/pci_hda.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ soc2016/iateaca/bhyve-hda-head/usr.sbin/bhyve/pci_hda.c	Sat May 14 13:53:42 2016	(r302902)
@@ -0,0 +1,314 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "pci_emul.h"
+
+/*
+ * HDA Debug Log
+ */
+#define DEBUG_HDA			1
+#if DEBUG_HDA == 1
+static FILE *dbg;
+#define DPRINTF(fmt, arg...)						\
+do {fprintf(dbg, "%s-%d: " fmt, __func__, __LINE__, ##arg);		\
+fflush(dbg); } while (0)
+#else
+#define DPRINTF(fmt, arg...)
+#endif
+
+/*
+ * HDA defines
+ */
+#define INTEL_VENDORID		0x8086
+#define HDA_INTEL_82801G	0x27d8
+
+#define HDA_OSS_NO		0x04
+#define HDA_ISS_NO		0x04
+#define HDA_LAST_OFFSET		(0x80 + ((HDA_ISS_NO) * 0x20) + ((HDA_OSS_NO) * 0x20))
+
+/*
+ * HDA Controller Register Offsets
+ */
+#define HDAC_GCAP       0x00    /* 2 - Global Capabilities*/
+#define HDAC_VMIN       0x02    /* 1 - Minor Version */
+#define HDAC_VMAJ       0x03    /* 1 - Major Version */
+#define HDAC_OUTPAY     0x04    /* 2 - Output Payload Capability */
+#define HDAC_INPAY      0x06    /* 2 - Input Payload Capability */
+#define HDAC_GCTL       0x08    /* 4 - Global Control */
+#define HDAC_WAKEEN     0x0c    /* 2 - Wake Enable */
+#define HDAC_STATESTS   0x0e    /* 2 - State Change Status */
+#define HDAC_GSTS       0x10    /* 2 - Global Status */
+#define HDAC_OUTSTRMPAY 0x18    /* 2 - Output Stream Payload Capability */
+#define HDAC_INSTRMPAY  0x1a    /* 2 - Input Stream Payload Capability */
+#define HDAC_INTCTL     0x20    /* 4 - Interrupt Control */
+#define HDAC_INTSTS     0x24    /* 4 - Interrupt Status */
+#define HDAC_WALCLK     0x30    /* 4 - Wall Clock Counter */
+#define HDAC_SSYNC      0x38    /* 4 - Stream Synchronization */
+#define HDAC_CORBLBASE  0x40    /* 4 - CORB Lower Base Address */
+#define HDAC_CORBUBASE  0x44    /* 4 - CORB Upper Base Address */
+#define HDAC_CORBWP     0x48    /* 2 - CORB Write Pointer */
+#define HDAC_CORBRP     0x4a    /* 2 - CORB Read Pointer */
+#define HDAC_CORBCTL    0x4c    /* 1 - CORB Control */
+#define HDAC_CORBSTS    0x4d    /* 1 - CORB Status */
+#define HDAC_CORBSIZE   0x4e    /* 1 - CORB Size */
+#define HDAC_RIRBLBASE  0x50    /* 4 - RIRB Lower Base Address */
+#define HDAC_RIRBUBASE  0x54    /* 4 - RIRB Upper Base Address */
+#define HDAC_RIRBWP     0x58    /* 2 - RIRB Write Pointer */
+#define HDAC_RINTCNT    0x5a    /* 2 - Response Interrupt Count */
+#define HDAC_RIRBCTL    0x5c    /* 1 - RIRB Control */
+#define HDAC_RIRBSTS    0x5d    /* 1 - RIRB Status */
+#define HDAC_RIRBSIZE   0x5e    /* 1 - RIRB Size */
+#define HDAC_ICOI       0x60    /* 4 - Immediate Command Output Interface */
+#define HDAC_ICII       0x64    /* 4 - Immediate Command Input Interface */
+#define HDAC_ICIS       0x68    /* 2 - Immediate Command Status */
+#define HDAC_DPIBLBASE  0x70    /* 4 - DMA Position Buffer Lower Base */
+#define HDAC_DPIBUBASE  0x74    /* 4 - DMA Position Buffer Upper Base */
+#define HDAC_SDCTL0     0x80    /* 3 - Stream Descriptor Control */
+#define HDAC_SDCTL1     0x81    /* 3 - Stream Descriptor Control */
+#define HDAC_SDCTL2     0x82    /* 3 - Stream Descriptor Control */
+#define HDAC_SDSTS      0x83    /* 1 - Stream Descriptor Status */
+#define HDAC_SDLPIB     0x84    /* 4 - Link Position in Buffer */
+#define HDAC_SDCBL      0x88    /* 4 - Cyclic Buffer Length */
+#define HDAC_SDLVI      0x8C    /* 2 - Last Valid Index */
+#define HDAC_SDFIFOS    0x90    /* 2 - FIFOS */
+#define HDAC_SDFMT      0x92    /* 2 - fmt */
+#define HDAC_SDBDPL     0x98    /* 4 - Buffer Descriptor Pointer Lower Base */
+#define HDAC_SDBDPU     0x9C    /* 4 - Buffer Descriptor Pointer Upper Base */
+
+#define _HDAC_ISDOFFSET(n, iss, oss)    (0x80 + ((n) * 0x20))
+#define _HDAC_ISDCTL(n, iss, oss)       (0x00 + _HDAC_ISDOFFSET(n, iss, oss))
+#define _HDAC_ISDSTS(n, iss, oss)       (0x03 + _HDAC_ISDOFFSET(n, iss, oss))
+#define _HDAC_ISDPICB(n, iss, oss)      (0x04 + _HDAC_ISDOFFSET(n, iss, oss))
+#define _HDAC_ISDCBL(n, iss, oss)       (0x08 + _HDAC_ISDOFFSET(n, iss, oss))
+#define _HDAC_ISDLVI(n, iss, oss)       (0x0c + _HDAC_ISDOFFSET(n, iss, oss))
+#define _HDAC_ISDFIFOD(n, iss, oss)     (0x10 + _HDAC_ISDOFFSET(n, iss, oss))
+#define _HDAC_ISDFMT(n, iss, oss)       (0x12 + _HDAC_ISDOFFSET(n, iss, oss))
+#define _HDAC_ISDBDPL(n, iss, oss)      (0x18 + _HDAC_ISDOFFSET(n, iss, oss))
+#define _HDAC_ISDBDPU(n, iss, oss)      (0x1c + _HDAC_ISDOFFSET(n, iss, oss))
+
+#define _HDAC_OSDOFFSET(n, iss, oss)    (0x80 + ((iss) * 0x20) + ((n) * 0x20))
+#define _HDAC_OSDCTL(n, iss, oss)       (0x00 + _HDAC_OSDOFFSET(n, iss, oss))
+#define _HDAC_OSDSTS(n, iss, oss)       (0x03 + _HDAC_OSDOFFSET(n, iss, oss))
+#define _HDAC_OSDPICB(n, iss, oss)      (0x04 + _HDAC_OSDOFFSET(n, iss, oss))
+#define _HDAC_OSDCBL(n, iss, oss)       (0x08 + _HDAC_OSDOFFSET(n, iss, oss))
+#define _HDAC_OSDLVI(n, iss, oss)       (0x0c + _HDAC_OSDOFFSET(n, iss, oss))
+#define _HDAC_OSDFIFOD(n, iss, oss)     (0x10 + _HDAC_OSDOFFSET(n, iss, oss))
+#define _HDAC_OSDFMT(n, iss, oss)       (0x12 + _HDAC_OSDOFFSET(n, iss, oss))
+#define _HDAC_OSDBDPL(n, iss, oss)      (0x18 + _HDAC_OSDOFFSET(n, iss, oss))
+#define _HDAC_OSDBDPU(n, iss, oss)      (0x1c + _HDAC_OSDOFFSET(n, iss, oss))
+
+/*
+ * HDA data structures
+ */
+
+struct hda_softc;
+
+typedef void (*hda_set_reg_handler)(struct hda_softc *sc, uint32_t old);
+
+struct hda_softc {
+	uint32_t regs[HDA_LAST_OFFSET];
+};
+
+/*
+ * HDA module function declarations
+ */
+static void
+hda_set_reg_by_offset(struct hda_softc *sc, uint32_t offset, uint32_t value);
+static uint32_t
+hda_get_reg_by_offset(struct hda_softc *sc, uint32_t offset);
+static void
+hda_set_field_by_offset(struct hda_softc *sc, uint32_t offset, uint32_t mask, uint32_t value);
+
+static struct hda_softc *hda_init(const char *opts);
+static void hda_reset_regs(struct hda_softc *sc);
+static uint32_t
+hda_read(struct hda_softc *sc, uint32_t offset);
+static int
+hda_write(struct hda_softc *sc, uint32_t offset, uint32_t value);
+
+/*
+ * PCI HDA function declarations
+ */
+static int
+pci_hda_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts);
+static void
+pci_hda_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
+		int baridx, uint64_t offset, int size, uint64_t value);
+static uint64_t
+pci_hda_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
+		int baridx, uint64_t offset, int size);
+/*
+ * HDA global data
+ */
+
+static const hda_set_reg_handler hda_set_reg_table[] = {
+	[HDA_LAST_OFFSET] = NULL,
+};
+
+struct pci_devemu pci_de_hda = {
+	.pe_emu		= "hda",
+	.pe_init	= pci_hda_init,
+	.pe_barwrite	= pci_hda_write,
+	.pe_barread	= pci_hda_read
+};
+
+PCI_EMUL_SET(pci_de_hda);
+
+/*
+ * HDA module function definitions
+ */
+
+static void
+hda_set_reg_by_offset(struct hda_softc *sc, uint32_t offset, uint32_t value)
+{
+	assert(offset < HDA_LAST_OFFSET);
+	sc->regs[offset] = value;
+
+	return;
+}
+
+static uint32_t
+hda_get_reg_by_offset(struct hda_softc *sc, uint32_t offset)
+{
+	assert(offset < HDA_LAST_OFFSET);
+	return sc->regs[offset];
+}
+
+static void
+hda_set_field_by_offset(struct hda_softc *sc, uint32_t offset, uint32_t mask, uint32_t value)
+{
+	uint32_t reg_value = 0;
+
+	reg_value = hda_get_reg_by_offset(sc, offset);
+
+	reg_value &= ~mask;
+	reg_value |= value;
+
+	hda_set_reg_by_offset(sc, offset, reg_value);
+
+	return;
+}
+
+static struct hda_softc *hda_init(const char *opts)
+{
+	struct hda_softc *sc = NULL;
+
+#if DEBUG_HDA == 1
+	dbg = fopen("/tmp/bhyve_hda.log", "w+");
+#endif
+
+	DPRINTF("opts: %s\n", opts);
+
+	sc = calloc(1, sizeof(*sc));
+	if (!sc)
+		return NULL;
+
+	hda_reset_regs(sc);
+
+	return sc;
+}
+
+static void hda_reset_regs(struct hda_softc *sc)
+{
+	memset(sc->regs, 0, sizeof(sc->regs));
+
+	hda_set_reg_by_offset(sc, HDAC_GCAP, 0x4401);
+	hda_set_reg_by_offset(sc, HDAC_CORBSIZE, 0x42);
+	hda_set_reg_by_offset(sc, HDAC_RIRBSIZE, 0x42);
+
+	return;
+}
+
+static uint32_t
+hda_read(struct hda_softc *sc, uint32_t offset)
+{
+	return hda_get_reg_by_offset(sc, offset);
+}
+
+static int
+hda_write(struct hda_softc *sc, uint32_t offset, uint32_t value)
+{
+	uint32_t old = hda_get_reg_by_offset(sc, offset);
+	hda_set_reg_handler set_reg_handler = hda_set_reg_table[offset];
+
+	hda_set_reg_by_offset(sc, offset, value);
+
+	if (set_reg_handler)
+		set_reg_handler(sc, old);
+
+	return 0;
+}
+
+/*
+ * PCI HDA function definitions
+ */
+static int
+pci_hda_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
+{
+	struct hda_softc *sc = NULL;
+
+	assert(ctx != NULL);
+	assert(pi != NULL);
+
+	pci_set_cfgdata16(pi, PCIR_VENDOR, INTEL_VENDORID);
+	pci_set_cfgdata16(pi, PCIR_DEVICE, HDA_INTEL_82801G);
+
+	pci_set_cfgdata8(pi, PCIR_SUBCLASS, PCIS_MULTIMEDIA_HDA);
+	pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_MULTIMEDIA);
+
+	/* TODO check the right size */
+	/* allocate one BAR register for the Memory address offsets */
+	pci_emul_alloc_bar(pi, 0, PCIBAR_MEM32, 0x1000);
+
+	/* allocate an IRQ pin for our slot */
+	pci_lintr_request(pi);
+
+	sc = hda_init(opts);
+	if (!sc)
+		return -1;
+
+	pi->pi_arg = sc;
+
+	return 0;
+}
+
+static void
+pci_hda_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
+		int baridx, uint64_t offset, int size, uint64_t value)
+{
+	struct hda_softc *sc = pi->pi_arg;
+	int err;
+
+	assert(sc);
+	assert(baridx == 0);
+	assert(size <= 4);
+
+	DPRINTF("offset: 0x%lx value: 0x%lx\n", offset, value);
+
+	err = hda_write(sc, offset, value);
+	assert(!err);
+
+	return;
+}
+
+static uint64_t
+pci_hda_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
+		int baridx, uint64_t offset, int size)
+{
+	struct hda_softc *sc = pi->pi_arg;
+	uint64_t value = 0;
+
+	assert(sc);
+	assert(baridx == 0);
+	assert(size <= 4);
+
+	value = hda_read(sc, offset);
+
+	DPRINTF("offset: 0x%lx value: 0x%lx\n", offset, value);
+
+	return value;
+}
+
+


More information about the svn-soc-all mailing list