From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from [140.186.70.92] (port=34114 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1PXHZE-00070B-3I for qemu-devel@nongnu.org; Mon, 27 Dec 2010 13:13:12 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1PXHZA-0006r7-7O for qemu-devel@nongnu.org; Mon, 27 Dec 2010 13:13:07 -0500 Received: from mail-gy0-f173.google.com ([209.85.160.173]:42219) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1PXHZ9-0006qL-V3 for qemu-devel@nongnu.org; Mon, 27 Dec 2010 13:13:04 -0500 Received: by gye5 with SMTP id 5so4496602gye.4 for ; Mon, 27 Dec 2010 10:13:02 -0800 (PST) From: "Adnan Khaleel" Message-ID: <20101227181256.287949dc@shadowfax.no-ip.com> Date: Mon, 27 Dec 2010 12:12:56 -0600 MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="-----------6f0d8078e6b4b0c79b162ca81aeed552" Subject: [Qemu-devel] Re: PCIe Transaction handling in Qemu Reply-To: adnan@khaleel.us List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Isaku Yamahata , Paul Brook Cc: qemu-devel@nongnu.org This is a multi-part message in MIME format. -------------6f0d8078e6b4b0c79b162ca81aeed552 Content-Type: multipart/alternative; boundary="-----------a7c7e0c125219f2ad44679c720b7238e" -------------a7c7e0c125219f2ad44679c720b7238e Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable =20 Yamahata and Paul, thank you very much for your responses. I have some f= ollowup questions below. Thanks for all your assistance! Adnan > I have a question regarding how Qemu PCIe devices handle Config = Transactions vs > Memory Transactions (assuming the PCI device is setup to act > as PCI=5FBASE=5FADDRESS=5FSPACE=5FMEMORY). >=20 > I'm using portions of hw/cirrus=5Fvga.c to make my point, =20 If you can send out what you have instead of mimicked example, it would help to figure out what you are trying to do. =20 I was trying to keep things simple with common code that was well establ= ished inside Qemu. I've attached the code from my PCIe device to help yo= u better understand what I'm trying to do. I'm using Qemu to drive a PCIe device model. Here is a diagrammatic repr= esentation =5F=5F=5F=5F=5F=5F =5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F= =5F=5F=5F =5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F= =5F Qemu |<-->|PCIe Model Wrapper |<----->| PCIe Device Model | =5F=5F=5F=5F=5F=5F| |=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F= =5F=5F=5F| |=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F= =5F| The PCIe Device model is a complete GPU model that communicates via a si= mulated PCIe interface i.e. the model represents a PCIe card that would = plug into a PCIe slot and expects to see PCIe transactions to drive it. = In other words, the PCIe Device model thinks its connected to a PCI-Brid= ge so I have to mimic this partially with the PCIe Model wrapper. It is = important that you understand this since its very central to the issues = I'm trying to better comprehend. I don't have the source code to the dev= ice model, hence my many challenges. I've written the PCIe model wrapper (the attached file), this wrapper ac= ts as a proxy for the Device Model and is what Qemu "sees" as an PCI end= point. The PCIe Model Wrapper is modelled as a Qemu PCIe device and incl= udes PCI configuration space registers, however the TRUE PCI config regi= sters are contained with the PCIe Device Model.=20 So in a nutshell this is what I'm trying to do:=20 - When the Guest OS inside Qemu does a PCIe config read/write, the PCIe = model wrapper has to intercept that call, construct a valid PCIe config = transaction and send it to the PCIe device model.=20 - Similarly for a PCIe MMIO transaction i.e, the wrapper has to construc= t a PCIe transaction and send it to the device model. I hope this puts into perspective why I was asking the questions about h= ow I can definitively identify if a request is a config request or if it= s a MMIO request because I need to synthesize the appropriate PCIe trans= actions to send to the Model. > I have some questions about PCIe operations sssuming the device has MM= IO > handlers involved (as shown above). > 1. Will all PCIe config operations ALWAYS use the installed config h= andlers=3F Or > can PCIe config operations use the MMIO handlers=3F =20 MMIO on MMCONFIG area are routed to write/read config handler. On the other hand MMIO on memory BAR is routed to mmio hanlder you pic= tured. NOTE: the upstream qemu lacks q35 chipset support, so guest can NOT do MMIO on MMCONFIG area. =20 I am using the q35 chipset that you (Yamahata) have been working on. So = does that mean that guests OS with the qemu with q35 can only access the= legacy PCI config space (256 bytes) and not the full PCIe 4k config spa= ce=3F The reason I ask is because of an AMD document I found http://developer.amd.com/Assets/pci%20-%20pci%20express%20configuration%= 20space%20access.pdf Here is the relevant text: 3.3 MMIO access with different Linux Kernel versions Support for MMIO ac= cess for PCI configuration space depends on the Linux Kernel version and= configuration, and the existence of an MCFG ACPI table. IO access to PC= I configuration space is always possible and will be used if MMIO access= is not available. To access extended configuration space (between byte = 256 and 4095) MMIO access is required. : Note: In both cases Linux supports the IO access method as a fallback if= MMIO access is not possible (e.g. if MCFG ACPI table is missing).=20 A kernel (with version prior to and including 2.6.25) with enabled MMIO = access method is able to do MMIO access if and only if the BIOS provides= a valid MCFG ACPI table and if the configuration space is "E820-reserve= d". If these requirements are not met, IO access is used and the kernel = logs an error message like this PCI: BIOS Bug: MCFG area at e0000000 is = not E820-reserved PCI: Not using MMCONFIG. PCI: Using configuration type= 1 Beginning with kernel version 2.6.25 Linux always uses the IO access = method to access configuration space below byte 256. Thus MMIO access is= used only for extended configuration space. > 2. Assuming that both PCI config and MMIO operations can use the MMI= O handlers, > is there any way I can identify if a transaction is a config or a me= mory > transaction=3F Here is a code snippet where I register the config handlers: static PCIDeviceInfo pcie=5Fmsix=5Finfo =3D { .qdev.name =3D PCIE=5FMSIX=5FDEVICE, .qdev.desc =3D "PCIE MSIX device template", .qdev.size =3D sizeof(PCIE=5FMSIX=5FDEVState), .qdev.reset =3D pcie=5Fmsix=5Freset, .qdev.vmsd =3D &vmstate=5Fpcie=5Fmsix, .is=5Fexpress =3D 1, .config=5Fread =3D pcie=5Fmsix=5Fread=5Fconfig, .config=5Fwrite =3D pcie=5Fmsix=5Fwrite=5Fconfig, .init =3D pcie=5Fmsix=5Finitfn, .exit =3D pcie=5Fmsix=5Fexitfn, .qdev.props =3D (Property[]) { DEFINE=5FPROP=5FUINT32("vectors", PCIE=5FMSIX=5FDEVState, vector= s, PCIE=5FMSIX=5FMSI=5FNR=5FVECTOR), =20 DEFINE=5FPROP=5FUINT16("aer=5Flog=5Fmax", PCIESlot, port.br.dev.aer=5Flog.log=5Fmax, PCIE=5FAER=5FLOG=5FMAX=5FDEFAULT), DEFINE=5FPROP=5FEND=5FOF=5FLIST(), } }; Here is a code snippet where I register the mmio handlers: static CPUWriteMemoryFunc * const pcie=5Fmsix=5Fmem=5Fwrite=5Ffn[] =3D { pcie=5Fmsix=5Fmem=5Fwriteb, pcie=5Fmsix=5Fmem=5Fwritew, pcie=5Fmsix= =5Fmem=5Fwritel, pcie=5Fmsix=5Fmem=5Fwrited }; static CPUReadMemoryFunc * const pcie=5Fmsix=5Fmem=5Fread=5Ffn[] =3D { pcie=5Fmsix=5Fmem=5Freadb, pcie=5Fmsix=5Fmem=5Freadw, pcie=5Fmsix=5F= mem=5Freadl, pcie=5Fmsix=5Fmem=5Freadd }; static void=20 pcie=5Fmsix=5Fmem=5Fmap(PCIDevice *dev, int region=5Fnum,=20 pcibus=5Ft addr, pcibus=5Ft size, int type) { uint32=5Ft msix=5Fmem=5Fbar =3D 0; PCIE=5FMSIX=5FDEVState *d =3D DO=5FUPCAST(PCIE=5FMSIX=5FDEVState, de= v, dev); cpu=5Fregister=5Fphysical=5Fmemory(addr, BAR=5FRegions[msix=5Fmem=5F= bar][0], d->mmio=5Findex); } Which I register via the following call in the pcie=5Fmsix=5Finitfn(PCID= evice *pci=5Fdev) function pci=5Fregister=5Fbar(&d->dev, msix=5Fmem=5Fbar, BAR=5FRegions[msix=5Fmem= =5Fbar][0], BAR=5FRegions[msix=5Fmem=5Fbar][1], pcie=5Fmsix=5Fmem=5Fmap)= ; So are my following assumption true then for my PCIe device i.e the wrap= per=3F All config requests WILL be handled by the config handlers and, All MMIO requests will be handled by the mmio handlers (given that the q= 35 model does not support MMIO on MMCONFIG) =20 > 3.a. What address is passed on the MMIO handlers for config and MMIO > operations=3F From pci=5Fdata=5Fwrite in pci=5Fhost.c, it appears th= at config > operations send only the offset into the config region. I couldn't d= etermine > what address is passed for MMIO operations. > b. Is it an offset from the BAR for MMIO operations=3F > c. How do I get the full physical address=3F > d. What address does a PCIe device expect to see - physical or of= fset for=3F > e. Is there anyway I can find out what the bus and device numbers= are once > inside the config and MMIO handlers=3F i.e once the execution has re= ached > the pci=5Fcirrus=5Fwrite=5Fconfig() or cirrus=5Fvga=5Fmem=5Freadb(..= ) from the code above=3F =20 offset in configuration space of each pcie function is passed to write/read config handler physical address is passed to mmio handler of memory BAR. When I examine the address on calls to the PCIe Device Wrapper config ha= ndlers, they start at 0x0 so they clearly are offsets. However, I also s= ee addresses from 0x0 in the MMIO handlers. Paul's response indicated th= at they were offsets so I'm inclined to believe that the address is an o= ffset from the start of the BAR. So let me ask my question again - when = I'm synthesizing the PCIe transaction to send to the PCIe device model, = do I have to give it a full address i.e. bus,dev,fn for config transacti= ons and full physical address for MMIO transactions=3F --=20 yamahata =20 -------------a7c7e0c125219f2ad44679c720b7238e Content-Type: text/html; charset="us-ascii" Content-Transfer-Encoding: quoted-printable =20 =20
Yamahata and Paul, thank you very much for your respon= ses. I have some followup questions below.

Thanks for all your assistance!

Adnan =
> I have a qu= estion regarding how Qemu PCIe devices handle Config Transactions vs
> Memory Transactions (assuming the PCI device is setup to act
> as PCI=5FBASE=5FADDRESS=5FSPACE=5FMEMORY).
>
> I'm using portions of hw/cirrus=5Fvga.c to make my point,

If you can send out what you have instead of mimicked
example, it would help to figure out what you are trying to do.
I was trying to keep = things simple with common code that was well established inside Qemu. I'= ve attached the code from my PCIe device to help you better understand w= hat I'm trying to do.
I'm using Qemu to dr= ive a PCIe device model. Here is a diagrammatic representation
=5F=5F=5F=5F=5F=5F      =5F=5F=5F=5F=5F=5F= =5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F         =5F= =5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F
Qe= mu  |<-->|PCIe Model Wrapper |<----->| PCIe Device Mode= l |
=5F=5F=5F=5F=5F=5F|    |=5F=5F=5F=5F=5F=5F= =5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F|       |=5F=5F=5F= =5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F=5F|

The PCIe Device model = is a complete GPU model that communicates via a simulated PCIe interface= i.e. the model represents a PCIe card that would plug into a PCIe slot = and expects to see PCIe transactions to drive it. In other words, the PC= Ie Device model thinks its connected to a PCI-Bridge so I have to mimic = this partially with the PCIe Model wrapper. It is important that you und= erstand this since its very central to the issues I'm trying to better c= omprehend. I don't have the source code to the device model, hence my ma= ny challenges.

I've written the PCIe model wrapper (the attached file), this wr= apper acts as a proxy for the Device Model and is what Qemu "sees" as an= PCI endpoint. The PCIe Model Wrapper is modelled as a Qemu PCIe device = and includes PCI configuration space registers, however the TRUE PCI con= fig registers are contained with the PCIe Device Model. 

So in a nutshell = this is what I'm trying to do: 
- Whe= n the Guest OS inside Qemu does a PCIe config read/write, the PCIe model= wrapper has to intercept that call, construct a valid PCIe config trans= action and send it to the PCIe device model. 
- Similarly for a PCIe MMIO transaction i.e, the wrapper has to= construct a PCIe transaction and send it to the device model.

I hope this puts= into perspective why I was asking the questions about how I can de= finitively identify if a request is a config request or if its a MMIO re= quest because I need to synthesize the appropriate PCIe transactions to = send to the Model.

> I have some questions about PCIe operations= sssuming the device has MMIO
> handlers involved (as shown above).
> 1. Will all PCIe config operations ALWAYS use the installed config = handlers=3F Or
> can PCIe config operations use the MMIO handlers=3F

MMIO on MMCONFIG area are routed to write/read config handler.
On the other hand MMIO on memory BAR is routed to mmio hanlder you pictu= red.
NOTE: the upstream qemu lacks q35 chipset support, so guest can NOT do MMIO on MMCONFIG area.
I am using the q35 ch= ipset that you (Yamahata) have been working on. So does that mean that g= uests OS with the qemu with q35 can only access the legacy PCI config sp= ace (256 bytes) and not the full PCIe 4k config space=3F The reason I as= k is because of an AMD document I found

Here is the relevant text:
3.3 MMIO access with different Linux Ker= nel versions Support for MMIO access for PCI configuration space depends= on the Linux Kernel version and configuration, and the existence of an = MCFG ACPI table. IO access to PCI configuration space is always possible= and will be used if MMIO access is not available. To access extended co= nfiguration space (between byte 256 and 4095) MMIO access is required.
:
Note: In bo= th cases Linux supports the IO access method as a fallback if MMIO acces= s is not possible (e.g. if MCFG ACPI table is missing). 

A kernel (with ve= rsion prior to and including 2.6.25) with enabled MMIO access method is = able to do MMIO access if and only if the BIOS provides a valid MCFG ACP= I table and if the configuration space is "E820-reserved". If these requ= irements are not met, IO access is used and the kernel logs an error mes= sage like this PCI: BIOS Bug: MCFG area at e0000000 is not E820-reserved= PCI: Not using MMCONFIG. PCI: Using configuration type 1 Beginning with= kernel version 2.6.25 Linux always uses the IO access method to access = configuration space below byte 256. Thus MMIO access is used only for ex= tended configuration space.


> 2. Assuming that both PCI config and MMIO operations can use the MM= IO handlers,
> is there any way I can identify if a transaction is a config or a m= emory
> transaction=3F
He= re is a code snippet where I register the config handlers:

static PCIDevice= Info pcie=5Fmsix=5Finfo =3D {
    .qdev.na= me      =3D PCIE=5FMSIX=5FDEVICE,
 &n= bsp;  .qdev.desc      =3D "PCIE MSIX device template= ",
    .qdev.size      =3D = sizeof(PCIE=5FMSIX=5FDEVState),
    .qdev.= reset     =3D pcie=5Fmsix=5Freset,
  =  .qdev.vmsd      =3D &vmstate=5Fpcie=5Fmsix,
    .is=5Fexpress     =3D 1,
   &nb= sp;.config=5Fread    =3D pcie=5Fmsix=5Fread=5Fconfig,
    = .config=5Fwrite   =3D pcie=5Fmsix=5Fwrite=5Fconfig,
=     .init           =3D pcie=5Fm= six=5Finitfn,
    .exit     &nbs= p;     =3D pcie=5Fmsix=5Fexitfn,
   &= nbsp;.qdev.props     =3D (Property[]) {
 &= nbsp;      DEFINE=5FPROP=5FUINT32("vectors", PCIE=5FMSIX= =5FDEVState, vectors, PCIE=5FMSIX=5FMSI=5FNR=5FVECTOR),     &n= bsp;  
        DEFINE=5FPRO= P=5FUINT16("aer=5Flog=5Fmax", PCIESlot,
   &nbs= p;                    =    port.br.dev.aer=5Flog.log=5Fmax,
 &nbs= p;                    =      PCIE=5FAER=5FLOG=5FMAX=5FDEFAULT),
&= nbsp;       DEFINE=5FPROP=5FEND=5FOF=5FLIST(),
    }
};

Here is a code sn= ippet where I register the mmio handlers:
=

static CPUWriteMemoryFunc * const= pcie=5Fmsix=5Fmem=5Fwrite=5Ffn[] =3D {
   &nbs= p;pcie=5Fmsix=5Fmem=5Fwriteb, pcie=5Fmsix=5Fmem=5Fwritew, pcie=5Fmsix=5F= mem=5Fwritel, pcie=5Fmsix=5Fmem=5Fwrited
};
<= div id=3D"kerio-curpos">
static CPUReadMemoryFunc * const pcie=5Fmsix=5Fmem= =5Fread=5Ffn[] =3D {
    pcie=5Fmsix=5Fmem= =5Freadb, pcie=5Fmsix=5Fmem=5Freadw, pcie=5Fmsix=5Fmem=5Freadl, pcie=5Fm= six=5Fmem=5Freadd
};

s= tatic void 
pcie=5Fmsix=5Fmem=5Fmap(PCIDevice *dev, = int region=5Fnum, 
        =          pcibus=5Ft addr, pcibus=5Ft size, int= type)
{
    uint32=5Ft msi= x=5Fmem=5Fbar =3D 0;
    PCIE=5FMSIX=5FDEV= State *d =3D DO=5FUPCAST(PCIE=5FMSIX=5FDEVState, dev, dev);
=
    cpu=5Fregister=5Fphysical=5Fmemory(addr, BAR=5FReg= ions[msix=5Fmem=5Fbar][0], d->mmio=5Findex);
}<= /div>

W= hich I register via the following call in the pcie=5Fmsix=5Finitfn(PCIDevice *pci=5Fdev= ) function
<= div id=3D"kerio-curpos">
pci=5Fregister=5Fbar(&d->d= ev, msix=5Fmem=5Fbar, BAR=5FRegions[msix=5Fmem=5Fbar][0], BAR=5FRegions[= msix=5Fmem=5Fbar][1], pcie=5Fmsix=5Fmem=5Fmap);

So are my following assu= mption true then for my PCIe device i.e the wrapper=3F
All config requests WILL be handled by the config handlers = and,
All MMIO requests will be handled by = the mmio handlers (given that the q35 model does not support MMIO on MMC= ONFIG)
  

> 3.a. What address is passed on the MMIO handlers for config and MMI= O
> operations=3F From pci=5Fdata=5Fwrite in pci=5Fhost.c, it appears t= hat config
> operations send only the offset into the config region. I couldn't = determine
> what address is passed for MMIO operations.
> b. Is it an offset from the BAR for MMIO operations=3F
> c. How do I get the full physical address=3F
> d. What address does a PCIe device expect to see - physical or o= ffset for=3F
> e. Is there anyway I can find out what the bus and device number= s are once
> inside the config and MMIO handlers=3F i.e once the execution has r= eached
> the pci=5Fcirrus=5Fwrite=5Fconfig() or cirrus=5Fvga=5Fmem=5Freadb(.= .) from the code above=3F

offset in configuration space of each pcie function is passed to
write/read config handler
physical address is passed to mmio handler of memory BAR.
When I examine the address on calls = to the PCIe Device Wrapper config handlers, they start at 0x0 so they cl= early are offsets. However, I also see addresses from 0x0 in the MMIO ha= ndlers. Paul's response indicated that they were offsets so I'm inclined= to believe that the address is an offset from the start of the BAR. So = let me ask my question again - when I'm synthesizing the PCIe transactio= n to send to the PCIe device model, do I have to give it a full address = i.e. bus,dev,fn for config transactions and full physical address for MM= IO transactions=3F


--
yamahata
-------------a7c7e0c125219f2ad44679c720b7238e-- -------------6f0d8078e6b4b0c79b162ca81aeed552 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="pcie_msix_template_1.c" /* * pcie=5Ftemplate=5Fdevice.c * * Copyright (c) 2010 Adnan Khaleel * Cray Inc * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License alo= ng * with this program; if not, see . */ /* This is essentially an example for a device that utilises PCIe and MS= I-X */ #include "hw.h" #include "pc.h" #include "pci=5Fids.h" #include "msi.h" #include "msix.h" #include "pcie.h" #include "pcie=5Fmsix=5Ftemplate.h" #include "pcie=5Fpkt.h" extern int pcie=5Fserver=5Ffd; extern struct hostent *pcie=5Fserver; extern uint64 pcie=5FtransId; extern bool pcie=5Fserver=5Fconnected; #define BYTE 1 #define WORD 2*BYTE #define LWORD 4*BYTE #define DWORD 8*BYTE /* Debug code */ #define DEBUG=5FPCIE=5FMSIX=5FTEMPLATE #ifdef DEBUG=5FPCIE=5FMSIX=5FTEMPLATE #define SPLIT64(x) (uint32=5Ft)((x >> 32) & 0xffffffff), (uint32=5Ft)(x = & 0xffffffff) #define PRINT=5FDEBUG(format, ...) printf(format, =5F=5FVA=5FARGS=5F=5F)= ; #define PRINT=5FDEBUG0(format) printf(format); #else #define SPLIT64(x) #define PRINT=5FDEBUG(format, ...) #define PRINT=5FDEBUG0(format) #endif #define DEFINE=5FDEVICE=5FPROPERTIES(=5Fstate, =5Fconf) #define PCIE=5FMSIX=5FVID PCI=5FVENDOR=5FID=5FCRAY #define PCIE=5FMSIX=5FDID PCI=5FDEVICE=5FID=5FCRAY=5FA= SIC #define PCIE=5FMSIX=5FSS=5FDID 0x100 #define PCIE=5FMSIX=5FVERSION 0x1 #define PCIE=5FMSIX=5FMSI=5FSUPPORTED=5FFLAGS PCI=5FMSI=5FFLAGS=5F64BI= T #define PCIE=5FMSIX=5FMSI=5FNR=5FVECTOR 1 =20 #define PCIE=5FMSIX=5FMSI=5FOFFSET 0x70 #define PCIE=5FMSIX=5FSSVID=5FOFFSET 0x80 #define PCIE=5FMSIX=5FSVID 0 #define PCIE=5FMSIX=5FSSID 0 #define PCIE=5FMSIX=5FEXP=5FOFFSET 0x90 #define PCIE=5FMSIX=5FAER=5FOFFSET 0x100 /* PCI BUS commands */ #define CMD=5FIOREAD=09 0x02 #define CMD=5FIOWRITE=09 0x03 #define CMD=5FMEMREAD=09 0x06 #define CMD=5FMEMWRITE=09 0x07 #define CMD=5FCONFIGREAD=09 0x0A #define CMD=5FCONFIGWRITE=09 0x0B // PCI device header uint32=5Ft g=5Fcfg=5Finit[0x100] =3D { // index : offset 0x030117db, // 0x00 : 0x00: Vendor ID and device ID 0x00100007, // 0x01 : 0x04: Command and status 0x00000010, // 0x02 : 0x08: Revision ID and class code 0x00800008, // 0x03 : 0x0c: BIST, header type, latency time and cach= e size 0x0000000c, // 0x04 : 0x10: BAR 0 0x00000020, // 0x05 : 0x14: BAR 1 0x00000000, // 0x06 : 0x18: BAR 2 0x00000000, // 0x07 : 0x1c: BAR 3 0x00000000, // 0x08 : 0x20: BAR 4 0x00000000, // 0x09 : 0x24: BAR 5 0x00000000, // 0x0a : 0x28 0x000017db, // 0x0b : 0x2c: Subsystem vendor ID and subsystem ID 0x00000000, // 0x0c : 0x30: Expansion ROM base address 0x00000080, // 0x0d : 0x34: Capabilities pointer 0x00000000, // 0x0e : 0x38 0x0000010b, // 0x0f : 0x3c: Interrupt line and interrupt pin 0, 0, 0, 0, // 0x10 : 0x40 0, 0, 0, 0, // 0x14 : 0x50 0, 0, 0, 0, // 0x18 : 0x60 0, 0, 0, 0, // 0x1c : 0x70 0x0003b001, // 0x20 : 0x80: Power management capabilities 0x00000008, // 0x21 : 0x84: Power management control/status 0x00000000, // 0x22 : 0x88 0x00000000, // 0x23 : 0x8c 0, 0, 0, 0, // 0x24 : 0x90 0, 0, 0, 0, // 0x28 : 0xa0 0x003fc011, // 0x2c : 0xb0: MSI-X control 0x00402000, // 0x2d : 0xb4: MSI-X table offset 0x00403000, // 0x2e : 0xb8: MSI-X pending interrupt 0x00000000, // 0x2f : 0xbc 0x00010010, // 0x30 : 0xc0: PCIe capability list register 0x00008120, // 0x31 : 0xc4: PCIe device capabilities 0x00092100, // 0x32 : 0xc8: PCIe device control and status 0x00004411, // 0x33 : 0xcc: Link capabilities 0x00110000, // 0x34 : 0xd0: Link control and status 0x00000000, // 0x35 : 0xd4 0x00000000, // 0x36 : 0xd8 0x00000000, // 0x37 : 0xdc 0x00000000, // 0x38 : 0xe0 0x00000012, // 0x39 : 0xe4: PCIe device capabilities 2 0x00000000, // 0x3a : 0xe8: PCIe device control and status 2 0x00000000, // 0x3b : 0xec: Link capabilities 2 0x00000000, // 0x3c : 0xf0: Link control and status 2 }; static const unsigned long long BAR=5FRegions[6][2] =3D=20 { // len , type 0x2000000000ull { 0x2000000000ull, PCI=5FBASE=5FADDRESS=5FSPACE=5FMEMORY | PCI=5FBAS= E=5FADDRESS=5FMEM=5FTYPE=5F64 | PCI=5FBASE=5FADDRESS=5FMEM=5FPREFETCH} ,= //BAR0, =20 { 0, 0} , // BAR1 { 0, 0} , // BAR2, { 0, 0} , // BAR3 { 0, 0} , // BAR4 { 0, 0} , // BAR5 =20 }; #define TIMEOUT=5FSEC 0 #define TIMEOUT=5FUSEC 50 extern int do=5Fremote=5Fpcie=5Fmodel=5Fsocket=5Fread(void* pcie=5Ftrans= , int size, int to=5Fsec, int to=5Fusec, bool startup, int64=5Ft loop=5F= count); extern int do=5Fremote=5Fpcie=5Fmodel=5Fsocket=5Fwrite(void* pcie=5Ftran= s, int size, int to=5Fsec, int to=5Fusec, bool startup, int64=5Ft loop= =5Fcount); typedef struct PCIE=5FMSIX=5FDEVState=5FSt { PCIDevice dev; int mmio=5Findex; uint32=5Ft intrmask; uint32=5Ft intrstatus; uint32=5Ft doorbell; uint32=5Ft vectors; uint32=5Ft features; } PCIE=5FMSIX=5FDEVState; static uint64=5Ft=20 do=5Fsocket=5Ftransaction(void *opaque, bool rd, uint64=5Ft addr, uint64= =5Ft val, int len) { int bar=5Fregion =3D 0, i, err; uint32=5Ft reg=5Fbase, reg=5Fsize, base=5Faddr; PCIDevice *d =3D opaque; PCIe=5Fcmd=5Ft pcie=5Ftrans; reg=5Fbase =3D d->dev.io=5Fregions[bar=5Fregion].addr; reg=5Fsize =3D d->dev.io=5Fregions[bar=5Fregion].size; base=5Faddr =3D d->dev.io=5Fregions[bar=5Fregion].addr; pcie=5Ftrans.pktType =3D (rd) =3F CFG=5FRD=5F0 : CFG=5FWR=5F0; pcie=5Ftrans.addr64 =3D addr; pcie=5Ftrans.transId =3D pcie=5FtransId++; for (i =3D 0; i < len; i++) pcie=5Ftrans.data[i] =3D (rd) =3F 0 : ((val >> (i*8)) & 0xff); pcie=5Ftrans.data=5Flen =3D len; pcie=5Ftrans.stop=5Fserver =3D false; pcie=5Ftrans.start=5Fdelta =3D 0; pcie=5Ftrans.isAlive =3D false; pcie=5Ftrans.valid =3D true; pcie=5Ftrans.aries=5Freq =3D false; if (rd) { PRINT=5FDEBUG("%s: Cfg=5FRd Addr=3D0x%08x%08x ReqId=3D%lld bar= =3D%d\n", =5F=5FFUNCTION=5F=5F, SPLIT64(addr64), pcie=5Ftrans.transId, b= ar=5Fregion); } else { PRINT=5FDEBUG("%s: Cfg=5FWr Addr=3D0x%08x%08x ReqId=3D%lld bar= =3D%d Data=3D0x", =5F=5FFUNCTION=5F=5F, SPLIT64(addr64), pcie=5Ftrans.tr= ansId, bar=5Fregion); for (i =3D 0; i < len; i++) PRINT=5FDEBUG("%02x", pcie=5Ftrans.data[i]); PRINT=5FDEBUG0("\n"); } if (pcie=5Fserver=5Fconnected) { err =3D do=5Fremote=5Fpcie=5Fmodel=5Fsocket=5Fwrite((void*)&pcie= =5Ftrans, sizeof(PCIe=5Fcmd=5Ft), TIMEOUT=5FSEC, TIMEOUT=5FUSEC, false, = 0); if (err > 0) { if (rd) { PCIe=5Fcmd=5Ft cmpltd=5Fcmd; cmpltd=5Fcmd.valid =3D false; err =3D do=5Fremote=5Fpcie=5Fmodel=5Fsocket=5Fread((void= *)&cmpltd=5Fcmd, sizeof(PCIe=5Fcmd=5Ft), TIMEOUT=5FSEC, TIMEOUT=5FUSEC, = false, 0); if ((err > 0) && (cmpltd=5Fcmd.valid)) { if ((cmpltd=5Fcmd.pktType =3D=3D CMPLT=5FD) &&=20 (pcie=5Ftrans.transId =3D=3D cmpltd=5Fcmd.transI= d))=20 { val =3D cmpltd=5Fcmd.data[3] << 24 |=20 cmpltd=5Fcmd.data[2] << 16 |=20 cmpltd=5Fcmd.data[1] << 8 |=20 cmpltd=5Fcmd.data[0]; PRINT=5FDEBUG("\n%s: Cfg=5FRd Cmplt=5FD %d bytes= . Addr=3D0x%08x%08x val=3D0x%08x%08x bar=3D%d",=5F=5FFUNCTION=5F=5F, len= , SPLIT64(addr), SPLIT64(val), bar=5Fregion); } } } } } return val; } static void=20 pcie=5Fmsix=5Fnotify(PCIDevice *d, uint16=5Ft vector, bool trigger) { PRINT=5FDEBUG("\n%s: notify vector %d trigger:%d \n", =5F=5FFUNCTION= =5F=5F, vector, trigger); if (msix=5Fenabled(d)) { if (trigger) { msix=5Fnotify(d, vector); } } else if (msi=5Fenabled(d)) { if (trigger){ msi=5Fnotify(d, vector); } } } static void=20 pcie=5Fmsix=5Fmem=5Fwrite(void *opaque, uint32=5Ft addr, uint32=5Ft val,= int len) {=20 uint32=5Ft reg=5Fbase, reg=5Fsize; uint32=5Ft base=5Faddr; int bar=5Fregion =3D 0; // Aries only has BAR 0/1 since its 64bit PCIE=5FMSIX=5FDEVState *d =3D opaque; bool write =3D false; reg=5Fbase =3D d->dev.io=5Fregions[bar=5Fregion].addr; reg=5Fsize =3D d->dev.io=5Fregions[bar=5Fregion].size; base=5Faddr =3D d->dev.io=5Fregions[bar=5Fregion].addr; PRINT=5FDEBUG("\n%s: mem=5Fwrite BAR Base address=3D0x%x Addr=3D0x%x= val=3D0x%x bar=3D%d\n", =5F=5FFUNCTION=5F=5F, base=5Faddr, addr, val, b= ar=5Fregion); PRINT=5FDEBUG("\n%s: mem=5Fwrite REAL address: 0x%x\n", =5F=5FFUNCTI= ON=5F=5F, base=5Faddr + addr); PRINT=5FDEBUG("\n%s: mem=5Fwrite Addr=3D0x%x val=3D0x%x bar=3D%d\n",= =5F=5FFUNCTION=5F=5F, addr-reg=5Fbase, val, bar=5Fregion); do=5Fsocket=5Ftransaction(opaque, write, addr, val, len); } static uint64=5Ft pcie=5Fmsix=5Fmem=5Fread(void *opaque, uint32=5Ft addr, int len) { =20 uint64=5Ft val =3D -1; uint32=5Ft reg=5Fbase, reg=5Fsize; uint32=5Ft base=5Faddr; int bar=5Fregion =3D 0; // Aries only has BAR 0/1 since its 64bit PCIE=5FMSIX=5FDEVState *d =3D opaque; bool read =3D true; reg=5Fbase =3D d->dev.io=5Fregions[bar=5Fregion].addr; reg=5Fsize =3D d->dev.io=5Fregions[bar=5Fregion].size; base=5Faddr =3D d->dev.io=5Fregions[bar=5Fregion].addr; PRINT=5FDEBUG("\n%s: mem=5Fread BAR Base address=3D0x%x Addr=3D0x%x = val=3D0x%x bar=3D%d\n", =5F=5FFUNCTION=5F=5F, base=5Faddr, addr, val, ba= r=5Fregion); PRINT=5FDEBUG("\n%s: mem=5Fread REAL address: 0x%x\n", =5F=5FFUNCTIO= N=5F=5F, base=5Faddr + addr); =20 val =3D do=5Fsocket=5Ftransaction(opaque, read, addr, val, len); =20 PRINT=5FDEBUG("\n%s: mem=5Fread Addr=3D0x%x val=3D0x%x bar=3D%d\n", = =5F=5FFUNCTION=5F=5F, addr-reg=5Fbase, val, bar=5Fregion); =20 return val; } static void pcie=5Fmsix=5Fmem=5Fwriteb(void *opaque, target=5Fphys=5Faddr=5Ft addr, = uint32=5Ft val) { pcie=5Fmsix=5Fmem=5Fwrite(opaque, addr, val, 1); } static void pcie=5Fmsix=5Fmem=5Fwritew(void *opaque, target=5Fphys=5Faddr=5Ft addr, = uint32=5Ft val) { pcie=5Fmsix=5Fmem=5Fwrite(opaque, addr, val, 2); } static void pcie=5Fmsix=5Fmem=5Fwritel(void *opaque, target=5Fphys=5Faddr=5Ft addr, = uint32=5Ft val) { pcie=5Fmsix=5Fmem=5Fwrite(opaque, addr, val, 4); } static bool trans64wr=5Fmsl; // Most Significant LWord static uint64=5Ft trans64wr=5Fval; static bool trans64rd=5Fmsl; // Most Significant LWord static uint64=5Ft trans64rd=5Fval; static void pcie=5Fmsix=5Fmem=5Fwrited(void *opaque, target=5Fphys=5Faddr=5Ft addr, = uint32=5Ft val) { if (!trans64wr=5Fmsl) { trans64wr=5Fval =3D val; trans64wr=5Fmsl =3D true; } else { uint64=5Ft temp =3D val; trans64wr=5Fval |=3D (temp << 32); pcie=5Fmsix=5Fmem=5Fwrite(opaque, addr, trans64wr=5Fval, 8); trans64wr=5Fmsl =3D false; } } static uint32=5Ft=20 pcie=5Fmsix=5Fmem=5Freadb(void *opaque, target=5Fphys=5Faddr=5Ft addr) { return pcie=5Fmsix=5Fmem=5Fread(opaque, addr, 1); } static uint32=5Ft=20 pcie=5Fmsix=5Fmem=5Freadw(void *opaque, target=5Fphys=5Faddr=5Ft addr) { return pcie=5Fmsix=5Fmem=5Fread(opaque, addr, 2); } static uint32=5Ft=20 pcie=5Fmsix=5Fmem=5Freadl(void *opaque, target=5Fphys=5Faddr=5Ft addr) { return pcie=5Fmsix=5Fmem=5Fread(opaque, addr, 4); } static uint32=5Ft=20 pcie=5Fmsix=5Fmem=5Freadd(void *opaque, target=5Fphys=5Faddr=5Ft addr) { if (!trans64rd=5Fmsl) { trans64rd=5Fval =3D pcie=5Fmsix=5Fmem=5Fread(opaque, addr, 8); trans64rd=5Fmsl =3D true; return (trans64rd=5Fval & 0xffffffff); } else { trans64rd=5Fmsl =3D false; return (trans64rd=5Fval >> 32); } } static CPUWriteMemoryFunc * const pcie=5Fmsix=5Fmem=5Fwrite=5Ffn[] =3D { pcie=5Fmsix=5Fmem=5Fwriteb, pcie=5Fmsix=5Fmem=5Fwritew, pcie=5Fmsix= =5Fmem=5Fwritel, pcie=5Fmsix=5Fmem=5Fwrited }; static CPUReadMemoryFunc * const pcie=5Fmsix=5Fmem=5Fread=5Ffn[] =3D { pcie=5Fmsix=5Fmem=5Freadb, pcie=5Fmsix=5Fmem=5Freadw, pcie=5Fmsix=5F= mem=5Freadl, pcie=5Fmsix=5Fmem=5Freadd }; static void=20 pcie=5Fmsix=5Fmem=5Fmap(PCIDevice *dev, int region=5Fnum,=20 pcibus=5Ft addr, pcibus=5Ft size, int type) { uint32=5Ft msix=5Fmem=5Fbar =3D 0; PCIE=5FMSIX=5FDEVState *d =3D DO=5FUPCAST(PCIE=5FMSIX=5FDEVState, de= v, dev); cpu=5Fregister=5Fphysical=5Fmemory(addr, BAR=5FRegions[msix=5Fmem=5F= bar][0], d->mmio=5Findex); } static uint32=5Ft pcie=5Fmsix=5Fread=5Fconfig(PCIDevice *d, uint32=5Ft address, int len) { return pci=5Fdefault=5Fread=5Fconfig(d, address, len); } static void pcie=5Fmsix=5Fwrite=5Fconfig(PCIDevice *d, uint32=5Ft address, uint32=5Ft val, i= nt len) { =20 pci=5Fdefault=5Fwrite=5Fconfig(d, address, val, len); msix=5Fwrite=5Fconfig(d, address, val, len); /*pcie=5Fcap=5Fdeverr=5Fwrite=5Fconfig(d, address, val, len); pcie=5Fcap=5Fflr=5Fwrite=5Fconfig(d, address, val, len); =20 pcie=5Faer=5Fwrite=5Fconfig=5Fvbridge(d, address, val, len); pcie=5Faer=5Fwrite=5Fconfig(d, address, val, len);*/ } static void pcie=5Fmsix=5Freset(DeviceState *qdev) { PCIDevice *d =3D DO=5FUPCAST(PCIDevice, qdev, qdev); msix=5Freset(d); pcie=5Fcap=5Fdeverr=5Freset(d); } static void pcie=5Fmsix=5Fflr(PCIDevice *d) { pci=5Fdevice=5Freset(d); } static int pcie=5Fmsix=5Finitfn(PCIDevice *pci=5Fdev) { PCIE=5FMSIX=5FDEVState *d =3D DO=5FUPCAST(PCIE=5FMSIX=5FDEVState, de= v, pci=5Fdev); PCIBridge *br =3D DO=5FUPCAST(PCIBridge, dev, pci=5Fdev); PCIEPort *p =3D DO=5FUPCAST(PCIEPort, br, br); int rc; PRINT=5FDEBUG("%s: PCIE MSIX Device init...\n", =5F=5FFUNCTION=5F=5F= ); int msix=5Fmem=5Fbar =3D 0; // Since its a 64bit BAR, we take up BAR= 0 & BAR1 d->vectors =3D 64; d->mmio=5Findex =3D cpu=5Fregister=5Fio=5Fmemory(pcie=5Fmsix=5Fmem= =5Fread=5Ffn, pcie=5Fmsix=5Fmem=5Fwrite=5Ffn, d); rc =3D msix=5Finit(&d->dev, d->vectors, msix=5Fmem=5Fbar, 0); =20 /*if (!rc) { PRINT=5FDEBUG("%s: Registering Bar %i as I/O BAR\n", =5F=5FFUNCT= ION=5F=5F, msix=5Fmem=5Fbar); pci=5Fregister=5Fbar(&d->dev, msix=5Fmem=5Fbar, msix=5Fbar=5Fsiz= e(&d->dev), PCI=5FBASE=5FADDRESS=5FSPACE=5FMEMORY, msix=5Fmmio=5Fmap); PRINT=5FDEBUG("%s: MSI-X initialized (%d vectors)\n", =5F=5FFUNC= TION=5F=5F, d->vectors); } else { PRINT=5FDEBUG("%s: MSI-X initialization failed!\n", =5F=5FFUNCTI= ON=5F=5F); return rc; }*/ =20 // Activate the vectors /*for (i =3D 0; i < d->vectors; i++) { msix=5Fvector=5Fuse(&d->dev, i); }*/ =20 pci=5Fregister=5Fbar(&d->dev, msix=5Fmem=5Fbar, BAR=5FRegions[msix= =5Fmem=5Fbar][0], BAR=5FRegions[msix=5Fmem=5Fbar][1], pcie=5Fmsix=5Fmem= =5Fmap); =20 rc =3D pci=5Fpcie=5Fcap=5Finit(&d->dev, PCIE=5FMSIX=5FEXP=5FOFFSET, = PCI=5FEXP=5FTYPE=5FENDPOINT, p->port); if (rc < 0) { return rc; } pci=5Fset=5Fword(&d->dev.config[PCI=5FVENDOR=5FID], g=5Fcfg= =5Finit[0] & 0xffff); pci=5Fset=5Fword(&d->dev.config[PCI=5FDEVICE=5FID], (g=5Fcfg= =5Finit[0] >> 16) & 0xffff); pci=5Fset=5Fword(&d->dev.config[PCI=5FCOMMAND], g=5Fcfg= =5Finit[1] & 0xffff); pci=5Fset=5Fword(&d->dev.config[PCI=5FSTATUS], (g=5Fcfg= =5Finit[1] >> 16) & 0xffff); pci=5Fset=5Fbyte(&d->dev.config[PCI=5FREVISION=5FID], g=5Fcfg= =5Finit[2] & 0xff); pci=5Fset=5Fbyte(&d->dev.config[PCI=5FREVISION=5FID+1], (g=5Fcfg= =5Finit[2] >> 8) & 0xff); pci=5Fset=5Fword(&d->dev.config[PCI=5FREVISION=5FID+2], (g=5Fcfg= =5Finit[2] >> 16) & 0xffff); pci=5Fset=5Fbyte(&d->dev.config[PCI=5FCACHE=5FLINE=5FSIZE], g=5Fc= fg=5Finit[3] & 0xff); pci=5Fset=5Fbyte(&d->dev.config[PCI=5FLATENCY=5FTIMER], (g=5Fcfg= =5Finit[3] >> 8) & 0xff); pci=5Fset=5Fbyte(&d->dev.config[PCI=5FHEADER=5FTYPE], (g=5Fcfg= =5Finit[3] >> 16) & 0xff); //pci=5Fset=5Fbyte(&d->dev.config[PCI=5FBIST], (g=5Fcfg= =5Finit[3] >> 24) & 0xff); //pci=5Fset=5Flong(&d->dev.config[PCI=5FBASE=5FADDRESS=5F0], g= =5Fcfg=5Finit[4]); //pci=5Fset=5Flong(&d->dev.config[PCI=5FBASE=5FADDRESS=5F1], g= =5Fcfg=5Finit[5]); //pci=5Fset=5Flong(&d->dev.config[PCI=5FBASE=5FADDRESS=5F2], g= =5Fcfg=5Finit[6]); //pci=5Fset=5Flong(&d->dev.config[PCI=5FBASE=5FADDRESS=5F3], g= =5Fcfg=5Finit[7]); //pci=5Fset=5Flong(&d->dev.config[PCI=5FBASE=5FADDRESS=5F4], g= =5Fcfg=5Finit[8]); //pci=5Fset=5Flong(&d->dev.config[PCI=5FBASE=5FADDRESS=5F5], g= =5Fcfg=5Finit[9]); //pci=5Fset=5Flong(&d->dev.config[PCI=5FCARDBUS=5FCIS], g=5Fc= fg=5Finit[0xa]); pci=5Fset=5Fword(&d->dev.config[PCI=5FSUBSYSTEM=5FVENDOR=5FID],g=5Fc= fg=5Finit[0xb] & 0xffff); pci=5Fset=5Fword(&d->dev.config[PCI=5FSUBSYSTEM=5FID], (g=5Fcfg= =5Finit[0xb] >> 16) & 0xffff); //pci=5Fset=5Flong(&d->dev.config[PCI=5FROM=5FADDRESS], g=5Fc= fg=5Finit[0xc]); //pci=5Fset=5Fbyte(&d->dev.config[PCI=5FCAPABILITY=5FLIST], g=5Fc= fg=5Finit[0xd] & 0xff); pci=5Fset=5Fbyte(&d->dev.config[PCI=5FINTERRUPT=5FLINE], g=5Fcfg= =5Finit[0xf] & 0xff); pci=5Fset=5Fbyte(&d->dev.config[PCI=5FINTERRUPT=5FPIN], (g=5Fcfg= =5Finit[0xf] >> 8) & 0xff); pci=5Fset=5Fbyte(&d->dev.config[PCI=5FMIN=5FGNT], (g=5Fcfg= =5Finit[0xf] >> 16) & 0xff); pci=5Fset=5Fbyte(&d->dev.config[PCI=5FMAX=5FLAT], (g=5Fcfg= =5Finit[0xf] >> 24) & 0xff); // Power Capabilities pci=5Fset=5Flong(&d->dev.config[0x80], g=5Fcfg=5Fi= nit[0x20]); pci=5Fset=5Flong(&d->dev.config[0x84], g=5Fcfg=5Fi= nit[0x21]); pci=5Fset=5Flong(&d->dev.config[0x88], g=5Fcfg=5Fi= nit[0x22]); pci=5Fset=5Flong(&d->dev.config[0x8c], g=5Fcfg=5Fi= nit[0x23]); // MSI-X Capabilities pci=5Fset=5Flong(&d->dev.config[0xb0], g=5Fcfg=5Fi= nit[0x2c]); pci=5Fset=5Flong(&d->dev.config[0xb4], g=5Fcfg=5Fi= nit[0x2d]); pci=5Fset=5Flong(&d->dev.config[0xb8], g=5Fcfg=5Fi= nit[0x2e]); pci=5Fset=5Flong(&d->dev.config[0xbc], g=5Fcfg=5Fi= nit[0x2f]); pci=5Fset=5Flong(&d->dev.config[0xc0], g=5Fcfg=5Fi= nit[0x30]); pci=5Fset=5Flong(&d->dev.config[0xc4], g=5Fcfg=5Fi= nit[0x31]); pci=5Fset=5Flong(&d->dev.config[0xc8], g=5Fcfg=5Fi= nit[0x32]); pci=5Fset=5Flong(&d->dev.config[0xcc], g=5Fcfg=5Fi= nit[0x33]); pci=5Fset=5Flong(&d->dev.config[0xd0], g=5Fcfg=5Fi= nit[0x34]); pci=5Fset=5Flong(&d->dev.config[0xd4], g=5Fcfg=5Fi= nit[0x35]); pci=5Fset=5Flong(&d->dev.config[0xd8], g=5Fcfg=5Fi= nit[0x36]); pci=5Fset=5Flong(&d->dev.config[0xdc], g=5Fcfg=5Fi= nit[0x37]); pci=5Fset=5Flong(&d->dev.config[0xe0], g=5Fcfg=5Fi= nit[0x38]); pci=5Fset=5Flong(&d->dev.config[0xe4], g=5Fcfg=5Fi= nit[0x39]); pci=5Fset=5Flong(&d->dev.config[0xe8], g=5Fcfg=5Fi= nit[0x3a]); pci=5Fset=5Flong(&d->dev.config[0xec], g=5Fcfg=5Fi= nit[0x3b]); pci=5Fset=5Flong(&d->dev.config[0xf0], g=5Fcfg=5Fi= nit[0x3c]); PRINT=5FDEBUG("%s: Init done\n", =5F=5FFUNCTION=5F=5F); return 0; } static int pcie=5Fmsix=5Fexitfn(PCIDevice *pci=5Fdev) { pcie=5Faer=5Fexit(pci=5Fdev); msix=5Funinit(pci=5Fdev); return pci=5Fpcie=5Fcap=5Fexit(pci=5Fdev); } PCIDevice* pcie=5Fmsix=5Finit(PCIBus *bus) { return pci=5Fcreate=5Fsimple(bus, -1, "pcie=5Fmsix=5Fdevice"); } static const VMStateDescription vmstate=5Fpcie=5Fmsix =3D { .name =3D "pcie-msix-device", .version=5Fid =3D 1, .minimum=5Fversion=5Fid =3D 1, .minimum=5Fversion=5Fid=5Fold =3D 1, .fields =3D (VMStateField[]) { VMSTATE=5FPCIE=5FDEVICE(dev, PCIE=5FMSIX=5FDEVState), VMSTATE=5FSTRUCT(dev.aer=5Flog, PCIE=5FMSIX=5FDEVState, 0, vmsta= te=5Fpcie=5Faer=5Flog, struct pcie=5Faer=5Flog), VMSTATE=5FEND=5FOF=5FLIST() } }; static PCIDeviceInfo pcie=5Fmsix=5Finfo =3D { .qdev.name =3D PCIE=5FMSIX=5FDEVICE, .qdev.desc =3D "PCIE MSIX device template", .qdev.size =3D sizeof(PCIE=5FMSIX=5FDEVState), .qdev.reset =3D pcie=5Fmsix=5Freset, .qdev.vmsd =3D &vmstate=5Fpcie=5Fmsix, .is=5Fexpress =3D 1, .config=5Fread =3D pcie=5Fmsix=5Fread=5Fconfig, .config=5Fwrite =3D pcie=5Fmsix=5Fwrite=5Fconfig, .init =3D pcie=5Fmsix=5Finitfn, .exit =3D pcie=5Fmsix=5Fexitfn, .qdev.props =3D (Property[]) { DEFINE=5FPROP=5FUINT32("vectors", PCIE=5FMSIX=5FDEVState, vector= s, PCIE=5FMSIX=5FMSI=5FNR=5FVECTOR), =20 DEFINE=5FPROP=5FUINT16("aer=5Flog=5Fmax", PCIESlot, port.br.dev.aer=5Flog.log=5Fmax, PCIE=5FAER=5FLOG=5FMAX=5FDEFAULT), DEFINE=5FPROP=5FEND=5FOF=5FLIST(), } }; static void pcie=5Fmsix=5Fregister(void) { pci=5Fqdev=5Fregister(&pcie=5Fmsix=5Finfo); } device=5Finit(pcie=5Fmsix=5Fregister); -------------6f0d8078e6b4b0c79b162ca81aeed552--