diff mbox

[RFC,v3,13/18] spapr_pci: Enable DDW

Message ID 1409307142-2600-14-git-send-email-aik@ozlabs.ru
State New
Headers show

Commit Message

Alexey Kardashevskiy Aug. 29, 2014, 10:12 a.m. UTC
This implements DDW for emulated PHB.

This advertises the query/create/remove RTAS tokens in device tree.
This does not advertise the reset RTAS token though, will be added later.

The "ddw" property is enabled by default on a PHB but for compatibility
pseries-2.1 machine disables it.

Since QEMU does not implement any 64bit DMA capable device, this hack
has been used to enable 64bit DMA on E1000:

Comments

Alexander Graf Sept. 10, 2014, 1:01 p.m. UTC | #1
On 29.08.14 12:12, Alexey Kardashevskiy wrote:
> This implements DDW for emulated PHB.
> 
> This advertises the query/create/remove RTAS tokens in device tree.
> This does not advertise the reset RTAS token though, will be added later.
> 
> The "ddw" property is enabled by default on a PHB but for compatibility
> pseries-2.1 machine disables it.
> 
> Since QEMU does not implement any 64bit DMA capable device, this hack
> has been used to enable 64bit DMA on E1000:
> 
> diff --git a/hw/net/e1000.c b/hw/net/e1000.c
> index 0fc29a0..131f80a 100644
> --- a/hw/net/e1000.c
> +++ b/hw/net/e1000.c
> @@ -240,6 +240,7 @@ static const uint32_t mac_reg_init[] = {
>      [STATUS] =  0x80000000 | E1000_STATUS_GIO_MASTER_ENABLE |
>                  E1000_STATUS_ASDV | E1000_STATUS_MTXCKOK |
>                  E1000_STATUS_SPEED_1000 | E1000_STATUS_FD |
> +                E1000_STATUS_PCIX_MODE |
>                  E1000_STATUS_LU,
>      [MANC] =    E1000_MANC_EN_MNG2HOST | E1000_MANC_RCV_TCO_EN |
>                  E1000_MANC_ARP_EN | E1000_MANC_0298_EN |
> 
> Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
> ---
> Changes:
> v3:
> * removed reset
> * windows_num is now 1 or bigger rather than 0-based value and it is only
> changed in PHB code, not in RTAS
> * added page mask check in create()
> 
> v2:
> * tested on hacked emulated E1000
> * implemented DDW reset on the PHB reset
> * spapr_pci_ddw_remove/spapr_pci_ddw_reset are public for reuse by VFIO
> ---
>  hw/ppc/spapr.c              |  9 +++++
>  hw/ppc/spapr_pci.c          | 94 +++++++++++++++++++++++++++++++++++++++++++++
>  include/hw/pci-host/spapr.h |  7 ++++
>  3 files changed, 110 insertions(+)
> 
> diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
> index d2d3c27..663cb75 100644
> --- a/hw/ppc/spapr.c
> +++ b/hw/ppc/spapr.c
> @@ -1670,11 +1670,20 @@ static const TypeInfo spapr_machine_info = {
>  static void spapr_machine_2_1_class_init(ObjectClass *oc, void *data)
>  {
>      MachineClass *mc = MACHINE_CLASS(oc);
> +    static GlobalProperty compat_props[] = {
> +        {
> +            .driver   = TYPE_SPAPR_PCI_HOST_BRIDGE,
> +            .property = "ddw",
> +            .value    = stringify(off),
> +        },
> +        { /* end of list */ }
> +    };
>  
>      mc->name = "pseries-2.1";
>      mc->desc = "pSeries Logical Partition (PAPR compliant) v2.1";
>      mc->alias = "pseries";
>      mc->is_default = 1;
> +    mc->compat_props = compat_props;
>  }
>  
>  static const TypeInfo spapr_machine_2_1_info = {
> diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
> index 2968b39..04ee1dc 100644
> --- a/hw/ppc/spapr_pci.c
> +++ b/hw/ppc/spapr_pci.c
> @@ -470,6 +470,76 @@ static const MemoryRegionOps spapr_msi_ops = {
>  };
>  
>  /*
> + * Dynamic DMA windows
> + */
> +static int spapr_pci_ddw_query(sPAPRPHBState *sphb,
> +                               uint32_t *windows_available,
> +                               uint32_t *page_size_mask)
> +{
> +    *windows_available = 1;
> +    *page_size_mask = DDW_PGSIZE_64K | DDW_PGSIZE_16M;
> +
> +    return 0;

What exactly does this return? The number of still available windows?
The total number of windows?


Alex
Alexey Kardashevskiy Sept. 10, 2014, 2:58 p.m. UTC | #2
On 09/10/2014 11:01 PM, Alexander Graf wrote:
> 
> 
> On 29.08.14 12:12, Alexey Kardashevskiy wrote:
>> This implements DDW for emulated PHB.
>>
>> This advertises the query/create/remove RTAS tokens in device tree.
>> This does not advertise the reset RTAS token though, will be added later.
>>
>> The "ddw" property is enabled by default on a PHB but for compatibility
>> pseries-2.1 machine disables it.
>>
>> Since QEMU does not implement any 64bit DMA capable device, this hack
>> has been used to enable 64bit DMA on E1000:
>>
>> diff --git a/hw/net/e1000.c b/hw/net/e1000.c
>> index 0fc29a0..131f80a 100644
>> --- a/hw/net/e1000.c
>> +++ b/hw/net/e1000.c
>> @@ -240,6 +240,7 @@ static const uint32_t mac_reg_init[] = {
>>      [STATUS] =  0x80000000 | E1000_STATUS_GIO_MASTER_ENABLE |
>>                  E1000_STATUS_ASDV | E1000_STATUS_MTXCKOK |
>>                  E1000_STATUS_SPEED_1000 | E1000_STATUS_FD |
>> +                E1000_STATUS_PCIX_MODE |
>>                  E1000_STATUS_LU,
>>      [MANC] =    E1000_MANC_EN_MNG2HOST | E1000_MANC_RCV_TCO_EN |
>>                  E1000_MANC_ARP_EN | E1000_MANC_0298_EN |
>>
>> Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
>> ---
>> Changes:
>> v3:
>> * removed reset
>> * windows_num is now 1 or bigger rather than 0-based value and it is only
>> changed in PHB code, not in RTAS
>> * added page mask check in create()
>>
>> v2:
>> * tested on hacked emulated E1000
>> * implemented DDW reset on the PHB reset
>> * spapr_pci_ddw_remove/spapr_pci_ddw_reset are public for reuse by VFIO
>> ---
>>  hw/ppc/spapr.c              |  9 +++++
>>  hw/ppc/spapr_pci.c          | 94 +++++++++++++++++++++++++++++++++++++++++++++
>>  include/hw/pci-host/spapr.h |  7 ++++
>>  3 files changed, 110 insertions(+)
>>
>> diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
>> index d2d3c27..663cb75 100644
>> --- a/hw/ppc/spapr.c
>> +++ b/hw/ppc/spapr.c
>> @@ -1670,11 +1670,20 @@ static const TypeInfo spapr_machine_info = {
>>  static void spapr_machine_2_1_class_init(ObjectClass *oc, void *data)
>>  {
>>      MachineClass *mc = MACHINE_CLASS(oc);
>> +    static GlobalProperty compat_props[] = {
>> +        {
>> +            .driver   = TYPE_SPAPR_PCI_HOST_BRIDGE,
>> +            .property = "ddw",
>> +            .value    = stringify(off),
>> +        },
>> +        { /* end of list */ }
>> +    };
>>  
>>      mc->name = "pseries-2.1";
>>      mc->desc = "pSeries Logical Partition (PAPR compliant) v2.1";
>>      mc->alias = "pseries";
>>      mc->is_default = 1;
>> +    mc->compat_props = compat_props;
>>  }
>>  
>>  static const TypeInfo spapr_machine_2_1_info = {
>> diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
>> index 2968b39..04ee1dc 100644
>> --- a/hw/ppc/spapr_pci.c
>> +++ b/hw/ppc/spapr_pci.c
>> @@ -470,6 +470,76 @@ static const MemoryRegionOps spapr_msi_ops = {
>>  };
>>  
>>  /*
>> + * Dynamic DMA windows
>> + */
>> +static int spapr_pci_ddw_query(sPAPRPHBState *sphb,
>> +                               uint32_t *windows_available,
>> +                               uint32_t *page_size_mask)
>> +{
>> +    *windows_available = 1;
>> +    *page_size_mask = DDW_PGSIZE_64K | DDW_PGSIZE_16M;
>> +
>> +    return 0;
> 
> What exactly does this return? The number of still available windows?
> The total number of windows?

1. Number of available windows
2. page masks supported for new windows.

This is what RTAS's counterpart does. We can change it to something better
if we want but I cannot think of anything better.
Alexander Graf Sept. 10, 2014, 9:16 p.m. UTC | #3
On 10.09.14 16:58, Alexey Kardashevskiy wrote:
> On 09/10/2014 11:01 PM, Alexander Graf wrote:
>>
>>
>> On 29.08.14 12:12, Alexey Kardashevskiy wrote:
>>> This implements DDW for emulated PHB.
>>>
>>> This advertises the query/create/remove RTAS tokens in device tree.
>>> This does not advertise the reset RTAS token though, will be added later.
>>>
>>> The "ddw" property is enabled by default on a PHB but for compatibility
>>> pseries-2.1 machine disables it.
>>>
>>> Since QEMU does not implement any 64bit DMA capable device, this hack
>>> has been used to enable 64bit DMA on E1000:
>>>
>>> diff --git a/hw/net/e1000.c b/hw/net/e1000.c
>>> index 0fc29a0..131f80a 100644
>>> --- a/hw/net/e1000.c
>>> +++ b/hw/net/e1000.c
>>> @@ -240,6 +240,7 @@ static const uint32_t mac_reg_init[] = {
>>>      [STATUS] =  0x80000000 | E1000_STATUS_GIO_MASTER_ENABLE |
>>>                  E1000_STATUS_ASDV | E1000_STATUS_MTXCKOK |
>>>                  E1000_STATUS_SPEED_1000 | E1000_STATUS_FD |
>>> +                E1000_STATUS_PCIX_MODE |
>>>                  E1000_STATUS_LU,
>>>      [MANC] =    E1000_MANC_EN_MNG2HOST | E1000_MANC_RCV_TCO_EN |
>>>                  E1000_MANC_ARP_EN | E1000_MANC_0298_EN |
>>>
>>> Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
>>> ---
>>> Changes:
>>> v3:
>>> * removed reset
>>> * windows_num is now 1 or bigger rather than 0-based value and it is only
>>> changed in PHB code, not in RTAS
>>> * added page mask check in create()
>>>
>>> v2:
>>> * tested on hacked emulated E1000
>>> * implemented DDW reset on the PHB reset
>>> * spapr_pci_ddw_remove/spapr_pci_ddw_reset are public for reuse by VFIO
>>> ---
>>>  hw/ppc/spapr.c              |  9 +++++
>>>  hw/ppc/spapr_pci.c          | 94 +++++++++++++++++++++++++++++++++++++++++++++
>>>  include/hw/pci-host/spapr.h |  7 ++++
>>>  3 files changed, 110 insertions(+)
>>>
>>> diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
>>> index d2d3c27..663cb75 100644
>>> --- a/hw/ppc/spapr.c
>>> +++ b/hw/ppc/spapr.c
>>> @@ -1670,11 +1670,20 @@ static const TypeInfo spapr_machine_info = {
>>>  static void spapr_machine_2_1_class_init(ObjectClass *oc, void *data)
>>>  {
>>>      MachineClass *mc = MACHINE_CLASS(oc);
>>> +    static GlobalProperty compat_props[] = {
>>> +        {
>>> +            .driver   = TYPE_SPAPR_PCI_HOST_BRIDGE,
>>> +            .property = "ddw",
>>> +            .value    = stringify(off),
>>> +        },
>>> +        { /* end of list */ }
>>> +    };
>>>  
>>>      mc->name = "pseries-2.1";
>>>      mc->desc = "pSeries Logical Partition (PAPR compliant) v2.1";
>>>      mc->alias = "pseries";
>>>      mc->is_default = 1;
>>> +    mc->compat_props = compat_props;
>>>  }
>>>  
>>>  static const TypeInfo spapr_machine_2_1_info = {
>>> diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
>>> index 2968b39..04ee1dc 100644
>>> --- a/hw/ppc/spapr_pci.c
>>> +++ b/hw/ppc/spapr_pci.c
>>> @@ -470,6 +470,76 @@ static const MemoryRegionOps spapr_msi_ops = {
>>>  };
>>>  
>>>  /*
>>> + * Dynamic DMA windows
>>> + */
>>> +static int spapr_pci_ddw_query(sPAPRPHBState *sphb,
>>> +                               uint32_t *windows_available,
>>> +                               uint32_t *page_size_mask)
>>> +{
>>> +    *windows_available = 1;
>>> +    *page_size_mask = DDW_PGSIZE_64K | DDW_PGSIZE_16M;
>>> +
>>> +    return 0;
>>
>> What exactly does this return? The number of still available windows?
>> The total number of windows?
> 
> 1. Number of available windows
> 2. page masks supported for new windows.
> 
> This is what RTAS's counterpart does. We can change it to something better
> if we want but I cannot think of anything better.

The reason I'm asking is that I don't quite grasp why we're always
returning 1 available window.

1 window is already taken by the default window, no? So "1" naturally
would mean no ddw window. If we ignore that one, what if I create 1 ddw
window? The call would still return 1, so could I create another one? If
I can, why didn't the call return 2 in the first place?


Alex
Alexey Kardashevskiy Sept. 11, 2014, 2:53 a.m. UTC | #4
On 09/11/2014 07:16 AM, Alexander Graf wrote:
> 
> 
> On 10.09.14 16:58, Alexey Kardashevskiy wrote:
>> On 09/10/2014 11:01 PM, Alexander Graf wrote:
>>>
>>>
>>> On 29.08.14 12:12, Alexey Kardashevskiy wrote:
>>>> This implements DDW for emulated PHB.
>>>>
>>>> This advertises the query/create/remove RTAS tokens in device tree.
>>>> This does not advertise the reset RTAS token though, will be added later.
>>>>
>>>> The "ddw" property is enabled by default on a PHB but for compatibility
>>>> pseries-2.1 machine disables it.
>>>>
>>>> Since QEMU does not implement any 64bit DMA capable device, this hack
>>>> has been used to enable 64bit DMA on E1000:
>>>>
>>>> diff --git a/hw/net/e1000.c b/hw/net/e1000.c
>>>> index 0fc29a0..131f80a 100644
>>>> --- a/hw/net/e1000.c
>>>> +++ b/hw/net/e1000.c
>>>> @@ -240,6 +240,7 @@ static const uint32_t mac_reg_init[] = {
>>>>      [STATUS] =  0x80000000 | E1000_STATUS_GIO_MASTER_ENABLE |
>>>>                  E1000_STATUS_ASDV | E1000_STATUS_MTXCKOK |
>>>>                  E1000_STATUS_SPEED_1000 | E1000_STATUS_FD |
>>>> +                E1000_STATUS_PCIX_MODE |
>>>>                  E1000_STATUS_LU,
>>>>      [MANC] =    E1000_MANC_EN_MNG2HOST | E1000_MANC_RCV_TCO_EN |
>>>>                  E1000_MANC_ARP_EN | E1000_MANC_0298_EN |
>>>>
>>>> Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
>>>> ---
>>>> Changes:
>>>> v3:
>>>> * removed reset
>>>> * windows_num is now 1 or bigger rather than 0-based value and it is only
>>>> changed in PHB code, not in RTAS
>>>> * added page mask check in create()
>>>>
>>>> v2:
>>>> * tested on hacked emulated E1000
>>>> * implemented DDW reset on the PHB reset
>>>> * spapr_pci_ddw_remove/spapr_pci_ddw_reset are public for reuse by VFIO
>>>> ---
>>>>  hw/ppc/spapr.c              |  9 +++++
>>>>  hw/ppc/spapr_pci.c          | 94 +++++++++++++++++++++++++++++++++++++++++++++
>>>>  include/hw/pci-host/spapr.h |  7 ++++
>>>>  3 files changed, 110 insertions(+)
>>>>
>>>> diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
>>>> index d2d3c27..663cb75 100644
>>>> --- a/hw/ppc/spapr.c
>>>> +++ b/hw/ppc/spapr.c
>>>> @@ -1670,11 +1670,20 @@ static const TypeInfo spapr_machine_info = {
>>>>  static void spapr_machine_2_1_class_init(ObjectClass *oc, void *data)
>>>>  {
>>>>      MachineClass *mc = MACHINE_CLASS(oc);
>>>> +    static GlobalProperty compat_props[] = {
>>>> +        {
>>>> +            .driver   = TYPE_SPAPR_PCI_HOST_BRIDGE,
>>>> +            .property = "ddw",
>>>> +            .value    = stringify(off),
>>>> +        },
>>>> +        { /* end of list */ }
>>>> +    };
>>>>  
>>>>      mc->name = "pseries-2.1";
>>>>      mc->desc = "pSeries Logical Partition (PAPR compliant) v2.1";
>>>>      mc->alias = "pseries";
>>>>      mc->is_default = 1;
>>>> +    mc->compat_props = compat_props;
>>>>  }
>>>>  
>>>>  static const TypeInfo spapr_machine_2_1_info = {
>>>> diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
>>>> index 2968b39..04ee1dc 100644
>>>> --- a/hw/ppc/spapr_pci.c
>>>> +++ b/hw/ppc/spapr_pci.c
>>>> @@ -470,6 +470,76 @@ static const MemoryRegionOps spapr_msi_ops = {
>>>>  };
>>>>  
>>>>  /*
>>>> + * Dynamic DMA windows
>>>> + */
>>>> +static int spapr_pci_ddw_query(sPAPRPHBState *sphb,
>>>> +                               uint32_t *windows_available,
>>>> +                               uint32_t *page_size_mask)
>>>> +{
>>>> +    *windows_available = 1;
>>>> +    *page_size_mask = DDW_PGSIZE_64K | DDW_PGSIZE_16M;
>>>> +
>>>> +    return 0;
>>>
>>> What exactly does this return? The number of still available windows?
>>> The total number of windows?
>>
>> 1. Number of available windows
>> 2. page masks supported for new windows.
>>
>> This is what RTAS's counterpart does. We can change it to something better
>> if we want but I cannot think of anything better.
> 
> The reason I'm asking is that I don't quite grasp why we're always
> returning 1 available window.


Oh. I see it now. Bug. Should 1 or 0 depending on whether big window was
created or not.

> 1 window is already taken by the default window, no? So "1" naturally
> would mean no ddw window. If we ignore that one, what if I create 1 ddw
> window? The call would still return 1, so could I create another one? If
> I can, why didn't the call return 2 in the first place?

"1" means 1 additional window can be created. It does not return "2"
because the default window is always there. When/If I enable "pe-dma-reset"
RTAS call, then the guest will be able to remove default DMA window and
then spapr_pci_ddw_query() will start returning "2" after the default
window is removed.
David Gibson Sept. 26, 2014, 5:39 a.m. UTC | #5
On Fri, Aug 29, 2014 at 08:12:17PM +1000, Alexey Kardashevskiy wrote:
> This implements DDW for emulated PHB.
> 
> This advertises the query/create/remove RTAS tokens in device tree.
> This does not advertise the reset RTAS token though, will be added later.
> 
> The "ddw" property is enabled by default on a PHB but for compatibility
> pseries-2.1 machine disables it.
> 
> Since QEMU does not implement any 64bit DMA capable device, this hack
> has been used to enable 64bit DMA on E1000:
> 
> diff --git a/hw/net/e1000.c b/hw/net/e1000.c
> index 0fc29a0..131f80a 100644
> --- a/hw/net/e1000.c
> +++ b/hw/net/e1000.c
> @@ -240,6 +240,7 @@ static const uint32_t mac_reg_init[] = {
>      [STATUS] =  0x80000000 | E1000_STATUS_GIO_MASTER_ENABLE |
>                  E1000_STATUS_ASDV | E1000_STATUS_MTXCKOK |
>                  E1000_STATUS_SPEED_1000 | E1000_STATUS_FD |
> +                E1000_STATUS_PCIX_MODE |
>                  E1000_STATUS_LU,
>      [MANC] =    E1000_MANC_EN_MNG2HOST | E1000_MANC_RCV_TCO_EN |
>                  E1000_MANC_ARP_EN | E1000_MANC_0298_EN |
> 
> Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
> ---
> Changes:
> v3:
> * removed reset
> * windows_num is now 1 or bigger rather than 0-based value and it is only
> changed in PHB code, not in RTAS
> * added page mask check in create()
> 
> v2:
> * tested on hacked emulated E1000
> * implemented DDW reset on the PHB reset
> * spapr_pci_ddw_remove/spapr_pci_ddw_reset are public for reuse by VFIO
> ---
>  hw/ppc/spapr.c              |  9 +++++
>  hw/ppc/spapr_pci.c          | 94 +++++++++++++++++++++++++++++++++++++++++++++
>  include/hw/pci-host/spapr.h |  7 ++++
>  3 files changed, 110 insertions(+)
> 
> diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
> index d2d3c27..663cb75 100644
> --- a/hw/ppc/spapr.c
> +++ b/hw/ppc/spapr.c
> @@ -1670,11 +1670,20 @@ static const TypeInfo spapr_machine_info = {
>  static void spapr_machine_2_1_class_init(ObjectClass *oc, void *data)
>  {
>      MachineClass *mc = MACHINE_CLASS(oc);
> +    static GlobalProperty compat_props[] = {
> +        {
> +            .driver   = TYPE_SPAPR_PCI_HOST_BRIDGE,
> +            .property = "ddw",
> +            .value    = stringify(off),
> +        },
> +        { /* end of list */ }
> +    };
>  
>      mc->name = "pseries-2.1";
>      mc->desc = "pSeries Logical Partition (PAPR compliant) v2.1";
>      mc->alias = "pseries";
>      mc->is_default = 1;
> +    mc->compat_props = compat_props;
>  }
>  
>  static const TypeInfo spapr_machine_2_1_info = {
> diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
> index 2968b39..04ee1dc 100644
> --- a/hw/ppc/spapr_pci.c
> +++ b/hw/ppc/spapr_pci.c
> @@ -470,6 +470,76 @@ static const MemoryRegionOps spapr_msi_ops = {
>  };
>  
>  /*
> + * Dynamic DMA windows
> + */
> +static int spapr_pci_ddw_query(sPAPRPHBState *sphb,
> +                               uint32_t *windows_available,
> +                               uint32_t *page_size_mask)
> +{
> +    *windows_available = 1;
> +    *page_size_mask = DDW_PGSIZE_64K | DDW_PGSIZE_16M;
> +
> +    return 0;
> +}
> +
> +static int spapr_pci_ddw_create(sPAPRPHBState *sphb, uint32_t page_shift,
> +                                uint32_t window_shift, uint32_t liobn,
> +                                sPAPRTCETable **ptcet)
> +{

I think the callbacks should check the ddw_enabled parameter and fail
if ddw is disabled, rather than just relying on the guest not calling
them if they're not advertised.
diff mbox

Patch

diff --git a/hw/net/e1000.c b/hw/net/e1000.c
index 0fc29a0..131f80a 100644
--- a/hw/net/e1000.c
+++ b/hw/net/e1000.c
@@ -240,6 +240,7 @@  static const uint32_t mac_reg_init[] = {
     [STATUS] =  0x80000000 | E1000_STATUS_GIO_MASTER_ENABLE |
                 E1000_STATUS_ASDV | E1000_STATUS_MTXCKOK |
                 E1000_STATUS_SPEED_1000 | E1000_STATUS_FD |
+                E1000_STATUS_PCIX_MODE |
                 E1000_STATUS_LU,
     [MANC] =    E1000_MANC_EN_MNG2HOST | E1000_MANC_RCV_TCO_EN |
                 E1000_MANC_ARP_EN | E1000_MANC_0298_EN |

Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
---
Changes:
v3:
* removed reset
* windows_num is now 1 or bigger rather than 0-based value and it is only
changed in PHB code, not in RTAS
* added page mask check in create()

v2:
* tested on hacked emulated E1000
* implemented DDW reset on the PHB reset
* spapr_pci_ddw_remove/spapr_pci_ddw_reset are public for reuse by VFIO
---
 hw/ppc/spapr.c              |  9 +++++
 hw/ppc/spapr_pci.c          | 94 +++++++++++++++++++++++++++++++++++++++++++++
 include/hw/pci-host/spapr.h |  7 ++++
 3 files changed, 110 insertions(+)

diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index d2d3c27..663cb75 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -1670,11 +1670,20 @@  static const TypeInfo spapr_machine_info = {
 static void spapr_machine_2_1_class_init(ObjectClass *oc, void *data)
 {
     MachineClass *mc = MACHINE_CLASS(oc);
+    static GlobalProperty compat_props[] = {
+        {
+            .driver   = TYPE_SPAPR_PCI_HOST_BRIDGE,
+            .property = "ddw",
+            .value    = stringify(off),
+        },
+        { /* end of list */ }
+    };
 
     mc->name = "pseries-2.1";
     mc->desc = "pSeries Logical Partition (PAPR compliant) v2.1";
     mc->alias = "pseries";
     mc->is_default = 1;
+    mc->compat_props = compat_props;
 }
 
 static const TypeInfo spapr_machine_2_1_info = {
diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index 2968b39..04ee1dc 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -470,6 +470,76 @@  static const MemoryRegionOps spapr_msi_ops = {
 };
 
 /*
+ * Dynamic DMA windows
+ */
+static int spapr_pci_ddw_query(sPAPRPHBState *sphb,
+                               uint32_t *windows_available,
+                               uint32_t *page_size_mask)
+{
+    *windows_available = 1;
+    *page_size_mask = DDW_PGSIZE_64K | DDW_PGSIZE_16M;
+
+    return 0;
+}
+
+static int spapr_pci_ddw_create(sPAPRPHBState *sphb, uint32_t page_shift,
+                                uint32_t window_shift, uint32_t liobn,
+                                sPAPRTCETable **ptcet)
+{
+    if ((page_shift != 16) && (page_shift != 24)) {
+        return -1;
+    }
+
+    *ptcet = spapr_tce_new_table(DEVICE(sphb), liobn,
+                                 SPAPR_PCI_TCE64_START, page_shift,
+                                 1ULL << (window_shift - page_shift),
+                                 true);
+    if (!*ptcet) {
+        return -1;
+    }
+    memory_region_add_subregion(&sphb->iommu_root, (*ptcet)->bus_offset,
+                                spapr_tce_get_iommu(*ptcet));
+
+    ++sphb->windows_num;
+
+    return 0;
+}
+
+int spapr_pci_ddw_remove(sPAPRPHBState *sphb, sPAPRTCETable *tcet)
+{
+    memory_region_del_subregion(&sphb->iommu_root,
+                                spapr_tce_get_iommu(tcet));
+    spapr_tce_free_table(tcet);
+
+    return 0;
+}
+
+static int spapr_pci_remove_ddw_cb(Object *child, void *opaque)
+{
+    sPAPRTCETable *tcet;
+
+    tcet = (sPAPRTCETable *) object_dynamic_cast(child, TYPE_SPAPR_TCE_TABLE);
+
+    /* Delete all dynamic windows, i.e. every except the default one with #0 */
+    if (tcet && SPAPR_PCI_DMA_WINDOW_NUM(tcet->liobn)) {
+        sPAPRPHBState *sphb = opaque;
+        sPAPRPHBClass *spc = SPAPR_PCI_HOST_BRIDGE_GET_CLASS(sphb);
+
+        spc->ddw_remove(sphb, tcet);
+    }
+
+    return 0;
+}
+
+int spapr_pci_ddw_reset(sPAPRPHBState *sphb)
+{
+    object_child_foreach(OBJECT(sphb), spapr_pci_remove_ddw_cb, sphb);
+    sphb->windows_num = 1;
+
+    return 0;
+}
+
+/*
  * PHB PCI device
  */
 static AddressSpace *spapr_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn)
@@ -668,6 +738,12 @@  static int spapr_phb_children_reset(Object *child, void *opaque)
 
 static void spapr_phb_reset(DeviceState *qdev)
 {
+    sPAPRPHBClass *spc = SPAPR_PCI_HOST_BRIDGE_GET_CLASS(qdev);
+
+    if (spc->ddw_reset) {
+        spc->ddw_reset(SPAPR_PCI_HOST_BRIDGE(qdev));
+    }
+
     /* Reset the IOMMU state */
     object_child_foreach(OBJECT(qdev), spapr_phb_children_reset, NULL);
 }
@@ -682,6 +758,7 @@  static Property spapr_phb_properties[] = {
     DEFINE_PROP_UINT64("io_win_addr", sPAPRPHBState, io_win_addr, -1),
     DEFINE_PROP_UINT64("io_win_size", sPAPRPHBState, io_win_size,
                        SPAPR_PCI_IO_WIN_SIZE),
+    DEFINE_PROP_BOOL("ddw", sPAPRPHBState, ddw_enabled, true),
     DEFINE_PROP_END_OF_LIST(),
 };
 
@@ -799,6 +876,10 @@  static void spapr_phb_class_init(ObjectClass *klass, void *data)
     set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
     dc->cannot_instantiate_with_device_add_yet = false;
     spc->finish_realize = spapr_phb_finish_realize;
+    spc->ddw_query = spapr_pci_ddw_query;
+    spc->ddw_create = spapr_pci_ddw_create;
+    spc->ddw_remove = spapr_pci_ddw_remove;
+    spc->ddw_reset = spapr_pci_ddw_reset;
 }
 
 static const TypeInfo spapr_phb_info = {
@@ -882,6 +963,12 @@  int spapr_populate_pci_dt(sPAPRPHBState *phb,
     uint32_t interrupt_map_mask[] = {
         cpu_to_be32(b_ddddd(-1)|b_fff(0)), 0x0, 0x0, cpu_to_be32(-1)};
     uint32_t interrupt_map[PCI_SLOT_MAX * PCI_NUM_PINS][7];
+    uint32_t ddw_applicable[] = {
+        RTAS_IBM_QUERY_PE_DMA_WINDOW,
+        RTAS_IBM_CREATE_PE_DMA_WINDOW,
+        RTAS_IBM_REMOVE_PE_DMA_WINDOW
+    };
+    sPAPRPHBClass *spc = SPAPR_PCI_HOST_BRIDGE_GET_CLASS(phb);
 
     /* Start populating the FDT */
     sprintf(nodename, "pci@%" PRIx64, phb->buid);
@@ -911,6 +998,13 @@  int spapr_populate_pci_dt(sPAPRPHBState *phb,
     _FDT(fdt_setprop_cell(fdt, bus_off, "ibm,pci-config-space-type", 0x1));
     _FDT(fdt_setprop_cell(fdt, bus_off, "ibm,pe-total-#msi", XICS_IRQS));
 
+    /* Dynamic DMA window */
+    if (phb->ddw_enabled &&
+        spc->ddw_query && spc->ddw_create && spc->ddw_remove) {
+        _FDT(fdt_setprop(fdt, bus_off, "ibm,ddw-applicable", &ddw_applicable,
+                         sizeof(ddw_applicable)));
+    }
+
     /* Build the interrupt-map, this must matches what is done
      * in pci_spapr_map_irq
      */
diff --git a/include/hw/pci-host/spapr.h b/include/hw/pci-host/spapr.h
index 07b60c3..01b3d25 100644
--- a/include/hw/pci-host/spapr.h
+++ b/include/hw/pci-host/spapr.h
@@ -104,6 +104,8 @@  struct sPAPRPHBState {
     int32_t msi_devs_num;
     spapr_pci_msi_mig *msi_devs;
 
+    bool ddw_enabled;
+
     QLIST_ENTRY(sPAPRPHBState) list;
 };
 
@@ -126,6 +128,9 @@  struct sPAPRPHBVFIOState {
 
 #define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL
 
+/* Default 64bit dynamic window offset */
+#define SPAPR_PCI_TCE64_START        0x8000000000000000ULL
+
 static inline qemu_irq spapr_phb_lsi_qirq(struct sPAPRPHBState *phb, int pin)
 {
     return xics_get_qirq(spapr->icp, phb->lsi_table[pin].irq);
@@ -144,5 +149,7 @@  void spapr_pci_rtas_init(void);
 sPAPRPHBState *spapr_pci_find_phb(sPAPREnvironment *spapr, uint64_t buid);
 PCIDevice *spapr_pci_find_dev(sPAPREnvironment *spapr, uint64_t buid,
                               uint32_t config_addr);
+int spapr_pci_ddw_remove(sPAPRPHBState *sphb, sPAPRTCETable *tcet);
+int spapr_pci_ddw_reset(sPAPRPHBState *sphb);
 
 #endif /* __HW_SPAPR_PCI_H__ */