mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-06-19 12:12:16 +00:00
Windows graphic driver obtains DSM address from in-BAR mmio register which has passthroughed. Not like the other platforms obtained from pci configure space register which has virtualized. So TGL has to keep identical mapping to avoid trap mmio BAR to do the emulation. To keep simple, this patch hardcode the TGL DSM region in vE820 table, this will cause memory waste here. In the near future, we need refine the entire vE820 logic as it is hard to maintained due to many reserved regions have introduced in recently. Signed-off-by: Sun Peng <peng.p.sun@intel.com> Acked-by: Wang, Yu1 <yu1.wang@intel.com> Tracked-On: #5461
1649 lines
48 KiB
C
1649 lines
48 KiB
C
/*-
|
|
* Copyright (c) 2011 NetApp, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*
|
|
* $FreeBSD$
|
|
*/
|
|
|
|
#include <sys/mman.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/user.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdbool.h>
|
|
#include <string.h>
|
|
#include <err.h>
|
|
#include <errno.h>
|
|
#include <pthread.h>
|
|
#include <pciaccess.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
|
|
#include "iodev.h"
|
|
#include "vmmapi.h"
|
|
#include "pciio.h"
|
|
#include "pci_core.h"
|
|
#include "acpi.h"
|
|
#include "dm.h"
|
|
|
|
|
|
/* Some audio drivers get topology data from ACPI NHLT table.
|
|
* For such drivers, we need to copy the host NHLT table to make it
|
|
* available to the Guest OS. Most audio drivers don't need this by
|
|
* default, when that's the case setting this macro to 0 will avoid
|
|
* unexpected failures.
|
|
* The cAVS audio needs this however, so we enable this feature.
|
|
*/
|
|
#define AUDIO_NHLT_HACK 1
|
|
|
|
#define PCI_BDF_GPU 0x00000010 /* 00:02.0 */
|
|
|
|
/* Reserved region in e820 table for GVT
|
|
* for GVT-g use:
|
|
* [0xDF000000, 0xDF800000) 8M, GOP FB, used OvmfPkg/GvtGopDxe for 1080p@30
|
|
* [0xDFFFD000, 0xDFFFF000) 8K, OpRegion, used by GvtGopDxe and GVT-g
|
|
* [0xDFFFF000, 0XE0000000) 4K, Reserved, not used
|
|
* for TGL GVT-d use:
|
|
* [0x3B800000, 0x3F800000) 64M, Date Stolen Memory
|
|
* [0x3F800000, 0X3F804000] 16K, OpRegion and Extended OpRegion
|
|
* for EHL/WHL/KBL GVT-d use:
|
|
* [0xDB000000, 0xDF000000) 64M, DSM, used by native GOP and gfx driver
|
|
* [0xDFFFC000, 0xDFFFE000) 8K, OpRegion, used by native GOP and gfx driver
|
|
* [0xDFFFE000, 0XE0000000] 8K, Extended OpRegion, store raw VBT
|
|
* OpRegion: 8KB(0x2000)
|
|
* [ OpRegion Header ] Offset: 0x0
|
|
* [ Mailbox #1: ACPI ] Offset: 0x100
|
|
* [ Mailbox #2: SWSCI ] Offset: 0x200
|
|
* [ Mailbox #3: ASLE ] Offset: 0x300
|
|
* [ Mailbox #4: VBT ] Offset: 0x400
|
|
* [ Mailbox #5: ASLE EXT ] Offset: 0x1C00
|
|
* Extended OpRegion: 8KB(0x2000)
|
|
* [ Raw VBT ] Offset: 0x0
|
|
* If VBT <= 6KB, stores in Mailbox #4
|
|
* If VBT > 6KB, stores in Extended OpRegion
|
|
* ASLE.rvda stores the location of VBT.
|
|
* For OpRegion 2.1+: ASLE.rvda = offset to OpRegion base address
|
|
* For OpRegion 2.0: ASLE.rvda = physical address, not support currently
|
|
*/
|
|
#define GPU_DSM_GPA 0xDB000000
|
|
#define GPU_DSM_SIZE 0x4000000
|
|
#define GPU_OPREGION_GPA 0xDFFFC000
|
|
#define GPU_OPREGION_SIZE 0x4000
|
|
/*
|
|
* TODO: Forced DSM/OPREGION size requires native BIOS configuration.
|
|
* This limitation need remove in future
|
|
*/
|
|
uint32_t gpu_dsm_hpa = 0;
|
|
uint32_t gpu_dsm_gpa = 0;
|
|
uint32_t gpu_opregion_hpa = 0;
|
|
uint32_t gpu_opregion_gpa = 0;
|
|
|
|
extern uint64_t audio_nhlt_len;
|
|
|
|
/* reference count for libpciaccess init/deinit */
|
|
static int pciaccess_ref_cnt;
|
|
static pthread_mutex_t ref_cnt_mtx = PTHREAD_MUTEX_INITIALIZER;
|
|
|
|
|
|
struct passthru_dev {
|
|
struct pci_vdev *dev;
|
|
struct pcibar bar[PCI_BARMAX + 1];
|
|
struct {
|
|
int capoff;
|
|
} msi;
|
|
struct {
|
|
int capoff;
|
|
} msix;
|
|
struct {
|
|
int capoff;
|
|
} pmcap;
|
|
bool pcie_cap;
|
|
struct pcisel sel;
|
|
int phys_pin;
|
|
uint16_t phys_bdf;
|
|
struct pci_device *phys_dev;
|
|
/* Options for passthrough device:
|
|
* need_reset - reset dev before passthrough
|
|
*/
|
|
bool need_reset;
|
|
bool d3hot_reset;
|
|
bool (*has_virt_pcicfg_regs)(int offset);
|
|
};
|
|
|
|
static uint32_t
|
|
read_config(struct pci_device *phys_dev, long reg, int width)
|
|
{
|
|
uint32_t temp = 0;
|
|
|
|
switch (width) {
|
|
case 1:
|
|
pci_device_cfg_read_u8(phys_dev, (uint8_t *)&temp, reg);
|
|
break;
|
|
case 2:
|
|
pci_device_cfg_read_u16(phys_dev, (uint16_t *)&temp, reg);
|
|
break;
|
|
case 4:
|
|
pci_device_cfg_read_u32(phys_dev, &temp, reg);
|
|
break;
|
|
default:
|
|
pr_warn("%s: invalid reg width", __func__);
|
|
return -1;
|
|
}
|
|
|
|
return temp;
|
|
}
|
|
|
|
static int
|
|
write_config(struct pci_device *phys_dev, long reg, int width, uint32_t data)
|
|
{
|
|
int temp = -1;
|
|
|
|
switch (width) {
|
|
case 1:
|
|
temp = pci_device_cfg_write_u8(phys_dev, data, reg);
|
|
break;
|
|
case 2:
|
|
temp = pci_device_cfg_write_u16(phys_dev, data, reg);
|
|
break;
|
|
case 4:
|
|
temp = pci_device_cfg_write_u32(phys_dev, data, reg);
|
|
break;
|
|
default:
|
|
pr_warn("%s: invalid reg width", __func__);
|
|
}
|
|
|
|
return temp;
|
|
}
|
|
|
|
static int
|
|
cfginit_cap(struct vmctx *ctx, struct passthru_dev *ptdev)
|
|
{
|
|
int ptr, cap, sts;
|
|
struct pci_device *phys_dev = ptdev->phys_dev;
|
|
|
|
/*
|
|
* Parse the capabilities and cache the location of the MSI
|
|
* and MSI-X capabilities.
|
|
*/
|
|
sts = read_config(phys_dev, PCIR_STATUS, 2);
|
|
if (sts & PCIM_STATUS_CAPPRESENT) {
|
|
ptr = read_config(phys_dev, PCIR_CAP_PTR, 1);
|
|
while (ptr != 0 && ptr != 0xff) {
|
|
cap = read_config(phys_dev, ptr + PCICAP_ID, 1);
|
|
if (cap == PCIY_MSI) {
|
|
ptdev->msi.capoff = ptr;
|
|
} else if (cap == PCIY_MSIX) {
|
|
ptdev->msix.capoff = ptr;
|
|
} else if (cap == PCIY_EXPRESS) {
|
|
ptdev->pcie_cap = true;
|
|
} else if (cap == PCIY_PMG)
|
|
ptdev->pmcap.capoff = ptr;
|
|
|
|
ptr = read_config(phys_dev, ptr + PCICAP_NEXTPTR, 1);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
passthru_set_power_state(struct passthru_dev *ptdev, uint16_t dpsts) {
|
|
int ret = -1;
|
|
uint32_t val;
|
|
|
|
dpsts &= PCIM_PSTAT_DMASK;
|
|
if (ptdev->pmcap.capoff != 0) {
|
|
val = read_config(ptdev->phys_dev,
|
|
ptdev->pmcap.capoff + PCIR_POWER_STATUS, 2);
|
|
val = (val & ~PCIM_PSTAT_DMASK) | dpsts;
|
|
|
|
write_config(ptdev->phys_dev,
|
|
ptdev->pmcap.capoff + PCIR_POWER_STATUS, 2, val);
|
|
|
|
ret = 0;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static inline int ptdev_msix_table_bar(struct passthru_dev *ptdev)
|
|
{
|
|
return ptdev->dev->msix.table_bar;
|
|
}
|
|
|
|
static inline int ptdev_msix_pba_bar(struct passthru_dev *ptdev)
|
|
{
|
|
return ptdev->dev->msix.pba_bar;
|
|
}
|
|
|
|
static int
|
|
cfginitbar(struct vmctx *ctx, struct passthru_dev *ptdev)
|
|
{
|
|
int i, error;
|
|
struct pci_vdev *dev;
|
|
struct pci_bar_io bar;
|
|
enum pcibar_type bartype;
|
|
uint64_t base, size;
|
|
uint32_t vbar_lo32;
|
|
|
|
dev = ptdev->dev;
|
|
|
|
/*
|
|
* Initialize BAR registers
|
|
*/
|
|
for (i = 0; i <= PCI_BARMAX; i++) {
|
|
bzero(&bar, sizeof(bar));
|
|
bar.sel = ptdev->sel;
|
|
bar.reg = PCIR_BAR(i);
|
|
|
|
bar.base = read_config(ptdev->phys_dev, bar.reg, 4);
|
|
bar.length = ptdev->phys_dev->regions[i].size;
|
|
|
|
if (PCI_BAR_IO(bar.base)) {
|
|
bartype = PCIBAR_IO;
|
|
base = bar.base & PCIM_BAR_IO_BASE;
|
|
} else {
|
|
switch (bar.base & PCIM_BAR_MEM_TYPE) {
|
|
case PCIM_BAR_MEM_64:
|
|
bartype = PCIBAR_MEM64;
|
|
break;
|
|
default:
|
|
bartype = PCIBAR_MEM32;
|
|
break;
|
|
}
|
|
base = bar.base & PCIM_BAR_MEM_BASE;
|
|
}
|
|
size = bar.length;
|
|
|
|
if (bartype != PCIBAR_IO) {
|
|
/* note here PAGE_MASK is 0xFFFFF000 */
|
|
if ((base & ~PAGE_MASK) != 0) {
|
|
pr_info("passthru device %x/%x/%x BAR %d: "
|
|
"base %#lx not page aligned\n",
|
|
ptdev->sel.bus, ptdev->sel.dev,
|
|
ptdev->sel.func, i, base);
|
|
return -1;
|
|
}
|
|
/* roundup to PAGE_SIZE for bar size */
|
|
if ((size & ~PAGE_MASK) != 0) {
|
|
pr_info("passthru device %x/%x/%x BAR %d: "
|
|
"size[%lx] is expanded to page aligned [%lx]\n",
|
|
ptdev->sel.bus, ptdev->sel.dev,
|
|
ptdev->sel.func, i, size, roundup2(size, PAGE_SIZE));
|
|
size = roundup2(size, PAGE_SIZE);
|
|
}
|
|
|
|
}
|
|
|
|
/* Cache information about the "real" BAR */
|
|
ptdev->bar[i].type = bartype;
|
|
ptdev->bar[i].size = size;
|
|
ptdev->bar[i].addr = base;
|
|
|
|
if (size == 0)
|
|
continue;
|
|
|
|
/* Allocate the BAR in the guest I/O or MMIO space */
|
|
error = pci_emul_alloc_pbar(dev, i, base, bartype, size);
|
|
if (error)
|
|
return -1;
|
|
|
|
/*
|
|
* For pass-thru devices,
|
|
* set the bar prefetchable property the same as physical bar.
|
|
*
|
|
* the pci bar prefetchable property has set by pci_emul_alloc_pbar,
|
|
* here, override the prefetchable property according to the physical bar.
|
|
*/
|
|
if (bartype == PCIBAR_MEM32 || bartype == PCIBAR_MEM64) {
|
|
vbar_lo32 = pci_get_cfgdata32(dev, PCIR_BAR(i));
|
|
|
|
if (bar.base & PCIM_BAR_MEM_PREFETCH)
|
|
vbar_lo32 |= PCIM_BAR_MEM_PREFETCH;
|
|
else
|
|
vbar_lo32 &= ~PCIM_BAR_MEM_PREFETCH;
|
|
|
|
pci_set_cfgdata32(dev, PCIR_BAR(i), vbar_lo32);
|
|
}
|
|
|
|
/*
|
|
* 64-bit BAR takes up two slots so skip the next one.
|
|
*/
|
|
if (bartype == PCIBAR_MEM64) {
|
|
i++;
|
|
if (i > PCI_BARMAX) {
|
|
pr_err("BAR count out of range\n");
|
|
return -1;
|
|
}
|
|
|
|
ptdev->bar[i].type = PCIBAR_MEMHI64;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* return value:
|
|
* -1 : fail
|
|
* >=0: succeed
|
|
* IRQ_INTX(0): phy dev has no MSI support
|
|
* IRQ_MSI(1): phy dev has MSI support
|
|
*/
|
|
static int
|
|
cfginit(struct vmctx *ctx, struct passthru_dev *ptdev, int bus,
|
|
int slot, int func)
|
|
{
|
|
int irq_type = IRQ_MSI;
|
|
char reset_path[60];
|
|
int fd;
|
|
|
|
bzero(&ptdev->sel, sizeof(struct pcisel));
|
|
ptdev->sel.bus = bus;
|
|
ptdev->sel.dev = slot;
|
|
ptdev->sel.func = func;
|
|
|
|
if (cfginit_cap(ctx, ptdev) != 0) {
|
|
pr_err("Capability check fails for PCI %x/%x/%x",
|
|
bus, slot, func);
|
|
return -1;
|
|
}
|
|
|
|
/* Check MSI or MSIX capabilities */
|
|
if (ptdev->msi.capoff == 0 && ptdev->msix.capoff == 0) {
|
|
pr_dbg("MSI not supported for PCI %x/%x/%x",
|
|
bus, slot, func);
|
|
irq_type = IRQ_INTX;
|
|
}
|
|
|
|
/* If SOS kernel provides 'reset' entry in sysfs, related dev has some
|
|
* reset capability, e.g. FLR, or secondary bus reset. We do 2 things:
|
|
* - reset each dev before passthrough to achieve valid dev state after
|
|
* UOS reboot
|
|
* - refuse to passthrough PCIe dev without any reset capability
|
|
*/
|
|
if (ptdev->need_reset) {
|
|
snprintf(reset_path, 40,
|
|
"/sys/bus/pci/devices/0000:%02x:%02x.%x/reset",
|
|
bus, slot, func);
|
|
|
|
fd = open(reset_path, O_WRONLY);
|
|
if (fd >= 0) {
|
|
if (write(fd, "1", 1) < 0)
|
|
pr_err("reset dev %x/%x/%x failed!\n",
|
|
bus, slot, func);
|
|
close(fd);
|
|
}
|
|
}
|
|
|
|
if (ptdev->d3hot_reset) {
|
|
if ((passthru_set_power_state(ptdev, PCIM_PSTAT_D3) != 0) ||
|
|
passthru_set_power_state(ptdev, PCIM_PSTAT_D0) != 0)
|
|
pr_warn("ptdev %x/%x/%x do d3hot_reset failed!\n", bus, slot, func);
|
|
}
|
|
|
|
if (cfginitbar(ctx, ptdev) != 0) {
|
|
pr_err("failed to initialize BARs for PCI %x/%x/%x",
|
|
bus, slot, func);
|
|
return -1;
|
|
} else
|
|
return irq_type;
|
|
}
|
|
|
|
/*
|
|
* convert the error code of pci_system_init in libpciaccess to DM standard
|
|
*
|
|
* pci_system_init in libpciaccess:
|
|
* return zero -> success
|
|
* return positive value -> failure
|
|
*
|
|
* DM standard:
|
|
* return zero -> success
|
|
* return negative value -> failure
|
|
*/
|
|
static int
|
|
native_pci_system_init()
|
|
{
|
|
int error;
|
|
|
|
error = pci_system_init();
|
|
|
|
/*
|
|
* convert the returned error value to negative since DM only handles
|
|
* the negative error code
|
|
*/
|
|
return -error;
|
|
}
|
|
|
|
/*
|
|
* return zero on success or non-zero on failure
|
|
*/
|
|
int
|
|
pciaccess_init(void)
|
|
{
|
|
int error;
|
|
|
|
pthread_mutex_lock(&ref_cnt_mtx);
|
|
|
|
if (!pciaccess_ref_cnt) {
|
|
error = native_pci_system_init();
|
|
if (error < 0) {
|
|
pr_err("libpciaccess couldn't access PCI system");
|
|
pthread_mutex_unlock(&ref_cnt_mtx);
|
|
return error;
|
|
}
|
|
}
|
|
pciaccess_ref_cnt++;
|
|
|
|
pthread_mutex_unlock(&ref_cnt_mtx);
|
|
|
|
return 0; /* success */
|
|
}
|
|
|
|
static bool
|
|
has_virt_pcicfg_regs_on_ehl_gpu(int offset)
|
|
{
|
|
return ((offset == PCIR_GEN11_BDSM_DW0) || (offset == PCIR_GEN11_BDSM_DW1) ||
|
|
(offset == PCIR_ASLS_CTL));
|
|
}
|
|
|
|
static bool
|
|
has_virt_pcicfg_regs_on_def_gpu(int offset)
|
|
{
|
|
return ((offset == PCIR_BDSM) || (offset == PCIR_ASLS_CTL));
|
|
}
|
|
|
|
/*
|
|
* passthrough GPU DSM(Data Stolen Memory) and Opregion to guest
|
|
*/
|
|
void
|
|
passthru_gpu_dsm_opregion(struct vmctx *ctx, struct passthru_dev *ptdev,
|
|
struct acrn_assign_pcidev *pcidev, uint16_t device)
|
|
{
|
|
uint32_t opregion_phys, dsm_mask_val;
|
|
|
|
/* get opregion hpa */
|
|
opregion_phys = read_config(ptdev->phys_dev, PCIR_ASLS_CTL, 4);
|
|
gpu_opregion_hpa = opregion_phys & PCIM_ASLS_OPREGION_MASK;
|
|
|
|
switch (device) {
|
|
case INTEL_ELKHARTLAKE:
|
|
/* BDSM register has 64 bits.
|
|
* bits 63:20 contains the base address of stolen memory
|
|
*/
|
|
gpu_dsm_hpa = read_config(ptdev->phys_dev, PCIR_GEN11_BDSM_DW0, 4);
|
|
dsm_mask_val = gpu_dsm_hpa & ~PCIM_BDSM_MASK;
|
|
gpu_dsm_hpa &= PCIM_BDSM_MASK;
|
|
gpu_dsm_hpa |= (uint64_t)read_config(ptdev->phys_dev, PCIR_GEN11_BDSM_DW1, 4) << 32;
|
|
gpu_dsm_gpa = GPU_DSM_GPA;
|
|
|
|
pci_set_cfgdata32(ptdev->dev, PCIR_GEN11_BDSM_DW0, gpu_dsm_gpa | dsm_mask_val);
|
|
/* write 0 to high 32-bits of BDSM on EHL platform */
|
|
pci_set_cfgdata32(ptdev->dev, PCIR_GEN11_BDSM_DW1, 0);
|
|
|
|
gpu_opregion_gpa = GPU_OPREGION_GPA;
|
|
|
|
ptdev->has_virt_pcicfg_regs = &has_virt_pcicfg_regs_on_ehl_gpu;
|
|
break;
|
|
|
|
case INTEL_TIGERLAKE:
|
|
/* BDSM register has 64 bits.
|
|
* bits 63:20 contains the base address of stolen memory
|
|
*/
|
|
gpu_dsm_hpa = read_config(ptdev->phys_dev, PCIR_GEN11_BDSM_DW0, 4);
|
|
dsm_mask_val = gpu_dsm_hpa & ~PCIM_BDSM_MASK;
|
|
gpu_dsm_hpa &= PCIM_BDSM_MASK;
|
|
gpu_dsm_hpa |= (uint64_t)read_config(ptdev->phys_dev, PCIR_GEN11_BDSM_DW1, 4) << 32;
|
|
/* Keep identical mapping for DSM region on TGL platform due to windows
|
|
* graphic driver obtain the DSM address from one mmio register locate
|
|
* in BAR instead of pci config space.
|
|
*/
|
|
gpu_dsm_gpa = gpu_dsm_hpa;
|
|
|
|
pci_set_cfgdata32(ptdev->dev, PCIR_GEN11_BDSM_DW0, gpu_dsm_gpa | dsm_mask_val);
|
|
/* write 0 to high 32-bits of BDSM on EHL platform */
|
|
pci_set_cfgdata32(ptdev->dev, PCIR_GEN11_BDSM_DW1, 0);
|
|
|
|
gpu_opregion_gpa = gpu_dsm_gpa + GPU_DSM_SIZE;
|
|
|
|
ptdev->has_virt_pcicfg_regs = &has_virt_pcicfg_regs_on_ehl_gpu;
|
|
break;
|
|
/* If on default platforms, such as KBL,WHL */
|
|
default:
|
|
/* bits 31:20 contains the base address of stolen memory */
|
|
gpu_dsm_hpa = read_config(ptdev->phys_dev, PCIR_BDSM, 4);
|
|
dsm_mask_val = gpu_dsm_hpa & ~PCIM_BDSM_MASK;
|
|
gpu_dsm_hpa &= PCIM_BDSM_MASK;
|
|
gpu_dsm_gpa = GPU_DSM_GPA;
|
|
|
|
pci_set_cfgdata32(ptdev->dev, PCIR_BDSM, gpu_dsm_gpa | dsm_mask_val);
|
|
|
|
gpu_opregion_gpa = GPU_OPREGION_GPA;
|
|
|
|
ptdev->has_virt_pcicfg_regs = &has_virt_pcicfg_regs_on_def_gpu;
|
|
break;
|
|
}
|
|
|
|
pci_set_cfgdata32(ptdev->dev, PCIR_ASLS_CTL, gpu_opregion_gpa | (opregion_phys & ~PCIM_ASLS_OPREGION_MASK));
|
|
|
|
/* initialize the EPT mapping for passthrough GPU dsm region */
|
|
vm_unmap_ptdev_mmio(ctx, 0, 2, 0, gpu_dsm_gpa, GPU_DSM_SIZE, gpu_dsm_hpa);
|
|
vm_map_ptdev_mmio(ctx, 0, 2, 0, gpu_dsm_gpa, GPU_DSM_SIZE, gpu_dsm_hpa);
|
|
|
|
/* initialize the EPT mapping for passthrough GPU opregion */
|
|
vm_unmap_ptdev_mmio(ctx, 0, 2, 0, gpu_opregion_gpa, GPU_OPREGION_SIZE, gpu_opregion_hpa);
|
|
vm_map_ptdev_mmio(ctx, 0, 2, 0, gpu_opregion_gpa, GPU_OPREGION_SIZE, gpu_opregion_hpa);
|
|
|
|
pcidev->type = QUIRK_PTDEV;
|
|
}
|
|
|
|
static int
|
|
parse_vmsix_on_msi_bar_id(char *s, int *id, int base)
|
|
{
|
|
char *str, *cp;
|
|
int ret = 0;
|
|
|
|
if (s == NULL)
|
|
return -EINVAL;
|
|
|
|
str = cp = strdup(s);
|
|
ret = dm_strtoi(cp, &cp, base, id);
|
|
free(str);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Passthrough device initialization function:
|
|
* - initialize virtual config space
|
|
* - read physical info via libpciaccess
|
|
* - issue related hypercall for passthrough
|
|
* - Do some specific actions:
|
|
* - enable NHLT for audio pt dev
|
|
* - emulate INTPIN/INTLINE
|
|
* - hide INTx link if ptdev support both MSI and INTx to force guest using
|
|
* MSI, so that mitigate ptdev GSI sharing issue.
|
|
*/
|
|
static int
|
|
passthru_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
|
|
{
|
|
int bus, slot, func, idx, error;
|
|
struct passthru_dev *ptdev;
|
|
struct pci_device_iterator *iter;
|
|
struct pci_device *phys_dev;
|
|
char *opt;
|
|
bool keep_gsi = false;
|
|
bool need_reset = true;
|
|
bool d3hot_reset = false;
|
|
int vmsix_on_msi_bar_id = -1;
|
|
struct acrn_assign_pcidev pcidev = {};
|
|
uint16_t vendor = 0, device = 0;
|
|
|
|
ptdev = NULL;
|
|
error = -EINVAL;
|
|
|
|
if (opts == NULL) {
|
|
pr_err("Empty passthru options\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
opt = strsep(&opts, ",");
|
|
if (parse_bdf(opt, &bus, &slot, &func, 16) != 0) {
|
|
pr_err("Invalid passthru BDF options:%s", opt);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (is_rtvm && (PCI_BDF(bus, slot, func) == PCI_BDF_GPU)) {
|
|
pr_err("%s RTVM doesn't support GVT-D.", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
while ((opt = strsep(&opts, ",")) != NULL) {
|
|
if (!strncmp(opt, "keep_gsi", 8))
|
|
keep_gsi = true;
|
|
else if (!strncmp(opt, "no_reset", 8))
|
|
need_reset = false;
|
|
else if (!strncmp(opt, "d3hot_reset", 11))
|
|
d3hot_reset = true;
|
|
else if (!strncmp(opt, "gpu", 3)) {
|
|
/* Create the dedicated "igd-lpc" on 00:1f.0 for IGD passthrough */
|
|
if (pci_parse_slot("31,igd-lpc") != 0)
|
|
pr_warn("faild to create igd-lpc");
|
|
} else if (!strncmp(opt, "vmsix_on_msi", 12)) {
|
|
opt = strsep(&opts, ",");
|
|
if (parse_vmsix_on_msi_bar_id(opt, &vmsix_on_msi_bar_id, 10) != 0) {
|
|
pr_err("faild to parse msix emulation bar id");
|
|
return -EINVAL;
|
|
}
|
|
|
|
} else
|
|
pr_warn("Invalid passthru options:%s", opt);
|
|
}
|
|
|
|
ptdev = calloc(1, sizeof(struct passthru_dev));
|
|
if (ptdev == NULL) {
|
|
pr_err("%s: calloc FAIL!", __func__);
|
|
error = -ENOMEM;
|
|
goto done;
|
|
}
|
|
|
|
ptdev->phys_bdf = PCI_BDF(bus, slot, func);
|
|
ptdev->need_reset = need_reset;
|
|
ptdev->d3hot_reset = d3hot_reset;
|
|
update_pt_info(ptdev->phys_bdf);
|
|
|
|
error = pciaccess_init();
|
|
if (error < 0)
|
|
goto done;
|
|
|
|
error = -ENODEV;
|
|
iter = pci_slot_match_iterator_create(NULL);
|
|
while ((phys_dev = pci_device_next(iter)) != NULL) {
|
|
if (phys_dev->bus == bus && phys_dev->dev == slot &&
|
|
phys_dev->func == func) {
|
|
ptdev->phys_dev = phys_dev;
|
|
error = 0;
|
|
break;
|
|
}
|
|
}
|
|
pci_iterator_destroy(iter);
|
|
|
|
if (error < 0) {
|
|
pr_err("No physical PCI device %x:%x.%x!", bus, slot, func);
|
|
goto done;
|
|
}
|
|
|
|
pci_device_probe(ptdev->phys_dev);
|
|
|
|
dev->arg = ptdev;
|
|
ptdev->dev = dev;
|
|
|
|
/* handle 0x3c~0x3f config space
|
|
* INTLINE/INTPIN: from emulated configuration space
|
|
* MINGNT/MAXLAT: from physical configuration space
|
|
*/
|
|
pci_set_cfgdata16(dev, PCIR_MINGNT,
|
|
read_config(ptdev->phys_dev, PCIR_MINGNT, 2));
|
|
|
|
|
|
/* Once this device is assigned to other guest, the original guest can't access it again
|
|
* So we need to cache verdor and device for filling DSDT.
|
|
*/
|
|
vendor = read_config(ptdev->phys_dev, PCIR_VENDOR, 2);
|
|
device = read_config(ptdev->phys_dev, PCIR_DEVICE, 2);
|
|
pci_set_cfgdata16(dev, PCIR_VENDOR, vendor);
|
|
pci_set_cfgdata16(dev, PCIR_DEVICE, device);
|
|
|
|
#if AUDIO_NHLT_HACK
|
|
/* device specific handling:
|
|
* audio: enable NHLT ACPI table
|
|
*/
|
|
if (vendor == 0x8086 && device == 0x5a98)
|
|
acpi_table_enable(NHLT_ENTRY_NO);
|
|
#endif
|
|
|
|
/* initialize config space */
|
|
error = cfginit(ctx, ptdev, bus, slot, func);
|
|
if (error < 0)
|
|
goto done;
|
|
|
|
if (vmsix_on_msi_bar_id != -1) {
|
|
error = pci_emul_alloc_pbar(dev, vmsix_on_msi_bar_id, 0, PCIBAR_MEM32, 4096);
|
|
if (error < 0)
|
|
goto done;
|
|
error = IRQ_MSI;
|
|
}
|
|
|
|
if (ptdev->phys_bdf == PCI_BDF_GPU)
|
|
passthru_gpu_dsm_opregion(ctx, ptdev, &pcidev, device);
|
|
|
|
pcidev.virt_bdf = PCI_BDF(dev->bus, dev->slot, dev->func);
|
|
pcidev.phys_bdf = ptdev->phys_bdf;
|
|
for (idx = 0; idx <= PCI_BARMAX; idx++) {
|
|
pcidev.bar[idx] = pci_get_cfgdata32(dev, PCIR_BAR(idx));
|
|
}
|
|
|
|
/* If ptdev support MSI/MSIX, stop here to skip virtual INTx setup.
|
|
* Forge Guest to use MSI/MSIX in this case to mitigate IRQ sharing
|
|
* issue
|
|
*/
|
|
if (error != IRQ_MSI || keep_gsi) {
|
|
/* Allocates the virq if ptdev only support INTx */
|
|
pci_lintr_request(dev);
|
|
|
|
ptdev->phys_pin = read_config(ptdev->phys_dev, PCIR_INTLINE, 1);
|
|
|
|
if (ptdev->phys_pin == -1 || ptdev->phys_pin > 256) {
|
|
pr_err("ptdev %x/%x/%x has wrong phys_pin %d, likely fail!",
|
|
bus, slot, func, ptdev->phys_pin);
|
|
error = -1;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
pcidev.intr_line = pci_get_cfgdata8(dev, PCIR_INTLINE);
|
|
pcidev.intr_pin = pci_get_cfgdata8(dev, PCIR_INTPIN);
|
|
error = vm_assign_pcidev(ctx, &pcidev);
|
|
done:
|
|
if (error && (ptdev != NULL)) {
|
|
free(ptdev);
|
|
}
|
|
return error;
|
|
}
|
|
|
|
void
|
|
pciaccess_cleanup(void)
|
|
{
|
|
pthread_mutex_lock(&ref_cnt_mtx);
|
|
pciaccess_ref_cnt--;
|
|
if (!pciaccess_ref_cnt)
|
|
pci_system_cleanup();
|
|
pthread_mutex_unlock(&ref_cnt_mtx);
|
|
}
|
|
|
|
static void
|
|
passthru_deinit(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
|
|
{
|
|
struct passthru_dev *ptdev;
|
|
uint16_t virt_bdf = PCI_BDF(dev->bus, dev->slot, dev->func);
|
|
struct acrn_assign_pcidev pcidev = {};
|
|
uint16_t phys_bdf = 0;
|
|
char reset_path[60];
|
|
int fd;
|
|
|
|
if (!dev->arg) {
|
|
pr_warn("%s: passthru_dev is NULL", __func__);
|
|
return;
|
|
}
|
|
|
|
ptdev = (struct passthru_dev *) dev->arg;
|
|
|
|
pr_info("vm_reset_ptdev_intx:0x%x-%x, ioapic virpin=%d.\n",
|
|
virt_bdf, ptdev->phys_bdf, dev->lintr.ioapic_irq);
|
|
if (dev->lintr.pin != 0) {
|
|
vm_reset_ptdev_intx_info(ctx, virt_bdf, ptdev->phys_bdf, dev->lintr.ioapic_irq, false);
|
|
}
|
|
|
|
if (ptdev)
|
|
phys_bdf = ptdev->phys_bdf;
|
|
|
|
if (ptdev->phys_bdf == PCI_BDF_GPU) {
|
|
vm_unmap_ptdev_mmio(ctx, 0, 2, 0, gpu_dsm_gpa, GPU_DSM_SIZE, gpu_dsm_hpa);
|
|
vm_unmap_ptdev_mmio(ctx, 0, 2, 0, gpu_opregion_gpa, GPU_OPREGION_SIZE, gpu_opregion_hpa);
|
|
}
|
|
|
|
pcidev.virt_bdf = PCI_BDF(dev->bus, dev->slot, dev->func);
|
|
pcidev.phys_bdf = ptdev->phys_bdf;
|
|
pciaccess_cleanup();
|
|
free(ptdev);
|
|
|
|
if (!is_rtvm) {
|
|
/* Let the HV to deassign the pt device for RTVM, In this case, the RTVM
|
|
* could still be alive if DM died.
|
|
*/
|
|
vm_deassign_pcidev(ctx, &pcidev);
|
|
}
|
|
if (!is_rtvm && phys_bdf) {
|
|
memset(reset_path, 0, sizeof(reset_path));
|
|
snprintf(reset_path, 40,
|
|
"/sys/bus/pci/devices/0000:%02x:%02x.%x/reset",
|
|
(phys_bdf >> 8) & 0xFF,
|
|
(phys_bdf >> 3) & 0x1F,
|
|
(phys_bdf & 0x7));
|
|
|
|
fd = open(reset_path, O_WRONLY);
|
|
if (fd >= 0) {
|
|
if (write(fd, "1", 1) < 0)
|
|
pr_warn("reset dev %x failed!\n",
|
|
phys_bdf);
|
|
close(fd);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* bind pin info for pass-through device */
|
|
static void
|
|
passthru_bind_irq(struct vmctx *ctx, struct pci_vdev *dev)
|
|
{
|
|
struct passthru_dev *ptdev = dev->arg;
|
|
uint16_t virt_bdf = PCI_BDF(dev->bus, dev->slot, dev->func);
|
|
|
|
/* No allocated virq indicates ptdev with MSI support, so no need to
|
|
* setup intx info as MSI is preferred over ioapic intr
|
|
*/
|
|
if (dev->lintr.pin == 0)
|
|
return;
|
|
|
|
pr_info("vm_set_ptdev_intx for %d:%d.%d, ",
|
|
dev->bus, dev->slot, dev->func);
|
|
pr_info("virt_pin=%d, phys_pin=%d, virt_bdf=0x%x, phys_bdf=0x%x.\n",
|
|
dev->lintr.ioapic_irq, ptdev->phys_pin,
|
|
virt_bdf, ptdev->phys_bdf);
|
|
|
|
vm_set_ptdev_intx_info(ctx, virt_bdf, ptdev->phys_bdf,
|
|
dev->lintr.ioapic_irq, ptdev->phys_pin, false);
|
|
}
|
|
|
|
static int
|
|
passthru_cfgread(struct vmctx *ctx, int vcpu, struct pci_vdev *dev,
|
|
int coff, int bytes, uint32_t *rv)
|
|
{
|
|
struct passthru_dev *ptdev = dev->arg;
|
|
|
|
if (ptdev->has_virt_pcicfg_regs && ptdev->has_virt_pcicfg_regs(coff))
|
|
*rv = pci_get_cfgdata32(dev, coff);
|
|
else
|
|
*rv = read_config(ptdev->phys_dev, coff, bytes);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
passthru_cfgwrite(struct vmctx *ctx, int vcpu, struct pci_vdev *dev,
|
|
int coff, int bytes, uint32_t val)
|
|
{
|
|
struct passthru_dev *ptdev = dev->arg;
|
|
|
|
if (!(ptdev->has_virt_pcicfg_regs && ptdev->has_virt_pcicfg_regs(coff)))
|
|
write_config(ptdev->phys_dev, coff, bytes, val);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
passthru_write(struct vmctx *ctx, int vcpu, struct pci_vdev *dev, int baridx,
|
|
uint64_t offset, int size, uint64_t value)
|
|
{
|
|
}
|
|
|
|
static uint64_t
|
|
passthru_read(struct vmctx *ctx, int vcpu, struct pci_vdev *dev, int baridx,
|
|
uint64_t offset, int size)
|
|
{
|
|
return ~0UL;
|
|
}
|
|
|
|
static void
|
|
write_dsdt_xdci(struct pci_vdev *dev)
|
|
{
|
|
pr_info("write virt-%x:%x.%x in dsdt for XDCI @ 00:15.1\n",
|
|
dev->bus,
|
|
dev->slot,
|
|
dev->func);
|
|
|
|
dsdt_line("");
|
|
dsdt_line("Device (XDCI)");
|
|
dsdt_line("{");
|
|
dsdt_line(" Name (_ADR, 0x%04X%04X)", dev->slot, dev->func);
|
|
dsdt_line(" Name (_DDN, \"Broxton XDCI controller\")");
|
|
dsdt_line(" Name (_STR, Unicode (\"Broxton XDCI controller\"))");
|
|
dsdt_line("}");
|
|
dsdt_line("");
|
|
}
|
|
|
|
static void
|
|
write_dsdt_hdac(struct pci_vdev *dev)
|
|
{
|
|
pr_info("write virt-%x:%x.%x in dsdt for HDAC @ 00:17.0\n",
|
|
dev->bus,
|
|
dev->slot,
|
|
dev->func);
|
|
|
|
/* Need prepare I2C # carefully for all passthrough devices */
|
|
dsdt_line("Device (I2C0)");
|
|
dsdt_line("{");
|
|
dsdt_line(" Name (_ADR, 0x%04X%04X)", dev->slot, dev->func);
|
|
dsdt_line(" Name (_DDN, \"Intel(R) I2C Controller #0\")");
|
|
dsdt_line(" Name (_UID, One) // _UID: Unique ID");
|
|
dsdt_line(" Name (LINK, \"\\\\_SB.PCI0.I2C0\")");
|
|
|
|
dsdt_line(" Name (RBUF, ResourceTemplate ()");
|
|
dsdt_line(" {");
|
|
dsdt_line(" })");
|
|
dsdt_line(" Name (IC4S, 0x00061A80)");
|
|
dsdt_line(" Name (_DSD, Package (0x02)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" ToUUID (\"daffd814-6eba-4d8c-8a91-bc9bbf4aa301\")"
|
|
" ,");
|
|
dsdt_line(" Package (0x01)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Package (0x02)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" \"clock-frequency\", ");
|
|
dsdt_line(" IC4S");
|
|
dsdt_line(" }");
|
|
dsdt_line(" }");
|
|
dsdt_line(" })");
|
|
dsdt_line(" Method (FMCN, 0, Serialized)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Name (PKG, Package (0x03)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" 0x64, ");
|
|
dsdt_line(" 0xD6, ");
|
|
dsdt_line(" 0x1C");
|
|
dsdt_line(" })");
|
|
dsdt_line(" Return (PKG)");
|
|
dsdt_line(" }");
|
|
dsdt_line("");
|
|
dsdt_line(" Method (FPCN, 0, Serialized)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Name (PKG, Package (0x03)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" 0x26, ");
|
|
dsdt_line(" 0x50, ");
|
|
dsdt_line(" 0x0C");
|
|
dsdt_line(" })");
|
|
dsdt_line(" Return (PKG)");
|
|
dsdt_line(" }");
|
|
dsdt_line("");
|
|
dsdt_line(" Method (HSCN, 0, Serialized)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Name (PKG, Package (0x03)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" 0x05, ");
|
|
dsdt_line(" 0x18, ");
|
|
dsdt_line(" 0x0C");
|
|
dsdt_line(" })");
|
|
dsdt_line(" Return (PKG)");
|
|
dsdt_line(" }");
|
|
dsdt_line("");
|
|
dsdt_line(" Method (SSCN, 0, Serialized)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Name (PKG, Package (0x03)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" 0x0244, ");
|
|
dsdt_line(" 0x02DA, ");
|
|
dsdt_line(" 0x1C");
|
|
dsdt_line(" })");
|
|
dsdt_line(" Return (PKG)");
|
|
dsdt_line(" }");
|
|
dsdt_line("");
|
|
dsdt_line(" Method (_CRS, 0, NotSerialized)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Return (RBUF)");
|
|
dsdt_line(" }");
|
|
|
|
dsdt_line(" Device (HDAC)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Name (_HID, \"INT34C3\") // _HID: Hardware ID");
|
|
dsdt_line(" Name (_CID, \"INT34C3\") // _CID: Compatible ID");
|
|
dsdt_line(" Name (_DDN, \"Intel(R) Smart Sound Technology "
|
|
"Audio Codec\") // _DDN: DOS Device Name");
|
|
dsdt_line(" Name (_UID, One) // _UID: Unique ID");
|
|
dsdt_line(" Method (_INI, 0, NotSerialized)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" }");
|
|
dsdt_line("");
|
|
dsdt_line(" Method (_CRS, 0, NotSerialized)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Name (SBFB, ResourceTemplate ()");
|
|
dsdt_line(" {");
|
|
dsdt_line(" I2cSerialBusV2 (0x006C, "
|
|
"ControllerInitiated, 0x00061A80,");
|
|
dsdt_line(" AddressingMode7Bit, "
|
|
"\"\\\\_SB.PCI0.I2C0\",");
|
|
dsdt_line(" 0x00, ResourceConsumer, , Exclusive,");
|
|
dsdt_line(" )");
|
|
dsdt_line(" })");
|
|
dsdt_line(" Name (SBFI, ResourceTemplate ()");
|
|
dsdt_line(" {");
|
|
dsdt_line(" })");
|
|
dsdt_line(" Return (ConcatenateResTemplate (SBFB, SBFI))");
|
|
dsdt_line(" }");
|
|
dsdt_line("");
|
|
dsdt_line(" Method (_STA, 0, NotSerialized) // _STA: Status");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Return (0x0F)");
|
|
dsdt_line(" }");
|
|
dsdt_line(" }");
|
|
dsdt_line("");
|
|
dsdt_line("}");
|
|
}
|
|
|
|
static void
|
|
write_dsdt_hdas(struct pci_vdev *dev)
|
|
{
|
|
pr_info("write virt-%x:%x.%x in dsdt for HDAS @ 00:e.0\n",
|
|
dev->bus,
|
|
dev->slot,
|
|
dev->func);
|
|
|
|
dsdt_line("Name (ADFM, 0x2A)");
|
|
dsdt_line("Name (ADPM, Zero)");
|
|
dsdt_line("Name (AG1L, Zero)");
|
|
dsdt_line("Name (AG1H, Zero)");
|
|
dsdt_line("Name (AG2L, Zero)");
|
|
dsdt_line("Name (AG2H, Zero)");
|
|
dsdt_line("Name (AG3L, Zero)");
|
|
dsdt_line("Name (AG3H, Zero)");
|
|
dsdt_line("Method (ADBG, 1, Serialized)");
|
|
dsdt_line("{");
|
|
dsdt_line(" Return (Zero)");
|
|
dsdt_line("}");
|
|
dsdt_line("Device (HDAS)");
|
|
dsdt_line("{");
|
|
dsdt_line(" Name (_ADR, 0x%04X%04X)", dev->slot, dev->func);
|
|
dsdt_line(" OperationRegion (HDAR, PCI_Config, Zero, 0x0100)");
|
|
dsdt_line(" Field (HDAR, ByteAcc, NoLock, Preserve)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" VDID, 32, ");
|
|
dsdt_line(" Offset (0x48), ");
|
|
dsdt_line(" , 6, ");
|
|
dsdt_line(" MBCG, 1, ");
|
|
dsdt_line(" Offset (0x54), ");
|
|
dsdt_line(" Offset (0x55), ");
|
|
dsdt_line(" PMEE, 1, ");
|
|
dsdt_line(" , 6, ");
|
|
dsdt_line(" PMES, 1");
|
|
dsdt_line(" }");
|
|
dsdt_line("");
|
|
dsdt_line(" Name (NBUF, ResourceTemplate ()");
|
|
dsdt_line(" {");
|
|
dsdt_line(" QWordMemory (ResourceConsumer, PosDecode, MinNotFixed,"
|
|
" MaxNotFixed, NonCacheable, ReadOnly,");
|
|
dsdt_line(" 0x0000000000000000, // Granularity");
|
|
dsdt_line(" 0x00000000000F2800, // Range Minimum");
|
|
dsdt_line(" 0x%08X, // Range Maximum",
|
|
0xF2800 + audio_nhlt_len -1);
|
|
dsdt_line(" 0x0000000000000000, // Translation Offset");
|
|
dsdt_line(" 0x%08X, // Length", audio_nhlt_len);
|
|
dsdt_line(" ,, _Y06, AddressRangeACPI, TypeStatic)");
|
|
dsdt_line(" })");
|
|
dsdt_line(" Name (_S0W, 0x03) // _S0W: S0 Device Wake State");
|
|
dsdt_line(" Method (_DSW, 3, NotSerialized)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" PMEE = Arg0");
|
|
dsdt_line(" }");
|
|
dsdt_line("");
|
|
dsdt_line(" Name (_PRW, Package (0x02)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" 0x0E, ");
|
|
dsdt_line(" 0x03");
|
|
dsdt_line(" })");
|
|
dsdt_line(" Method (_PS0, 0, Serialized)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" ADBG (\"HD-A Ctrlr D0\")");
|
|
dsdt_line(" }");
|
|
dsdt_line("");
|
|
dsdt_line(" Method (_PS3, 0, Serialized)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" ADBG (\"HD-A Ctrlr D3\")");
|
|
dsdt_line(" }");
|
|
dsdt_line("");
|
|
dsdt_line(" Method (_INI, 0, NotSerialized)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" ADBG (\"HDAS _INI\")");
|
|
dsdt_line(" }");
|
|
dsdt_line("");
|
|
dsdt_line(" Method (_DSM, 4, Serialized)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" ADBG (\"HDAS _DSM\")");
|
|
dsdt_line(" If ((Arg0 == ToUUID ("
|
|
"\"a69f886e-6ceb-4594-a41f-7b5dce24c553\")))");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Switch (ToInteger (Arg2))");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Case (Zero)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Return (Buffer (One)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" 0x0F");
|
|
dsdt_line(" })");
|
|
dsdt_line(" }");
|
|
dsdt_line(" Case (One)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" ADBG (\"_DSM Fun 1 NHLT\")");
|
|
dsdt_line(" Return (NBUF)");
|
|
dsdt_line(" }");
|
|
dsdt_line(" Case (0x02)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" ADBG (\"_DSM Fun 2 FMSK\")");
|
|
dsdt_line(" Return (ADFM)");
|
|
dsdt_line(" }");
|
|
dsdt_line(" Case (0x03)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" ADBG (\"_DSM Fun 3 PPMS\")");
|
|
dsdt_line(" If ((Arg3 == ToUUID ("
|
|
"\"b489c2de-0f96-42e1-8a2d-c25b5091ee49\")))");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Return ((ADPM & One))");
|
|
dsdt_line(" }");
|
|
dsdt_line("");
|
|
dsdt_line(" If ((Arg3 == ToUUID ("
|
|
"\"e1284052-8664-4fe4-a353-3878f72704c3\")))");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Return ((ADPM & 0x02))");
|
|
dsdt_line(" }");
|
|
dsdt_line("");
|
|
dsdt_line(" If ((Arg3 == ToUUID ("
|
|
"\"7c708106-3aff-40fe-88be-8c999b3f7445\")))");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Return ((ADPM & 0x04))");
|
|
dsdt_line(" }");
|
|
dsdt_line("");
|
|
dsdt_line(" If ((Arg3 == ToUUID ("
|
|
"\"e0e018a8-3550-4b54-a8d0-a8e05d0fcba2\")))");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Return ((ADPM & 0x08))");
|
|
dsdt_line(" }");
|
|
dsdt_line("");
|
|
dsdt_line(" If ((Arg3 == ToUUID ("
|
|
"\"202badb5-8870-4290-b536-f2380c63f55d\")))");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Return ((ADPM & 0x10))");
|
|
dsdt_line(" }");
|
|
dsdt_line("");
|
|
dsdt_line(" If ((Arg3 == ToUUID ("
|
|
"\"eb3fea76-394b-495d-a14d-8425092d5cb7\")))");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Return ((ADPM & 0x20))");
|
|
dsdt_line(" }");
|
|
dsdt_line("");
|
|
dsdt_line(" If ((Arg3 == ToUUID ("
|
|
"\"f1c69181-329a-45f0-8eef-d8bddf81e036\")))");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Return ((ADPM & 0x40))");
|
|
dsdt_line(" }");
|
|
dsdt_line("");
|
|
dsdt_line(" If ((Arg3 == ToUUID ("
|
|
"\"b3573eff-6441-4a75-91f7-4281eec4597d\")))");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Return ((ADPM & 0x80))");
|
|
dsdt_line(" }");
|
|
dsdt_line("");
|
|
dsdt_line(" If ((Arg3 == ToUUID ("
|
|
"\"ec774fa9-28d3-424a-90e4-69f984f1eeb7\")))");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Return ((ADPM & 0x0100))");
|
|
dsdt_line(" }");
|
|
dsdt_line("");
|
|
dsdt_line(" If ((Arg3 == ToUUID ("
|
|
"\"f101fef0-ff5a-4ad4-8710-43592a6f7948\")))");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Return ((ADPM & 0x0200))");
|
|
dsdt_line(" }");
|
|
dsdt_line("");
|
|
dsdt_line(" If ((Arg3 == ToUUID ("
|
|
"\"f3578986-4400-4adf-ae7e-cd433cd3f26e\")))");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Return ((ADPM & 0x0400))");
|
|
dsdt_line(" }");
|
|
dsdt_line("");
|
|
dsdt_line(" If ((Arg3 == ToUUID ("
|
|
"\"13b5e4d7-a91a-4059-8290-605b01ccb650\")))");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Return ((ADPM & 0x0800))");
|
|
dsdt_line(" }");
|
|
dsdt_line("");
|
|
dsdt_line(" If ((Arg3 == ACCG (AG1L, AG1H)))");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Return ((ADPM & 0x20000000))");
|
|
dsdt_line(" }");
|
|
dsdt_line("");
|
|
dsdt_line(" If ((Arg3 == ACCG (AG2L, AG2H)))");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Return ((ADPM & 0x40000000))");
|
|
dsdt_line(" }");
|
|
dsdt_line("");
|
|
dsdt_line(" If ((Arg3 == ACCG (AG3L, AG3H)))");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Return ((ADPM & 0x80000000))");
|
|
dsdt_line(" }");
|
|
dsdt_line("");
|
|
dsdt_line(" Return (Zero)");
|
|
dsdt_line(" }");
|
|
dsdt_line(" Default");
|
|
dsdt_line(" {");
|
|
dsdt_line(" ADBG (\"_DSM Fun NOK\")");
|
|
dsdt_line(" Return (Buffer (One)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" 0x00");
|
|
dsdt_line(" })");
|
|
dsdt_line(" }");
|
|
dsdt_line("");
|
|
dsdt_line(" }");
|
|
dsdt_line(" }");
|
|
dsdt_line("");
|
|
dsdt_line(" ADBG (\"_DSM UUID NOK\")");
|
|
dsdt_line(" Return (Buffer (One)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" 0x00");
|
|
dsdt_line(" })");
|
|
dsdt_line(" }");
|
|
dsdt_line("");
|
|
dsdt_line(" Method (ACCG, 2, Serialized)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Name (GBUF, Buffer (0x10){})");
|
|
dsdt_line(" Concatenate (Arg0, Arg1, GBUF)");
|
|
dsdt_line(" Return (GBUF) /* \\_SB_.PCI0.HDAS.ACCG.GBUF */");
|
|
dsdt_line(" }");
|
|
dsdt_line("}");
|
|
}
|
|
|
|
static void
|
|
write_dsdt_ipu_i2c(struct pci_vdev *dev)
|
|
{
|
|
pr_info("write virt-%x:%x.%x in dsdt for ipu's i2c-bus @ 00:16.0\n",
|
|
dev->bus, dev->slot, dev->func);
|
|
|
|
/* physical I2C 0:16.0 */
|
|
dsdt_line("Device (I2C1)");
|
|
dsdt_line("{");
|
|
dsdt_line(" Name (_ADR, 0x%04X%04X)", dev->slot, dev->func);
|
|
dsdt_line(" Name (_DDN, \"Intel(R) I2C Controller #1\")");
|
|
dsdt_line(" Name (_UID, One)");
|
|
dsdt_line(" Name (LINK, \"\\\\_SB.PCI0.I2C1\")");
|
|
dsdt_line(" Name (RBUF, ResourceTemplate ()");
|
|
dsdt_line(" {");
|
|
dsdt_line(" })");
|
|
dsdt_line(" Name (IC0S, 0x00061A80)");
|
|
dsdt_line(" Name (_DSD, Package (0x02)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" ToUUID (\"daffd814-6eba-4d8c-8a91-bc9bbf4aa301\")"
|
|
" ,");
|
|
dsdt_line(" Package (0x01)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Package (0x02)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" \"clock-frequency\", ");
|
|
dsdt_line(" IC0S");
|
|
dsdt_line(" }");
|
|
dsdt_line(" }");
|
|
dsdt_line(" })");
|
|
|
|
dsdt_line(" Method (FMCN, 0, Serialized)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Name (PKG, Package (0x03)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" 0x64, ");
|
|
dsdt_line(" 0xD6, ");
|
|
dsdt_line(" 0x1C");
|
|
dsdt_line(" })");
|
|
dsdt_line(" Return (PKG)");
|
|
dsdt_line(" }");
|
|
dsdt_line("");
|
|
|
|
dsdt_line(" Method (FPCN, 0, Serialized)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Name (PKG, Package (0x03)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" 0x26, ");
|
|
dsdt_line(" 0x50, ");
|
|
dsdt_line(" 0x0C");
|
|
dsdt_line(" })");
|
|
dsdt_line(" Return (PKG)");
|
|
dsdt_line(" }");
|
|
dsdt_line("");
|
|
|
|
dsdt_line(" Method (HSCN, 0, Serialized)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Name (PKG, Package (0x03)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" 0x05, ");
|
|
dsdt_line(" 0x18, ");
|
|
dsdt_line(" 0x0C");
|
|
dsdt_line(" })");
|
|
dsdt_line(" Return (PKG)");
|
|
dsdt_line(" }");
|
|
dsdt_line("");
|
|
|
|
dsdt_line(" Method (SSCN, 0, Serialized)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Name (PKG, Package (0x03)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" 0x0244, ");
|
|
dsdt_line(" 0x02DA, ");
|
|
dsdt_line(" 0x1C");
|
|
dsdt_line(" })");
|
|
dsdt_line(" Return (PKG)");
|
|
dsdt_line(" }");
|
|
dsdt_line("");
|
|
|
|
dsdt_line(" Method (_CRS, 0, NotSerialized)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Return (RBUF)");
|
|
dsdt_line(" }");
|
|
dsdt_line("");
|
|
|
|
/* CAM1 */
|
|
dsdt_line(" Device (CAM1)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Name (_ADR, Zero) // _ADR: Address");
|
|
dsdt_line(" Name (_HID, \"ADV7481A\") // _HID: Hardware ID");
|
|
dsdt_line(" Name (_CID, \"ADV7481A\") // _CID: Compatible ID");
|
|
dsdt_line(" Name (_UID, One) // _UID: Unique ID");
|
|
|
|
dsdt_line(" Method (_CRS, 0, Serialized)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Name (SBUF, ResourceTemplate ()");
|
|
dsdt_line(" {");
|
|
dsdt_line(" GpioIo (Exclusive, PullDefault, 0x0000, "
|
|
"0x0000, IoRestrictionInputOnly,");
|
|
dsdt_line(" \"\\\\_SB.GPO0\", 0x00, "
|
|
"ResourceConsumer, ,");
|
|
dsdt_line(" )");
|
|
dsdt_line(" { // Pin list");
|
|
dsdt_line(" 0x001E");
|
|
dsdt_line(" }");
|
|
dsdt_line(" I2cSerialBusV2 (0x0070, "
|
|
"ControllerInitiated, 0x00061A80,");
|
|
dsdt_line(" AddressingMode7Bit, "
|
|
"\"\\\\_SB.PCI0.I2C1\",");
|
|
dsdt_line(" 0x00, ResourceConsumer, , Exclusive,");
|
|
dsdt_line(" )");
|
|
dsdt_line(" })");
|
|
dsdt_line(" Return (SBUF)");
|
|
dsdt_line(" }");
|
|
|
|
dsdt_line(" Method (_DSM, 4, NotSerialized)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" If ((Arg0 == ToUUID ("
|
|
"\"377ba76a-f390-4aff-ab38-9b1bf33a3015\")))");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Return (\"ADV7481A\")");
|
|
dsdt_line(" }");
|
|
dsdt_line("");
|
|
dsdt_line(" If ((Arg0 == ToUUID ("
|
|
"\"ea3b7bd8-e09b-4239-ad6e-ed525f3f26ab\")))");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Return (0x40)");
|
|
dsdt_line(" }");
|
|
dsdt_line("");
|
|
dsdt_line(" If ((Arg0 == ToUUID ("
|
|
"\"8dbe2651-70c1-4c6f-ac87-a37cb46e4af6\")))");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Return (0xFF)");
|
|
dsdt_line(" }");
|
|
dsdt_line("");
|
|
dsdt_line(" If ((Arg0 == ToUUID ("
|
|
"\"26257549-9271-4ca4-bb43-c4899d5a4881\")))");
|
|
dsdt_line(" {");
|
|
dsdt_line(" If (Arg2 == One)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Return (0x02)");
|
|
dsdt_line(" }");
|
|
dsdt_line(" If (Arg2 == 0x02)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Return (0x02001000)");
|
|
dsdt_line(" }");
|
|
dsdt_line(" If (Arg2 == 0x03)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Return (0x02000E01)");
|
|
dsdt_line(" }");
|
|
dsdt_line(" }");
|
|
dsdt_line(" Return (Zero)");
|
|
dsdt_line(" }");
|
|
dsdt_line(" }");
|
|
dsdt_line("");
|
|
|
|
/* CAM2 */
|
|
dsdt_line(" Device (CAM2)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Name (_ADR, Zero) // _ADR: Address");
|
|
dsdt_line(" Name (_HID, \"ADV7481B\") // _HID: Hardware ID");
|
|
dsdt_line(" Name (_CID, \"ADV7481B\") // _CID: Compatible ID");
|
|
dsdt_line(" Name (_UID, One) // _UID: Unique ID");
|
|
|
|
dsdt_line(" Method (_CRS, 0, Serialized)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Name (SBUF, ResourceTemplate ()");
|
|
dsdt_line(" {");
|
|
dsdt_line(" GpioIo (Exclusive, PullDefault, 0x0000, "
|
|
"0x0000, IoRestrictionInputOnly,");
|
|
dsdt_line(" \"\\\\_SB.GPO0\", 0x00, "
|
|
"ResourceConsumer, ,");
|
|
dsdt_line(" )");
|
|
dsdt_line(" { // Pin list");
|
|
dsdt_line(" 0x001E");
|
|
dsdt_line(" }");
|
|
dsdt_line(" I2cSerialBusV2 (0x0071, "
|
|
"ControllerInitiated, 0x00061A80,");
|
|
dsdt_line(" AddressingMode7Bit, "
|
|
"\"\\\\_SB.PCI0.I2C1\",");
|
|
dsdt_line(" 0x00, ResourceConsumer, , Exclusive,");
|
|
dsdt_line(" )");
|
|
dsdt_line(" })");
|
|
dsdt_line(" Return (SBUF)");
|
|
dsdt_line(" }");
|
|
|
|
dsdt_line(" Method (_DSM, 4, NotSerialized) ");
|
|
dsdt_line(" {");
|
|
dsdt_line(" If ((Arg0 == ToUUID ("
|
|
"\"377ba76a-f390-4aff-ab38-9b1bf33a3015\")))");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Return (\"ADV7481B\")");
|
|
dsdt_line(" }");
|
|
dsdt_line("");
|
|
dsdt_line(" If ((Arg0 == ToUUID ("
|
|
"\"ea3b7bd8-e09b-4239-ad6e-ed525f3f26ab\")))");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Return (0x14)");
|
|
dsdt_line(" }");
|
|
dsdt_line("");
|
|
dsdt_line(" If ((Arg0 == ToUUID ("
|
|
"\"8dbe2651-70c1-4c6f-ac87-a37cb46e4af6\")))");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Return (0xFF)");
|
|
dsdt_line(" }");
|
|
dsdt_line("");
|
|
dsdt_line(" If ((Arg0 == ToUUID ("
|
|
"\"26257549-9271-4ca4-bb43-c4899d5a4881\")))");
|
|
dsdt_line(" {");
|
|
dsdt_line(" If (Arg2 == One)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Return (0x02)");
|
|
dsdt_line(" }");
|
|
dsdt_line(" If (Arg2 == 0x02)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Return (0x02001000)");
|
|
dsdt_line(" }");
|
|
dsdt_line(" If (Arg2 == 0x03)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Return (0x02000E01)");
|
|
dsdt_line(" }");
|
|
dsdt_line(" }");
|
|
dsdt_line(" Return (Zero)");
|
|
dsdt_line(" }");
|
|
dsdt_line(" }");
|
|
dsdt_line("");
|
|
|
|
dsdt_line("}");
|
|
}
|
|
|
|
static void
|
|
write_dsdt_urt1(struct pci_vdev *dev)
|
|
{
|
|
pr_info("write virt-%x:%x.%x in dsdt for URT1 @ 00:18.0\n",
|
|
dev->bus,
|
|
dev->slot,
|
|
dev->func);
|
|
dsdt_line("Device (URT1)");
|
|
dsdt_line("{");
|
|
dsdt_line(" Name (_ADR, 0x%04X%04X)", dev->slot, dev->func);
|
|
dsdt_line(" Name (_DDN, \"Intel(R) HS-UART Controller #1\")");
|
|
dsdt_line(" Name (_UID, One)");
|
|
dsdt_line(" Name (RBUF, ResourceTemplate ()");
|
|
dsdt_line(" {");
|
|
dsdt_line(" })");
|
|
dsdt_line(" Method (_CRS, 0, NotSerialized)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Return (RBUF)");
|
|
dsdt_line(" }");
|
|
dsdt_line("}");
|
|
}
|
|
|
|
static void
|
|
write_dsdt_sdc(struct pci_vdev *dev)
|
|
{
|
|
pr_info("write SDC-%x:%x.%x in dsdt for SDC @ 00:1b.0\n",
|
|
dev->bus,
|
|
dev->slot,
|
|
dev->func);
|
|
dsdt_line("Device (SDC)");
|
|
dsdt_line("{");
|
|
dsdt_line(" Name (_ADR, 0x%04X%04X)", dev->slot, dev->func);
|
|
dsdt_line(" Name (_DDN, \"Intel(R) SD Card Controller\")");
|
|
dsdt_line(" Name (_UID, One)");
|
|
dsdt_line(" Method (_CRS, 0, NotSerialized)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Name (RBUF, ResourceTemplate ()");
|
|
dsdt_line(" {");
|
|
dsdt_line(" GpioInt (Edge, ActiveBoth, SharedAndWake, "
|
|
"PullNone, 0, ");
|
|
dsdt_line(" \"\\\\_SB_.PCI0.AGPI\", 0, ResourceConsumer, ,");
|
|
dsdt_line(" )");
|
|
dsdt_line(" { // Pin list");
|
|
dsdt_line(" 0");
|
|
dsdt_line(" }");
|
|
dsdt_line(" GpioIo (Exclusive, PullDefault, 0x0000, "
|
|
"0x0000, IoRestrictionInputOnly,");
|
|
dsdt_line(" \"\\\\_SB._PCI0.AGPI\", 0x00, "
|
|
"ResourceConsumer, ,");
|
|
dsdt_line(" )");
|
|
dsdt_line(" { // Pin list");
|
|
dsdt_line(" 0");
|
|
dsdt_line(" }");
|
|
dsdt_line(" })");
|
|
dsdt_line(" Return (RBUF)");
|
|
dsdt_line(" }");
|
|
dsdt_line("}");
|
|
}
|
|
|
|
static void
|
|
write_dsdt_tsn(struct pci_vdev *dev, uint16_t device)
|
|
{
|
|
char device_name[4];
|
|
uint16_t pcs_id;
|
|
|
|
if (device == 0x4b32) {
|
|
strncpy(device_name, "GTSN", 4);
|
|
pcs_id = 0;
|
|
} else if (device == 0x4ba0) {
|
|
strncpy(device_name, "OTN0", 4);
|
|
pcs_id = 1;
|
|
} else if (device == 0x4bb0) {
|
|
strncpy(device_name, "OTN1", 4);
|
|
pcs_id = 2;
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
pr_info("write TSN-%x:%x.%x in dsdt for TSN-%d\n", dev->bus, dev->slot, dev->func, pcs_id);
|
|
|
|
dsdt_line("");
|
|
dsdt_line("Device (%.4s)", device_name);
|
|
dsdt_line("{");
|
|
dsdt_line(" Name (_ADR, 0x%04X%04X)", dev->slot, dev->func); // _ADR: Address
|
|
dsdt_line(" OperationRegion (TSRT, PCI_Config, Zero, 0x0100)");
|
|
dsdt_line(" Field (TSRT, AnyAcc, NoLock, Preserve)");
|
|
dsdt_line(" {");
|
|
dsdt_line(" DVID, 16,");
|
|
dsdt_line(" Offset (0x10),");
|
|
dsdt_line(" TADL, 32,");
|
|
dsdt_line(" TADH, 32");
|
|
dsdt_line(" }");
|
|
dsdt_line("}");
|
|
dsdt_line("");
|
|
dsdt_line("Scope (_SB)");
|
|
dsdt_line("{");
|
|
dsdt_line(" Device (PCS%01X)", pcs_id);
|
|
dsdt_line(" {");
|
|
dsdt_line(" Name (_HID, \"INTC1033\")"); // _HID: Hardware ID
|
|
dsdt_line(" Name (_UID, Zero)"); // _UID: Unique ID
|
|
dsdt_line(" Method (_STA, 0, NotSerialized)"); // _STA: Status
|
|
dsdt_line(" {");
|
|
dsdt_line("");
|
|
dsdt_line(" Return (0x0F)");
|
|
dsdt_line(" }");
|
|
dsdt_line("");
|
|
dsdt_line(" Method (_CRS, 0, Serialized)"); // _CRS: Current Resource Settings
|
|
dsdt_line(" {");
|
|
dsdt_line(" Name (PCSR, ResourceTemplate ()");
|
|
dsdt_line(" {");
|
|
dsdt_line(" Memory32Fixed (ReadWrite,");
|
|
dsdt_line(" 0x00000000,"); // Address Base
|
|
dsdt_line(" 0x00000004,"); // Address Length
|
|
dsdt_line(" _Y55)");
|
|
dsdt_line(" Memory32Fixed (ReadWrite,");
|
|
dsdt_line(" 0x00000000,"); // Address Base
|
|
dsdt_line(" 0x00000004,"); // Address Length
|
|
dsdt_line(" _Y56)");
|
|
dsdt_line(" })");
|
|
dsdt_line(" CreateDWordField (PCSR, \\_SB.PCS%01X._CRS._Y55._BAS, MAL0)", pcs_id); // _BAS: Base Address
|
|
dsdt_line(" MAL0 = ((^^PCI0.%.4s.TADL & 0xFFFFF000) + 0x0200)", device_name);
|
|
dsdt_line(" CreateDWordField (PCSR, \\_SB.PCS%01X._CRS._Y56._BAS, MDL0)", pcs_id); // _BAS: Base Address
|
|
dsdt_line(" MDL0 = ((^^PCI0.%.4s.TADL & 0xFFFFF000) + 0x0204)", device_name);
|
|
dsdt_line(" Return (PCSR)"); /* \_SB_.PCS0._CRS.PCSR */
|
|
dsdt_line(" }");
|
|
dsdt_line(" }");
|
|
dsdt_line("}");
|
|
dsdt_line("");
|
|
}
|
|
|
|
static void
|
|
passthru_write_dsdt(struct pci_vdev *dev)
|
|
{
|
|
uint16_t vendor = 0, device = 0;
|
|
|
|
vendor = pci_get_cfgdata16(dev, PCIR_VENDOR);
|
|
|
|
if (vendor != 0x8086)
|
|
return;
|
|
|
|
device = pci_get_cfgdata16(dev, PCIR_DEVICE);
|
|
|
|
/* Provides ACPI extra info */
|
|
if (device == 0x5aaa)
|
|
/* XDCI @ 00:15.1 to enable ADB */
|
|
write_dsdt_xdci(dev);
|
|
else if (device == 0x5ab4)
|
|
/* HDAC @ 00:17.0 as codec */
|
|
write_dsdt_hdac(dev);
|
|
else if (device == 0x5a98)
|
|
/* HDAS @ 00:e.0 */
|
|
write_dsdt_hdas(dev);
|
|
else if (device == 0x5aac)
|
|
/* i2c @ 00:16.0 for ipu */
|
|
write_dsdt_ipu_i2c(dev);
|
|
else if (device == 0x5abc)
|
|
/* URT1 @ 00:18.0 for bluetooth*/
|
|
write_dsdt_urt1(dev);
|
|
else if (device == 0x5aca)
|
|
/* SDC @ 00:1b.0 */
|
|
write_dsdt_sdc(dev);
|
|
else if ((device == 0x4b32) || (device == 0x4ba0) || (device == 0x4bb0))
|
|
write_dsdt_tsn(dev, device);
|
|
}
|
|
|
|
struct pci_vdev_ops passthru = {
|
|
.class_name = "passthru",
|
|
.vdev_init = passthru_init,
|
|
.vdev_deinit = passthru_deinit,
|
|
.vdev_cfgwrite = passthru_cfgwrite,
|
|
.vdev_cfgread = passthru_cfgread,
|
|
.vdev_barwrite = passthru_write,
|
|
.vdev_barread = passthru_read,
|
|
.vdev_phys_access = passthru_bind_irq,
|
|
.vdev_write_dsdt = passthru_write_dsdt,
|
|
};
|
|
DEFINE_PCI_DEVTYPE(passthru);
|