hw/cxl: Implement Physical Ports status retrieval
Add this command for both the Switch CCI in switch upstream ports. Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> Message-Id: <20231023160806.13206-11-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
parent
314f5033c6
commit
892e3479d7
@ -72,6 +72,7 @@ enum {
|
||||
#define CLEAR_POISON 0x2
|
||||
PHYSICAL_SWITCH = 0x51,
|
||||
#define IDENTIFY_SWITCH_DEVICE 0x0
|
||||
#define GET_PHYSICAL_PORT_STATE 0x1
|
||||
};
|
||||
|
||||
|
||||
@ -320,6 +321,131 @@ static CXLRetCode cmd_identify_switch_device(const struct cxl_cmd *cmd,
|
||||
|
||||
return CXL_MBOX_SUCCESS;
|
||||
}
|
||||
|
||||
/* CXL r3.0 Section 7.6.7.1.2: Get Physical Port State (Opcode 5101h) */
|
||||
static CXLRetCode cmd_get_physical_port_state(const struct cxl_cmd *cmd,
|
||||
uint8_t *payload_in,
|
||||
size_t len_in,
|
||||
uint8_t *payload_out,
|
||||
size_t *len_out,
|
||||
CXLCCI *cci)
|
||||
{
|
||||
/* CXL r3.0 Table 7-18: Get Physical Port State Request Payload */
|
||||
struct cxl_fmapi_get_phys_port_state_req_pl {
|
||||
uint8_t num_ports;
|
||||
uint8_t ports[];
|
||||
} QEMU_PACKED *in;
|
||||
|
||||
/*
|
||||
* CXL r3.0 Table 7-20: Get Physical Port State Port Information Block
|
||||
* Format
|
||||
*/
|
||||
struct cxl_fmapi_port_state_info_block {
|
||||
uint8_t port_id;
|
||||
uint8_t config_state;
|
||||
uint8_t connected_device_cxl_version;
|
||||
uint8_t rsv1;
|
||||
uint8_t connected_device_type;
|
||||
uint8_t port_cxl_version_bitmask;
|
||||
uint8_t max_link_width;
|
||||
uint8_t negotiated_link_width;
|
||||
uint8_t supported_link_speeds_vector;
|
||||
uint8_t max_link_speed;
|
||||
uint8_t current_link_speed;
|
||||
uint8_t ltssm_state;
|
||||
uint8_t first_lane_num;
|
||||
uint16_t link_state;
|
||||
uint8_t supported_ld_count;
|
||||
} QEMU_PACKED;
|
||||
|
||||
/* CXL r3.0 Table 7-19: Get Physical Port State Response Payload */
|
||||
struct cxl_fmapi_get_phys_port_state_resp_pl {
|
||||
uint8_t num_ports;
|
||||
uint8_t rsv1[3];
|
||||
struct cxl_fmapi_port_state_info_block ports[];
|
||||
} QEMU_PACKED *out;
|
||||
PCIBus *bus = &PCI_BRIDGE(cci->d)->sec_bus;
|
||||
PCIEPort *usp = PCIE_PORT(cci->d);
|
||||
size_t pl_size;
|
||||
int i;
|
||||
|
||||
in = (struct cxl_fmapi_get_phys_port_state_req_pl *)payload_in;
|
||||
out = (struct cxl_fmapi_get_phys_port_state_resp_pl *)payload_out;
|
||||
|
||||
/* Check if what was requested can fit */
|
||||
if (sizeof(*out) + sizeof(*out->ports) * in->num_ports > cci->payload_max) {
|
||||
return CXL_MBOX_INVALID_INPUT;
|
||||
}
|
||||
|
||||
/* For success there should be a match for each requested */
|
||||
out->num_ports = in->num_ports;
|
||||
|
||||
for (i = 0; i < in->num_ports; i++) {
|
||||
struct cxl_fmapi_port_state_info_block *port;
|
||||
/* First try to match on downstream port */
|
||||
PCIDevice *port_dev;
|
||||
uint16_t lnkcap, lnkcap2, lnksta;
|
||||
|
||||
port = &out->ports[i];
|
||||
|
||||
port_dev = pcie_find_port_by_pn(bus, in->ports[i]);
|
||||
if (port_dev) { /* DSP */
|
||||
PCIDevice *ds_dev = pci_bridge_get_sec_bus(PCI_BRIDGE(port_dev))
|
||||
->devices[0];
|
||||
port->config_state = 3;
|
||||
if (ds_dev) {
|
||||
if (object_dynamic_cast(OBJECT(ds_dev), TYPE_CXL_TYPE3)) {
|
||||
port->connected_device_type = 5; /* Assume MLD for now */
|
||||
} else {
|
||||
port->connected_device_type = 1;
|
||||
}
|
||||
} else {
|
||||
port->connected_device_type = 0;
|
||||
}
|
||||
port->supported_ld_count = 3;
|
||||
} else if (usp->port == in->ports[i]) { /* USP */
|
||||
port_dev = PCI_DEVICE(usp);
|
||||
port->config_state = 4;
|
||||
port->connected_device_type = 0;
|
||||
} else {
|
||||
return CXL_MBOX_INVALID_INPUT;
|
||||
}
|
||||
|
||||
port->port_id = in->ports[i];
|
||||
/* Information on status of this port in lnksta, lnkcap */
|
||||
if (!port_dev->exp.exp_cap) {
|
||||
return CXL_MBOX_INTERNAL_ERROR;
|
||||
}
|
||||
lnksta = port_dev->config_read(port_dev,
|
||||
port_dev->exp.exp_cap + PCI_EXP_LNKSTA,
|
||||
sizeof(lnksta));
|
||||
lnkcap = port_dev->config_read(port_dev,
|
||||
port_dev->exp.exp_cap + PCI_EXP_LNKCAP,
|
||||
sizeof(lnkcap));
|
||||
lnkcap2 = port_dev->config_read(port_dev,
|
||||
port_dev->exp.exp_cap + PCI_EXP_LNKCAP2,
|
||||
sizeof(lnkcap2));
|
||||
|
||||
port->max_link_width = (lnkcap & PCI_EXP_LNKCAP_MLW) >> 4;
|
||||
port->negotiated_link_width = (lnksta & PCI_EXP_LNKSTA_NLW) >> 4;
|
||||
/* No definition for SLS field in linux/pci_regs.h */
|
||||
port->supported_link_speeds_vector = (lnkcap2 & 0xFE) >> 1;
|
||||
port->max_link_speed = lnkcap & PCI_EXP_LNKCAP_SLS;
|
||||
port->current_link_speed = lnksta & PCI_EXP_LNKSTA_CLS;
|
||||
/* TODO: Track down if we can get the rest of the info */
|
||||
port->ltssm_state = 0x7;
|
||||
port->first_lane_num = 0;
|
||||
port->link_state = 0;
|
||||
port->port_cxl_version_bitmask = 0x2;
|
||||
port->connected_device_cxl_version = 0x2;
|
||||
}
|
||||
|
||||
pl_size = sizeof(*out) + sizeof(*out->ports) * in->num_ports;
|
||||
*len_out = pl_size;
|
||||
|
||||
return CXL_MBOX_SUCCESS;
|
||||
}
|
||||
|
||||
/* 8.2.9.2.1 */
|
||||
static CXLRetCode cmd_firmware_update_get_info(const struct cxl_cmd *cmd,
|
||||
uint8_t *payload_in,
|
||||
@ -881,6 +1007,8 @@ static const struct cxl_cmd cxl_cmd_set_sw[256][256] = {
|
||||
[LOGS][GET_LOG] = { "LOGS_GET_LOG", cmd_logs_get_log, 0x18, 0 },
|
||||
[PHYSICAL_SWITCH][IDENTIFY_SWITCH_DEVICE] = { "IDENTIFY_SWITCH_DEVICE",
|
||||
cmd_identify_switch_device, 0, 0 },
|
||||
[PHYSICAL_SWITCH][GET_PHYSICAL_PORT_STATE] = { "SWITCH_PHYSICAL_PORT_STATS",
|
||||
cmd_get_physical_port_state, ~0, 0 },
|
||||
};
|
||||
|
||||
int cxl_process_cci_message(CXLCCI *cci, uint8_t set, uint8_t cmd,
|
||||
|
Loading…
Reference in New Issue
Block a user