From: Jonathan Cameron <Jonathan.Cameron@huawei.com>
To: Arpit Kumar <arpit1.kumar@samsung.com>
Cc: <qemu-devel@nongnu.org>, <gost.dev@samsung.com>,
<linux-cxl@vger.kernel.org>, <nifan.cxl@gmail.com>,
<dave@stgolabs.net>, <vishak.g@samsung.com>,
<krish.reddy@samsung.com>, <a.manzanares@samsung.com>,
<alok.rathore@samsung.com>
Subject: Re: [PATCH 3/3] hw/cxl: Add Physical Port Control (Opcode 5102h)
Date: Tue, 10 Jun 2025 15:45:01 +0100 [thread overview]
Message-ID: <20250610154501.0000213b@huawei.com> (raw)
In-Reply-To: <20250602135942.2773823-4-arpit1.kumar@samsung.com>
On Mon, 2 Jun 2025 19:29:42 +0530
Arpit Kumar <arpit1.kumar@samsung.com> wrote:
Very interesting to see support for this. It will enable a load
of additional test cases.
> added assert-deassert PERST implementation, reset PPB
> for physical port.
Added
Please also include some details of testing done and what happens.
Given I know we have some issues with reset that we haven't resolved
I'm curious if you see them here.
>
> Signed-off-by: Arpit Kumar <arpit1.kumar@samsung.com>
> +/* Assert - Deassert PERST */
> +#define ASSERT_WAIT_TIME_MS 100
> +
> /* link state flags */
> #define LINK_STATE_FLAG_LANE_REVERSED (1 << 0)
> #define LINK_STATE_FLAG_PERST_ASSERTED (1 << 1)
> @@ -662,6 +666,114 @@ static CXLRetCode cmd_get_physical_port_state(const struct cxl_cmd *cmd,
> return CXL_MBOX_SUCCESS;
> }
>
> +static struct PCIDevice *cxl_find_port_dev(uint8_t ppb_id, PCIBus *bus)
> +{
> + PCIDevice *d;
> + int devfn;
> +
> + for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
As in patch one, maybe use the for_each_pci_... Though with the callback
needed it may end up slightly more complex that this.
> + d = bus->devices[devfn];
> + if (d) {
> + if (object_dynamic_cast(OBJECT(d), TYPE_CXL_DSP)) {
> + uint8_t port = PCIE_PORT(d)->port;
I'd not bother with the local variable for this one.
if (PCIE_PORT(d)->port == ppb_id) {
return d;
}
> + if (port == ppb_id) {
> + return d;
> + }
> + }
> + }
> + }
> + return NULL;
> +}
> +
> +static CXLRetCode deassert_PERST(Object *obj, ResetType type, uint8_t pn, CXLCCI *cci)
> +{
> + ResettableClass *rc = RESETTABLE_GET_CLASS(obj);
> + ResettableState *s = rc->get_state(obj);
> +
> + if (cci->pports.perst[pn].issued_assert_PERST) {
> + if (cci->pports.perst[pn].asrt_time == -1 && !s->hold_phase_pending) {
I'd flip the logic as then can return early in error case and reduce
indent of the rest.
> + qemu_mutex_lock(&cci->pports.perst[pn].lock);
QEMU_LOCK_GUARD(&cci->pports.prst[pn].lock);
> + resettable_release_reset(obj, type);
> + cci->pports.perst[pn].issued_assert_PERST = false;
> + cci->pports.pport_info[pn].link_state_flags &=
> + ~LINK_STATE_FLAG_PERST_ASSERTED;
> + cci->pports.perst[pn].asrt_time = ASSERT_WAIT_TIME_MS;
> + qemu_mutex_unlock(&cci->pports.perst[pn].lock);
and drop explicit unlock.
> + } else {
> + return CXL_MBOX_INTERNAL_ERROR;
> + }
> + } else {
> + return CXL_MBOX_INTERNAL_ERROR;
> + }
> + return CXL_MBOX_SUCCESS;
> +}
> +
> +static CXLRetCode assert_PERST(Object *obj, ResetType type, uint8_t pn, CXLCCI *cci)
> +{
> + ResettableClass *rc = RESETTABLE_GET_CLASS(obj);
> + ResettableState *s = rc->get_state(obj);
> +
> + if (cci->pports.perst[pn].issued_assert_PERST || s->exit_phase_in_progress) {
> + return CXL_MBOX_INTERNAL_ERROR;
> + }
> +
WITH_QEMU_LOCK_GUARD() perhaps
> + qemu_mutex_lock(&cci->pports.perst[pn].lock);
> + cci->pports.perst[pn].issued_assert_PERST = true;
> + cci->pports.pport_info[pn].link_state_flags |=
> + LINK_STATE_FLAG_PERST_ASSERTED;
> + resettable_assert_reset(obj, type);
> + qemu_mutex_unlock(&cci->pports.perst[pn].lock);
> +
> + /* holding reset phase for 100ms */
> + while (cci->pports.perst[pn].asrt_time--) {
> + usleep(1000);
Is this happening synchronously? I'd kind of expect it to be a background thing
where we'd just check it had finished.
> + }
> + return CXL_MBOX_SUCCESS;
> +}
> +
> +/*CXL r3.2 Section 7.6.7.1.3: Get Physical Port Control (Opcode 5102h)*/
> +static CXLRetCode cmd_physical_port_control(const struct cxl_cmd *cmd,
> + uint8_t *payload_in,
> + size_t len_in,
> + uint8_t *payload_out,
> + size_t *len_out,
> + CXLCCI *cci)
> +{
> + PCIBus *bus = &PCI_BRIDGE(cci->d)->sec_bus;
> + PCIDevice *dev;
> + struct cxl_fmapi_get_physical_port_control_req_pl {
> + uint8_t PPB_ID;
> + uint8_t Ports_Op;
> + } QEMU_PACKED *in;
> +
> + in = (struct cxl_fmapi_get_physical_port_control_req_pl *)payload_in;
Often we cheat on these where the type is locally defined and do
struct cxl_fmapi_get_physical_port_control_req_pl {
uint8_t ppb_id;
uint8_t ports_op;
} QEMU_PACKED *in = (void *)payload_in;
Given it's all together the type isn't confusing or ambiguous even
though we use a void * instead of the more specific cast.
Note also that it is better to stick to local style and use lower_case
style for structure element naming etc.
> +
> + if (len_in < sizeof(*in)) {
> + return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
> + }
> +
> + uint8_t pn = in->PPB_ID;
> + dev = cxl_find_port_dev(pn, bus);
> + if (!dev) {
> + return CXL_MBOX_INTERNAL_ERROR;
> + }
> +
> + switch (in->Ports_Op) {
> + case 0:
> + assert_PERST(OBJECT(&dev->qdev), RESET_TYPE_COLD, pn, cci);
Even for these probably
assert_perst()
> + break;
return CXL_MBOX_SUCESS;
> + case 1:
> + deassert_PERST(OBJECT(&dev->qdev), RESET_TYPE_COLD, pn, cci);
> + break;
> + case 2:
> + device_cold_reset(&dev->qdev);
> + break;
> + default:
> + return CXL_MBOX_INVALID_INPUT;
> + }
> + return CXL_MBOX_SUCCESS;
> +}
> +
> @@ -3878,4 +3995,15 @@ void cxl_initialize_usp_mctpcci(CXLCCI *cci, DeviceState *d, DeviceState *intf,
> cci->intf = intf;
> cxl_init_cci(cci, payload_max);
> cxl_set_phy_port_info(cci); /* store port info */
> + /* physical port control */
> + for (int i = 0; i < PCI_DEVFN_MAX; i++) {
> + qemu_mutex_init(&cci->pports.perst[i].lock);
perst is definitely port wise - not linked to CCI so that stuff should be
in the port structures themselves.
> + cci->pports.perst[i].issued_assert_PERST = false;
> + /* Assert PERST involves physical port to be in
wrap at 80 chars.
> + * hold reset phase for minimum 100ms. No other calls
> + * are entertained until Deassert PERST command.
> + * https://patchwork.ozlabs.org/project/linux-pci/patch/20190523194409.17718-1-niklas.cassel@linaro.org/#2178369
Blocking other commands is fine but we should lock up emulation of other stuff
in the system and I think you currently do.
> + */
> + cci->pports.perst[i].asrt_time = ASSERT_WAIT_TIME_MS;
> + }
> }
> diff --git a/include/hw/cxl/cxl_device.h b/include/hw/cxl/cxl_device.h
> index 9eb128a1e8..f877d60b39 100644
> --- a/include/hw/cxl/cxl_device.h
> +++ b/include/hw/cxl/cxl_device.h
> @@ -146,10 +146,18 @@ struct cxl_phy_port_info {
> uint8_t supported_ld_count;
> } QEMU_PACKED;
>
> +/* assert-deassert PERST */
> +struct pperst {
> + bool issued_assert_PERST;
> + int asrt_time;
> + QemuMutex lock;
> +};
> +
> struct phy_port {
> uint8_t num_ports;
> uint8_t active_port_bitmask[0x20];
> struct cxl_phy_port_info pport_info[PCI_DEVFN_MAX];
> + struct pperst perst[PCI_DEVFN_MAX];
> };
>
> /* CXL r3.1 Table 8-34: Command Return Codes */
WARNING: multiple messages have this Message-ID (diff)
From: Jonathan Cameron via <qemu-devel@nongnu.org>
To: Arpit Kumar <arpit1.kumar@samsung.com>
Cc: <qemu-devel@nongnu.org>, <gost.dev@samsung.com>,
<linux-cxl@vger.kernel.org>, <nifan.cxl@gmail.com>,
<dave@stgolabs.net>, <vishak.g@samsung.com>,
<krish.reddy@samsung.com>, <a.manzanares@samsung.com>,
<alok.rathore@samsung.com>
Subject: Re: [PATCH 3/3] hw/cxl: Add Physical Port Control (Opcode 5102h)
Date: Tue, 10 Jun 2025 15:45:01 +0100 [thread overview]
Message-ID: <20250610154501.0000213b@huawei.com> (raw)
In-Reply-To: <20250602135942.2773823-4-arpit1.kumar@samsung.com>
On Mon, 2 Jun 2025 19:29:42 +0530
Arpit Kumar <arpit1.kumar@samsung.com> wrote:
Very interesting to see support for this. It will enable a load
of additional test cases.
> added assert-deassert PERST implementation, reset PPB
> for physical port.
Added
Please also include some details of testing done and what happens.
Given I know we have some issues with reset that we haven't resolved
I'm curious if you see them here.
>
> Signed-off-by: Arpit Kumar <arpit1.kumar@samsung.com>
> +/* Assert - Deassert PERST */
> +#define ASSERT_WAIT_TIME_MS 100
> +
> /* link state flags */
> #define LINK_STATE_FLAG_LANE_REVERSED (1 << 0)
> #define LINK_STATE_FLAG_PERST_ASSERTED (1 << 1)
> @@ -662,6 +666,114 @@ static CXLRetCode cmd_get_physical_port_state(const struct cxl_cmd *cmd,
> return CXL_MBOX_SUCCESS;
> }
>
> +static struct PCIDevice *cxl_find_port_dev(uint8_t ppb_id, PCIBus *bus)
> +{
> + PCIDevice *d;
> + int devfn;
> +
> + for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
As in patch one, maybe use the for_each_pci_... Though with the callback
needed it may end up slightly more complex that this.
> + d = bus->devices[devfn];
> + if (d) {
> + if (object_dynamic_cast(OBJECT(d), TYPE_CXL_DSP)) {
> + uint8_t port = PCIE_PORT(d)->port;
I'd not bother with the local variable for this one.
if (PCIE_PORT(d)->port == ppb_id) {
return d;
}
> + if (port == ppb_id) {
> + return d;
> + }
> + }
> + }
> + }
> + return NULL;
> +}
> +
> +static CXLRetCode deassert_PERST(Object *obj, ResetType type, uint8_t pn, CXLCCI *cci)
> +{
> + ResettableClass *rc = RESETTABLE_GET_CLASS(obj);
> + ResettableState *s = rc->get_state(obj);
> +
> + if (cci->pports.perst[pn].issued_assert_PERST) {
> + if (cci->pports.perst[pn].asrt_time == -1 && !s->hold_phase_pending) {
I'd flip the logic as then can return early in error case and reduce
indent of the rest.
> + qemu_mutex_lock(&cci->pports.perst[pn].lock);
QEMU_LOCK_GUARD(&cci->pports.prst[pn].lock);
> + resettable_release_reset(obj, type);
> + cci->pports.perst[pn].issued_assert_PERST = false;
> + cci->pports.pport_info[pn].link_state_flags &=
> + ~LINK_STATE_FLAG_PERST_ASSERTED;
> + cci->pports.perst[pn].asrt_time = ASSERT_WAIT_TIME_MS;
> + qemu_mutex_unlock(&cci->pports.perst[pn].lock);
and drop explicit unlock.
> + } else {
> + return CXL_MBOX_INTERNAL_ERROR;
> + }
> + } else {
> + return CXL_MBOX_INTERNAL_ERROR;
> + }
> + return CXL_MBOX_SUCCESS;
> +}
> +
> +static CXLRetCode assert_PERST(Object *obj, ResetType type, uint8_t pn, CXLCCI *cci)
> +{
> + ResettableClass *rc = RESETTABLE_GET_CLASS(obj);
> + ResettableState *s = rc->get_state(obj);
> +
> + if (cci->pports.perst[pn].issued_assert_PERST || s->exit_phase_in_progress) {
> + return CXL_MBOX_INTERNAL_ERROR;
> + }
> +
WITH_QEMU_LOCK_GUARD() perhaps
> + qemu_mutex_lock(&cci->pports.perst[pn].lock);
> + cci->pports.perst[pn].issued_assert_PERST = true;
> + cci->pports.pport_info[pn].link_state_flags |=
> + LINK_STATE_FLAG_PERST_ASSERTED;
> + resettable_assert_reset(obj, type);
> + qemu_mutex_unlock(&cci->pports.perst[pn].lock);
> +
> + /* holding reset phase for 100ms */
> + while (cci->pports.perst[pn].asrt_time--) {
> + usleep(1000);
Is this happening synchronously? I'd kind of expect it to be a background thing
where we'd just check it had finished.
> + }
> + return CXL_MBOX_SUCCESS;
> +}
> +
> +/*CXL r3.2 Section 7.6.7.1.3: Get Physical Port Control (Opcode 5102h)*/
> +static CXLRetCode cmd_physical_port_control(const struct cxl_cmd *cmd,
> + uint8_t *payload_in,
> + size_t len_in,
> + uint8_t *payload_out,
> + size_t *len_out,
> + CXLCCI *cci)
> +{
> + PCIBus *bus = &PCI_BRIDGE(cci->d)->sec_bus;
> + PCIDevice *dev;
> + struct cxl_fmapi_get_physical_port_control_req_pl {
> + uint8_t PPB_ID;
> + uint8_t Ports_Op;
> + } QEMU_PACKED *in;
> +
> + in = (struct cxl_fmapi_get_physical_port_control_req_pl *)payload_in;
Often we cheat on these where the type is locally defined and do
struct cxl_fmapi_get_physical_port_control_req_pl {
uint8_t ppb_id;
uint8_t ports_op;
} QEMU_PACKED *in = (void *)payload_in;
Given it's all together the type isn't confusing or ambiguous even
though we use a void * instead of the more specific cast.
Note also that it is better to stick to local style and use lower_case
style for structure element naming etc.
> +
> + if (len_in < sizeof(*in)) {
> + return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
> + }
> +
> + uint8_t pn = in->PPB_ID;
> + dev = cxl_find_port_dev(pn, bus);
> + if (!dev) {
> + return CXL_MBOX_INTERNAL_ERROR;
> + }
> +
> + switch (in->Ports_Op) {
> + case 0:
> + assert_PERST(OBJECT(&dev->qdev), RESET_TYPE_COLD, pn, cci);
Even for these probably
assert_perst()
> + break;
return CXL_MBOX_SUCESS;
> + case 1:
> + deassert_PERST(OBJECT(&dev->qdev), RESET_TYPE_COLD, pn, cci);
> + break;
> + case 2:
> + device_cold_reset(&dev->qdev);
> + break;
> + default:
> + return CXL_MBOX_INVALID_INPUT;
> + }
> + return CXL_MBOX_SUCCESS;
> +}
> +
> @@ -3878,4 +3995,15 @@ void cxl_initialize_usp_mctpcci(CXLCCI *cci, DeviceState *d, DeviceState *intf,
> cci->intf = intf;
> cxl_init_cci(cci, payload_max);
> cxl_set_phy_port_info(cci); /* store port info */
> + /* physical port control */
> + for (int i = 0; i < PCI_DEVFN_MAX; i++) {
> + qemu_mutex_init(&cci->pports.perst[i].lock);
perst is definitely port wise - not linked to CCI so that stuff should be
in the port structures themselves.
> + cci->pports.perst[i].issued_assert_PERST = false;
> + /* Assert PERST involves physical port to be in
wrap at 80 chars.
> + * hold reset phase for minimum 100ms. No other calls
> + * are entertained until Deassert PERST command.
> + * https://patchwork.ozlabs.org/project/linux-pci/patch/20190523194409.17718-1-niklas.cassel@linaro.org/#2178369
Blocking other commands is fine but we should lock up emulation of other stuff
in the system and I think you currently do.
> + */
> + cci->pports.perst[i].asrt_time = ASSERT_WAIT_TIME_MS;
> + }
> }
> diff --git a/include/hw/cxl/cxl_device.h b/include/hw/cxl/cxl_device.h
> index 9eb128a1e8..f877d60b39 100644
> --- a/include/hw/cxl/cxl_device.h
> +++ b/include/hw/cxl/cxl_device.h
> @@ -146,10 +146,18 @@ struct cxl_phy_port_info {
> uint8_t supported_ld_count;
> } QEMU_PACKED;
>
> +/* assert-deassert PERST */
> +struct pperst {
> + bool issued_assert_PERST;
> + int asrt_time;
> + QemuMutex lock;
> +};
> +
> struct phy_port {
> uint8_t num_ports;
> uint8_t active_port_bitmask[0x20];
> struct cxl_phy_port_info pport_info[PCI_DEVFN_MAX];
> + struct pperst perst[PCI_DEVFN_MAX];
> };
>
> /* CXL r3.1 Table 8-34: Command Return Codes */
next prev parent reply other threads:[~2025-06-10 14:45 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <CGME20250602140008epcas5p25fce01492de105da3cdc0aaa533f6ebc@epcas5p2.samsung.com>
2025-06-02 13:59 ` [PATCH 0/3] FM-API Physical switch command set update Arpit Kumar
2025-06-02 13:59 ` [PATCH 1/3] hw/cxl: Storing physical ports info during enumeration Arpit Kumar
2025-06-10 14:21 ` Jonathan Cameron
2025-06-10 14:21 ` Jonathan Cameron via
2025-06-17 9:46 ` Arpit Kumar
2025-06-18 11:31 ` Jonathan Cameron
2025-06-18 11:31 ` Jonathan Cameron via
2025-06-02 13:59 ` [PATCH 2/3] hw/cxl: Simplified Identify Switch Device & Get Physical Port State Arpit Kumar
2025-06-10 14:29 ` Jonathan Cameron
2025-06-10 14:29 ` Jonathan Cameron via
2025-06-17 10:01 ` Arpit Kumar
2025-06-02 13:59 ` [PATCH 3/3] hw/cxl: Add Physical Port Control (Opcode 5102h) Arpit Kumar
2025-06-10 14:45 ` Jonathan Cameron [this message]
2025-06-10 14:45 ` Jonathan Cameron via
2025-06-17 10:11 ` Arpit Kumar
2025-06-18 11:32 ` Jonathan Cameron
2025-06-18 11:32 ` Jonathan Cameron via
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250610154501.0000213b@huawei.com \
--to=jonathan.cameron@huawei.com \
--cc=a.manzanares@samsung.com \
--cc=alok.rathore@samsung.com \
--cc=arpit1.kumar@samsung.com \
--cc=dave@stgolabs.net \
--cc=gost.dev@samsung.com \
--cc=krish.reddy@samsung.com \
--cc=linux-cxl@vger.kernel.org \
--cc=nifan.cxl@gmail.com \
--cc=qemu-devel@nongnu.org \
--cc=vishak.g@samsung.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.