<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="Generator" content="Microsoft Word 15 (filtered medium)">
<style><!--
/* Font Definitions */
@font-face
        {font-family:"Cambria Math";
        panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
        {font-family:DengXian;
        panose-1:2 1 6 0 3 1 1 1 1 1;}
@font-face
        {font-family:Calibri;
        panose-1:2 15 5 2 2 2 4 3 2 4;}
@font-face
        {font-family:"\@DengXian";
        panose-1:2 1 6 0 3 1 1 1 1 1;}
@font-face
        {font-family:Tahoma;
        panose-1:2 11 6 4 3 5 4 4 2 4;}
@font-face
        {font-family:"Microsoft YaHei";
        panose-1:2 11 5 3 2 2 4 2 2 4;}
@font-face
        {font-family:"\@Microsoft YaHei";}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
        {margin:0cm;
        font-size:11.0pt;
        font-family:"Calibri",sans-serif;}
a:link, span.MsoHyperlink
        {mso-style-priority:99;
        color:#0563C1;
        text-decoration:underline;}
span.EmailStyle19
        {mso-style-type:personal-reply;
        font-family:"Calibri",sans-serif;
        color:windowtext;}
.MsoChpDefault
        {mso-style-type:export-only;
        font-family:"Calibri",sans-serif;
        mso-ligatures:none;}
@page WordSection1
        {size:612.0pt 792.0pt;
        margin:72.0pt 72.0pt 72.0pt 72.0pt;}
div.WordSection1
        {page:WordSection1;}
--></style><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext="edit" spidmax="1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1" />
</o:shapelayout></xml><![endif]-->
</head>
<body lang="EN-CA" link="#0563C1" vlink="#954F72" style="word-wrap:break-word">
<div class="WordSection1">
<p class="MsoNormal">Hi Chunming,<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">In this email thread, Christian mentioned a very special virtualization environment where multiple guess processes relies on a host proxy process to talk to kfd. Such setup has a hard confliction with SVM concept as SVM means shared virtual
 address space in *one* process while the host proxy process in this setup need to represent multiple guest process. Thus SVM doesn’t work in such setup.<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">Normal GPU virtualization such as SRIOV, or system virtualization (such as passing whole GPU device to guest machine), works perfectly fine with SVM design.<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">Regards,<o:p></o:p></p>
<p class="MsoNormal">Oak<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<div style="border:none;border-left:solid blue 1.5pt;padding:0cm 0cm 0cm 4.0pt">
<div>
<div style="border:none;border-top:solid #E1E1E1 1.0pt;padding:3.0pt 0cm 0cm 0cm">
<p class="MsoNormal"><b><span lang="EN-US">From:</span></b><span lang="EN-US"> </span>
<span lang="ZH-CN" style="font-family:"Microsoft YaHei",sans-serif">周春明</span><span lang="EN-US">(</span><span lang="ZH-CN" style="font-family:"Microsoft YaHei",sans-serif">日月</span><span lang="EN-US">) <riyue.zcm@alibaba-inc.com>
<br>
<b>Sent:</b> Monday, January 29, 2024 10:55 PM<br>
<b>To:</b> Felix Kuehling <felix.kuehling@amd.com>; Christian König <christian.koenig@amd.com>; Daniel Vetter <daniel@ffwll.ch><br>
<b>Cc:</b> Brost, Matthew <matthew.brost@intel.com>; Thomas.Hellstrom@linux.intel.com; Welty, Brian <brian.welty@intel.com>; Ghimiray, Himal Prasad <himal.prasad.ghimiray@intel.com>; dri-devel@lists.freedesktop.org; Gupta, saurabhg <saurabhg.gupta@intel.com>;
 Danilo Krummrich <dakr@redhat.com>; Zeng, Oak <oak.zeng@intel.com>; Bommu, Krishnaiah <krishnaiah.bommu@intel.com>; Dave Airlie <airlied@redhat.com>; Vishwanathapura, Niranjana <niranjana.vishwanathapura@intel.com>; intel-xe@lists.freedesktop.org;
</span><span lang="ZH-CN" style="font-family:"Microsoft YaHei",sans-serif">毛钧</span><span lang="EN-US">(</span><span lang="ZH-CN" style="font-family:"Microsoft YaHei",sans-serif">落提</span><span lang="EN-US">) <luoti.mj@alibaba-inc.com><br>
<b>Subject:</b> re</span><span lang="ZH-CN" style="font-family:"Microsoft YaHei",sans-serif">:</span><span lang="EN-US">Making drm_gpuvm work across gpu devices<o:p></o:p></span></p>
</div>
</div>
<p class="MsoNormal"><o:p> </o:p></p>
<div>
<div>
<div>
<p class="MsoNormal"><span style="font-size:10.5pt;font-family:"Tahoma",sans-serif;color:black"><o:p> </o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:10.5pt;font-family:"Tahoma",sans-serif;color:black">Hi Felix,<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:10.5pt;font-family:"Tahoma",sans-serif;color:black"><o:p> </o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:10.5pt;font-family:"Tahoma",sans-serif;color:black">Following your thread, you mentioned many times that SVM API cannot run in virtualization env, I still don't get it why.<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:10.5pt;font-family:"Tahoma",sans-serif;color:black">Why you often said need a host proxy process? Cannot HW report page fault interrupt per VF via vfid? Isn't it sriov env?<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:10.5pt;font-family:"Tahoma",sans-serif;color:black"><o:p> </o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:10.5pt;font-family:"Tahoma",sans-serif;color:black">Regargs,<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:10.5pt;font-family:"Tahoma",sans-serif;color:black">-Chunming<o:p></o:p></span></p>
</div>
<blockquote style="margin-right:0cm">
<div>
<p class="MsoNormal"><span style="font-size:10.5pt;font-family:"Tahoma",sans-serif;color:black">------------------------------------------------------------------<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span lang="ZH-CN" style="font-size:10.5pt;font-family:DengXian;color:black">发件人:</span><span style="font-size:10.5pt;font-family:"Tahoma",sans-serif;color:black">Felix Kuehling <<a href="mailto:felix.kuehling@amd.com">felix.kuehling@amd.com</a>><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span lang="ZH-CN" style="font-size:10.5pt;font-family:DengXian;color:black">发送时间:</span><span style="font-size:10.5pt;font-family:"Tahoma",sans-serif;color:black">2024</span><span lang="ZH-CN" style="font-size:10.5pt;font-family:DengXian;color:black">年</span><span style="font-size:10.5pt;font-family:"Tahoma",sans-serif;color:black">1</span><span lang="ZH-CN" style="font-size:10.5pt;font-family:DengXian;color:black">月</span><span style="font-size:10.5pt;font-family:"Tahoma",sans-serif;color:black">30</span><span lang="ZH-CN" style="font-size:10.5pt;font-family:DengXian;color:black">日</span><span style="font-size:10.5pt;font-family:"Tahoma",sans-serif;color:black">(</span><span lang="ZH-CN" style="font-size:10.5pt;font-family:DengXian;color:black">星期二</span><span style="font-size:10.5pt;font-family:"Tahoma",sans-serif;color:black">)
 04:24<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span lang="ZH-CN" style="font-size:10.5pt;font-family:DengXian;color:black">收件人:</span><span style="font-size:10.5pt;font-family:"Tahoma",sans-serif;color:black">"Christian König" <<a href="mailto:christian.koenig@amd.com">christian.koenig@amd.com</a>>;
 Daniel Vetter <<a href="mailto:daniel@ffwll.ch">daniel@ffwll.ch</a>><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span lang="ZH-CN" style="font-size:10.5pt;font-family:DengXian;color:black">抄 送:</span><span style="font-size:10.5pt;font-family:"Tahoma",sans-serif;color:black">"Brost, Matthew" <<a href="mailto:matthew.brost@intel.com">matthew.brost@intel.com</a>>;
<a href="mailto:Thomas.Hellstrom@linux.intel.com">Thomas.Hellstrom@linux.intel.com</a> <<a href="mailto:Thomas.Hellstrom@linux.intel.com">Thomas.Hellstrom@linux.intel.com</a>>; "Welty, Brian" <<a href="mailto:brian.welty@intel.com">brian.welty@intel.com</a>>;
 "Ghimiray, Himal Prasad" <<a href="mailto:himal.prasad.ghimiray@intel.com">himal.prasad.ghimiray@intel.com</a>>;
<a href="mailto:dri-devel@lists.freedesktop.org">dri-devel@lists.freedesktop.org</a> <<a href="mailto:dri-devel@lists.freedesktop.org">dri-devel@lists.freedesktop.org</a>>; "Gupta, saurabhg" <<a href="mailto:saurabhg.gupta@intel.com">saurabhg.gupta@intel.com</a>>;
 Danilo Krummrich <<a href="mailto:dakr@redhat.com">dakr@redhat.com</a>>; "Zeng, Oak" <<a href="mailto:oak.zeng@intel.com">oak.zeng@intel.com</a>>; "Bommu, Krishnaiah" <<a href="mailto:krishnaiah.bommu@intel.com">krishnaiah.bommu@intel.com</a>>; Dave Airlie
 <<a href="mailto:airlied@redhat.com">airlied@redhat.com</a>>; "Vishwanathapura, Niranjana" <<a href="mailto:niranjana.vishwanathapura@intel.com">niranjana.vishwanathapura@intel.com</a>>;
<a href="mailto:intel-xe@lists.freedesktop.org">intel-xe@lists.freedesktop.org</a> <<a href="mailto:intel-xe@lists.freedesktop.org">intel-xe@lists.freedesktop.org</a>><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span lang="ZH-CN" style="font-size:10.5pt;font-family:DengXian;color:black">主 题:</span><span style="font-size:10.5pt;font-family:"Tahoma",sans-serif;color:black">Re: Making drm_gpuvm work across gpu devices<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:10.5pt;font-family:"Tahoma",sans-serif;color:black"><o:p> </o:p></span></p>
</div>
<p class="MsoNormal"><span style="font-size:10.5pt;font-family:"Tahoma",sans-serif;color:black"><br>
On 2024-01-29 14:03, Christian König wrote:<br>
> Am 29.01.24 um 18:52 schrieb Felix Kuehling:<br>
>> On 2024-01-29 11:28, Christian König wrote:<br>
>>> Am 29.01.24 um 17:24 schrieb Felix Kuehling:<br>
>>>> On 2024-01-29 10:33, Christian König wrote:<br>
>>>>> Am 29.01.24 um 16:03 schrieb Felix Kuehling:<br>
>>>>>> On 2024-01-25 13:32, Daniel Vetter wrote:<br>
>>>>>>> On Wed, Jan 24, 2024 at 09:33:12AM +0100, Christian König wrote:<br>
>>>>>>>> Am 23.01.24 um 20:37 schrieb Zeng, Oak:<br>
>>>>>>>>> [SNIP]<br>
>>>>>>>>> Yes most API are per device based.<br>
>>>>>>>>><br>
>>>>>>>>> One exception I know is actually the kfd SVM API. If you look <br>
>>>>>>>>> at the svm_ioctl function, it is per-process based. Each <br>
>>>>>>>>> kfd_process represent a process across N gpu devices.<br>
>>>>>>>> Yeah and that was a big mistake in my opinion. We should really <br>
>>>>>>>> not do that<br>
>>>>>>>> ever again.<br>
>>>>>>>><br>
>>>>>>>>> Need to say, kfd SVM represent a shared virtual address space <br>
>>>>>>>>> across CPU and all GPU devices on the system. This is by the <br>
>>>>>>>>> definition of SVM (shared virtual memory). This is very <br>
>>>>>>>>> different from our legacy gpu *device* driver which works for <br>
>>>>>>>>> only one device (i.e., if you want one device to access <br>
>>>>>>>>> another device's memory, you will have to use dma-buf <br>
>>>>>>>>> export/import etc).<br>
>>>>>>>> Exactly that thinking is what we have currently found as <br>
>>>>>>>> blocker for a<br>
>>>>>>>> virtualization projects. Having SVM as device independent <br>
>>>>>>>> feature which<br>
>>>>>>>> somehow ties to the process address space turned out to be an <br>
>>>>>>>> extremely bad<br>
>>>>>>>> idea.<br>
>>>>>>>><br>
>>>>>>>> The background is that this only works for some use cases but <br>
>>>>>>>> not all of<br>
>>>>>>>> them.<br>
>>>>>>>><br>
>>>>>>>> What's working much better is to just have a mirror <br>
>>>>>>>> functionality which says<br>
>>>>>>>> that a range A..B of the process address space is mapped into a <br>
>>>>>>>> range C..D<br>
>>>>>>>> of the GPU address space.<br>
>>>>>>>><br>
>>>>>>>> Those ranges can then be used to implement the SVM feature <br>
>>>>>>>> required for<br>
>>>>>>>> higher level APIs and not something you need at the UAPI or <br>
>>>>>>>> even inside the<br>
>>>>>>>> low level kernel memory management.<br>
>>>>>>>><br>
>>>>>>>> When you talk about migrating memory to a device you also do <br>
>>>>>>>> this on a per<br>
>>>>>>>> device basis and *not* tied to the process address space. If <br>
>>>>>>>> you then get<br>
>>>>>>>> crappy performance because userspace gave contradicting <br>
>>>>>>>> information where to<br>
>>>>>>>> migrate memory then that's a bug in userspace and not something <br>
>>>>>>>> the kernel<br>
>>>>>>>> should try to prevent somehow.<br>
>>>>>>>><br>
>>>>>>>> [SNIP]<br>
>>>>>>>>>> I think if you start using the same drm_gpuvm for multiple <br>
>>>>>>>>>> devices you<br>
>>>>>>>>>> will sooner or later start to run into the same mess we have <br>
>>>>>>>>>> seen with<br>
>>>>>>>>>> KFD, where we moved more and more functionality from the KFD <br>
>>>>>>>>>> to the DRM<br>
>>>>>>>>>> render node because we found that a lot of the stuff simply <br>
>>>>>>>>>> doesn't work<br>
>>>>>>>>>> correctly with a single object to maintain the state.<br>
>>>>>>>>> As I understand it, KFD is designed to work across devices. A <br>
>>>>>>>>> single pseudo /dev/kfd device represent all hardware gpu <br>
>>>>>>>>> devices. That is why during kfd open, many pdd (process device <br>
>>>>>>>>> data) is created, each for one hardware device for this process.<br>
>>>>>>>> Yes, I'm perfectly aware of that. And I can only repeat myself <br>
>>>>>>>> that I see<br>
>>>>>>>> this design as a rather extreme failure. And I think it's one <br>
>>>>>>>> of the reasons<br>
>>>>>>>> why NVidia is so dominant with Cuda.<br>
>>>>>>>><br>
>>>>>>>> This whole approach KFD takes was designed with the idea of <br>
>>>>>>>> extending the<br>
>>>>>>>> CPU process into the GPUs, but this idea only works for a few <br>
>>>>>>>> use cases and<br>
>>>>>>>> is not something we should apply to drivers in general.<br>
>>>>>>>><br>
>>>>>>>> A very good example are virtualization use cases where you end <br>
>>>>>>>> up with CPU<br>
>>>>>>>> address != GPU address because the VAs are actually coming from <br>
>>>>>>>> the guest VM<br>
>>>>>>>> and not the host process.<br>
>>>>>>>><br>
>>>>>>>> SVM is a high level concept of OpenCL, Cuda, ROCm etc.. This <br>
>>>>>>>> should not have<br>
>>>>>>>> any influence on the design of the kernel UAPI.<br>
>>>>>>>><br>
>>>>>>>> If you want to do something similar as KFD for Xe I think you <br>
>>>>>>>> need to get<br>
>>>>>>>> explicit permission to do this from Dave and Daniel and maybe <br>
>>>>>>>> even Linus.<br>
>>>>>>> I think the one and only one exception where an SVM uapi like in <br>
>>>>>>> kfd makes<br>
>>>>>>> sense, is if the _hardware_ itself, not the software stack defined<br>
>>>>>>> semantics that you've happened to build on top of that hw, <br>
>>>>>>> enforces a 1:1<br>
>>>>>>> mapping with the cpu process address space.<br>
>>>>>>><br>
>>>>>>> Which means your hardware is using PASID, IOMMU based <br>
>>>>>>> translation, PCI-ATS<br>
>>>>>>> (address translation services) or whatever your hw calls it and <br>
>>>>>>> has _no_<br>
>>>>>>> device-side pagetables on top. Which from what I've seen all <br>
>>>>>>> devices with<br>
>>>>>>> device-memory have, simply because they need some place to store <br>
>>>>>>> whether<br>
>>>>>>> that memory is currently in device memory or should be <br>
>>>>>>> translated using<br>
>>>>>>> PASID. Currently there's no gpu that works with PASID only, but <br>
>>>>>>> there are<br>
>>>>>>> some on-cpu-die accelerator things that do work like that.<br>
>>>>>>><br>
>>>>>>> Maybe in the future there will be some accelerators that are <br>
>>>>>>> fully cpu<br>
>>>>>>> cache coherent (including atomics) with something like CXL, and the<br>
>>>>>>> on-device memory is managed as normal system memory with struct <br>
>>>>>>> page as<br>
>>>>>>> ZONE_DEVICE and accelerator va -> physical address translation <br>
>>>>>>> is only<br>
>>>>>>> done with PASID ... but for now I haven't seen that, definitely <br>
>>>>>>> not in<br>
>>>>>>> upstream drivers.<br>
>>>>>>><br>
>>>>>>> And the moment you have some per-device pagetables or per-device <br>
>>>>>>> memory<br>
>>>>>>> management of some sort (like using gpuva mgr) then I'm 100% <br>
>>>>>>> agreeing with<br>
>>>>>>> Christian that the kfd SVM model is too strict and not a great <br>
>>>>>>> idea.<br>
>>>>>><br>
>>>>>> That basically means, without ATS/PRI+PASID you cannot implement <br>
>>>>>> a unified memory programming model, where GPUs or accelerators <br>
>>>>>> access virtual addresses without pre-registering them with an SVM <br>
>>>>>> API call.<br>
>>>>>><br>
>>>>>> Unified memory is a feature implemented by the KFD SVM API and <br>
>>>>>> used by ROCm. This is used e.g. to implement OpenMP USM (unified <br>
>>>>>> shared memory). It's implemented with recoverable GPU page <br>
>>>>>> faults. If the page fault interrupt handler cannot assume a <br>
>>>>>> shared virtual address space, then implementing this feature <br>
>>>>>> isn't possible.<br>
>>>>><br>
>>>>> Why not? As far as I can see the OpenMP USM is just another funky <br>
>>>>> way of userptr handling.<br>
>>>>><br>
>>>>> The difference is that in an userptr we assume that we always need <br>
>>>>> to request the whole block A..B from a mapping while for page <br>
>>>>> fault based handling it can be just any page in between A and B <br>
>>>>> which is requested and made available to the GPU address space.<br>
>>>>><br>
>>>>> As far as I can see there is absolutely no need for any special <br>
>>>>> SVM handling.<br>
>>>><br>
>>>> It does assume a shared virtual address space between CPU and GPUs. <br>
>>>> There are no API calls to tell the driver that address A on the CPU <br>
>>>> maps to address B on the GPU1 and address C on GPU2. The KFD SVM <br>
>>>> API was designed to work with this programming model, by augmenting <br>
>>>> the shared virtual address mappings with virtual address range <br>
>>>> attributes that can modify the migration policy and indicate <br>
>>>> prefetching, prefaulting, etc. You could think of it as madvise on <br>
>>>> steroids.<br>
>>><br>
>>> Yeah, so what? In this case you just say through an IOCTL that CPU <br>
>>> range A..B should map to GPU range C..D and for A/B and C/D you use <br>
>>> the maximum of the address space.<br>
>><br>
>> What I want is that address range A..B on the CPU matches A..B on the <br>
>> GPU, because I'm sharing pointers between CPU and GPU. I can't think <br>
>> of any sane user mode using a unified memory programming model, that <br>
>> would ever ask KFD to map unified memory mappints to a different <br>
>> address range on the GPU. Adding such an ioclt is a complete waste of <br>
>> time, and can only serve to add unnecessary complexity.<br>
><br>
> This is exactly the use case which happens when the submitting process <br>
> is not the one originally stitching together the command stream.<br>
><br>
> Basically all native context, virtualization and other proxy use cases <br>
> work like this.<br>
<br>
You cannot use unified memory in this type of environment. A GPU page <br>
fault would occur in a GPU virtual address space in the host-side proxy <br>
process. That page fault would need to be resolved to map some memory <br>
from a process running in a guest? Which guest? Which process? That's <br>
anyone's guess. There is no way to annotate that because the pointer in <br>
the fault is coming from a shader program that's running in the guest <br>
context and competely unaware of the virtualization. There are no API <br>
calls from the guest before the fault occurs to establish a meaningful <br>
mapping.<br>
<br>
The way this virtualization of the GPU is implemented, with out proxy <br>
multiplexing multiple clients is just fundamentally incompatible with a <br>
unified memory programming model that has to assume a shared virtual <br>
address space to make sense. You'd need separate proxy processes on the <br>
host side to handle that. You can't blame this on bad design decisions <br>
in the SVM API. As I see it, it's just a fundamental limitation of the <br>
virtualization approach that cannot handle guest applications that want <br>
to use a unified shared memory programming model.<br>
<br>
That's why I suggested to completely disable the SVM API in this <br>
virtualization scenario when you create a KFD context that's separate <br>
from the process address space. It is not essential for any <br>
non-unified-memory functionality. ROCm user mode has fallbacks to work <br>
without it, because we also needs to support older kernels and GPUs that <br>
didn't support this programming model.<br>
<br>
Regards,<br>
  Felix<br>
<br>
<br>
><br>
> So that the CPU address doesn't match the GPU address is an absolutely <br>
> real use case and should be able to be handled by the GPU VA interface.<br>
><br>
> Regards,<br>
> Christian.<br>
><br>
><br>
><br>
>><br>
>> Regards,<br>
>>   Felix<br>
>><br>
>><br>
>>><br>
>>> There is no restriction that this needs to be accurate in way. It's <br>
>>> just the it can be accurate to be more efficient and eventually use <br>
>>> only a fraction of the address space instead of all of it for some <br>
>>> use cases.<br>
>>><br>
>>> So this isn't a blocker, it's just one special use case.<br>
>>><br>
>>> Regards,<br>
>>> Christian.<br>
>>><br>
>>>><br>
>>>> Regards,<br>
>>>>   Felix<br>
>>>><br>
>>>><br>
>>>>><br>
>>>>> Regards,<br>
>>>>> Christian.<br>
>>>>><br>
>>>>>><br>
>>>>>> Regards,<br>
>>>>>>   Felix<br>
>>>>>><br>
>>>>>><br>
>>>>>>><br>
>>>>>>> Cheers, Sima<br>
>>>>><br>
>>><br>
><o:p></o:p></span></p>
</blockquote>
</div>
</div>
</div>
</div>
</body>
</html>