net/dpaa2: support link status event
Signed-off-by: Hemant Agrawal <hemant.agrawal@nxp.com>
This commit is contained in:
parent
01d0df35e7
commit
c5acbb5ea2
@ -6,6 +6,7 @@
|
||||
[Features]
|
||||
Speed capabilities = P
|
||||
Link status = Y
|
||||
Link status event = Y
|
||||
Queue start/stop = Y
|
||||
Jumbo frame = Y
|
||||
MTU update = Y
|
||||
|
@ -54,6 +54,8 @@
|
||||
|
||||
static struct rte_dpaa2_driver rte_dpaa2_pmd;
|
||||
static int dpaa2_dev_uninit(struct rte_eth_dev *eth_dev);
|
||||
static int dpaa2_dev_link_update(struct rte_eth_dev *dev,
|
||||
int wait_to_complete);
|
||||
static int dpaa2_dev_set_link_up(struct rte_eth_dev *dev);
|
||||
static int dpaa2_dev_set_link_down(struct rte_eth_dev *dev);
|
||||
static int dpaa2_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu);
|
||||
@ -344,6 +346,10 @@ dpaa2_eth_dev_configure(struct rte_eth_dev *dev)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* update the current status */
|
||||
dpaa2_dev_link_update(dev, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -556,9 +562,87 @@ dpaa2_supported_ptypes_get(struct rte_eth_dev *dev)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dpaa2 link Interrupt handler
|
||||
*
|
||||
* @param param
|
||||
* The address of parameter (struct rte_eth_dev *) regsitered before.
|
||||
*
|
||||
* @return
|
||||
* void
|
||||
*/
|
||||
static void
|
||||
dpaa2_interrupt_handler(void *param)
|
||||
{
|
||||
struct rte_eth_dev *dev = param;
|
||||
struct dpaa2_dev_priv *priv = dev->data->dev_private;
|
||||
struct fsl_mc_io *dpni = (struct fsl_mc_io *)priv->hw;
|
||||
int ret;
|
||||
int irq_index = DPNI_IRQ_INDEX;
|
||||
unsigned int status = 0, clear = 0;
|
||||
|
||||
PMD_INIT_FUNC_TRACE();
|
||||
|
||||
if (dpni == NULL) {
|
||||
RTE_LOG(ERR, PMD, "dpni is NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = dpni_get_irq_status(dpni, CMD_PRI_LOW, priv->token,
|
||||
irq_index, &status);
|
||||
if (unlikely(ret)) {
|
||||
RTE_LOG(ERR, PMD, "Can't get irq status (err %d)", ret);
|
||||
clear = 0xffffffff;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (status & DPNI_IRQ_EVENT_LINK_CHANGED) {
|
||||
clear = DPNI_IRQ_EVENT_LINK_CHANGED;
|
||||
dpaa2_dev_link_update(dev, 0);
|
||||
/* calling all the apps registered for link status event */
|
||||
_rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC,
|
||||
NULL, NULL);
|
||||
}
|
||||
out:
|
||||
ret = dpni_clear_irq_status(dpni, CMD_PRI_LOW, priv->token,
|
||||
irq_index, clear);
|
||||
if (unlikely(ret))
|
||||
RTE_LOG(ERR, PMD, "Can't clear irq status (err %d)", ret);
|
||||
}
|
||||
|
||||
static int
|
||||
dpaa2_eth_setup_irqs(struct rte_eth_dev *dev, int enable)
|
||||
{
|
||||
int err = 0;
|
||||
struct dpaa2_dev_priv *priv = dev->data->dev_private;
|
||||
struct fsl_mc_io *dpni = (struct fsl_mc_io *)priv->hw;
|
||||
int irq_index = DPNI_IRQ_INDEX;
|
||||
unsigned int mask = DPNI_IRQ_EVENT_LINK_CHANGED;
|
||||
|
||||
PMD_INIT_FUNC_TRACE();
|
||||
|
||||
err = dpni_set_irq_mask(dpni, CMD_PRI_LOW, priv->token,
|
||||
irq_index, mask);
|
||||
if (err < 0) {
|
||||
PMD_INIT_LOG(ERR, "Error: dpni_set_irq_mask():%d (%s)", err,
|
||||
strerror(-err));
|
||||
return err;
|
||||
}
|
||||
|
||||
err = dpni_set_irq_enable(dpni, CMD_PRI_LOW, priv->token,
|
||||
irq_index, enable);
|
||||
if (err < 0)
|
||||
PMD_INIT_LOG(ERR, "Error: dpni_set_irq_enable():%d (%s)", err,
|
||||
strerror(-err));
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
dpaa2_dev_start(struct rte_eth_dev *dev)
|
||||
{
|
||||
struct rte_device *rdev = dev->device;
|
||||
struct rte_dpaa2_device *dpaa2_dev;
|
||||
struct rte_eth_dev_data *data = dev->data;
|
||||
struct dpaa2_dev_priv *priv = data->dev_private;
|
||||
struct fsl_mc_io *dpni = (struct fsl_mc_io *)priv->hw;
|
||||
@ -568,6 +652,10 @@ dpaa2_dev_start(struct rte_eth_dev *dev)
|
||||
struct dpni_queue_id qid;
|
||||
struct dpaa2_queue *dpaa2_q;
|
||||
int ret, i;
|
||||
struct rte_intr_handle *intr_handle;
|
||||
|
||||
dpaa2_dev = container_of(rdev, struct rte_dpaa2_device, device);
|
||||
intr_handle = &dpaa2_dev->intr_handle;
|
||||
|
||||
PMD_INIT_FUNC_TRACE();
|
||||
|
||||
@ -647,6 +735,24 @@ dpaa2_dev_start(struct rte_eth_dev *dev)
|
||||
if (priv->max_vlan_filters)
|
||||
dpaa2_vlan_offload_set(dev, ETH_VLAN_FILTER_MASK);
|
||||
|
||||
/* if the interrupts were configured on this devices*/
|
||||
if (intr_handle && (intr_handle->fd) &&
|
||||
(dev->data->dev_conf.intr_conf.lsc != 0)) {
|
||||
/* Registering LSC interrupt handler */
|
||||
rte_intr_callback_register(intr_handle,
|
||||
dpaa2_interrupt_handler,
|
||||
(void *)dev);
|
||||
|
||||
/* enable vfio intr/eventfd mapping
|
||||
* Interrupt index 0 is required, so we can not use
|
||||
* rte_intr_enable.
|
||||
*/
|
||||
rte_dpaa2_intr_enable(intr_handle, DPNI_IRQ_INDEX);
|
||||
|
||||
/* enable dpni_irqs */
|
||||
dpaa2_eth_setup_irqs(dev, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -661,9 +767,25 @@ dpaa2_dev_stop(struct rte_eth_dev *dev)
|
||||
struct fsl_mc_io *dpni = (struct fsl_mc_io *)priv->hw;
|
||||
int ret;
|
||||
struct rte_eth_link link;
|
||||
struct rte_intr_handle *intr_handle = dev->intr_handle;
|
||||
|
||||
PMD_INIT_FUNC_TRACE();
|
||||
|
||||
/* reset interrupt callback */
|
||||
if (intr_handle && (intr_handle->fd) &&
|
||||
(dev->data->dev_conf.intr_conf.lsc != 0)) {
|
||||
/*disable dpni irqs */
|
||||
dpaa2_eth_setup_irqs(dev, 0);
|
||||
|
||||
/* disable vfio intr before callback unregister */
|
||||
rte_dpaa2_intr_disable(intr_handle, DPNI_IRQ_INDEX);
|
||||
|
||||
/* Unregistering LSC interrupt handler */
|
||||
rte_intr_callback_unregister(intr_handle,
|
||||
dpaa2_interrupt_handler,
|
||||
(void *)dev);
|
||||
}
|
||||
|
||||
dpaa2_dev_set_link_down(dev);
|
||||
|
||||
ret = dpni_disable(dpni, CMD_PRI_LOW, priv->token);
|
||||
@ -1458,6 +1580,7 @@ dpaa2_dev_init(struct rte_eth_dev *eth_dev)
|
||||
}
|
||||
|
||||
eth_dev->dev_ops = &dpaa2_ethdev_ops;
|
||||
eth_dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC;
|
||||
|
||||
eth_dev->rx_pkt_burst = dpaa2_dev_prefetch_rx;
|
||||
eth_dev->tx_pkt_burst = dpaa2_dev_tx;
|
||||
|
@ -350,6 +350,239 @@ int dpni_reset(struct fsl_mc_io *mc_io,
|
||||
return mc_send_command(mc_io, &cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* dpni_set_irq_enable() - Set overall interrupt state.
|
||||
* @mc_io: Pointer to MC portal's I/O object
|
||||
* @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
|
||||
* @token: Token of DPNI object
|
||||
* @irq_index: The interrupt index to configure
|
||||
* @en: Interrupt state: - enable = 1, disable = 0
|
||||
*
|
||||
* Allows GPP software to control when interrupts are generated.
|
||||
* Each interrupt can have up to 32 causes. The enable/disable control's the
|
||||
* overall interrupt state. if the interrupt is disabled no causes will cause
|
||||
* an interrupt.
|
||||
*
|
||||
* Return: '0' on Success; Error code otherwise.
|
||||
*/
|
||||
int dpni_set_irq_enable(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token,
|
||||
uint8_t irq_index,
|
||||
uint8_t en)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
struct dpni_cmd_set_irq_enable *cmd_params;
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_IRQ_ENABLE,
|
||||
cmd_flags,
|
||||
token);
|
||||
cmd_params = (struct dpni_cmd_set_irq_enable *)cmd.params;
|
||||
dpni_set_field(cmd_params->enable, ENABLE, en);
|
||||
cmd_params->irq_index = irq_index;
|
||||
|
||||
/* send command to mc*/
|
||||
return mc_send_command(mc_io, &cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* dpni_get_irq_enable() - Get overall interrupt state
|
||||
* @mc_io: Pointer to MC portal's I/O object
|
||||
* @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
|
||||
* @token: Token of DPNI object
|
||||
* @irq_index: The interrupt index to configure
|
||||
* @en: Returned interrupt state - enable = 1, disable = 0
|
||||
*
|
||||
* Return: '0' on Success; Error code otherwise.
|
||||
*/
|
||||
int dpni_get_irq_enable(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token,
|
||||
uint8_t irq_index,
|
||||
uint8_t *en)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
struct dpni_cmd_get_irq_enable *cmd_params;
|
||||
struct dpni_rsp_get_irq_enable *rsp_params;
|
||||
|
||||
int err;
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_IRQ_ENABLE,
|
||||
cmd_flags,
|
||||
token);
|
||||
cmd_params = (struct dpni_cmd_get_irq_enable *)cmd.params;
|
||||
cmd_params->irq_index = irq_index;
|
||||
|
||||
/* send command to mc*/
|
||||
err = mc_send_command(mc_io, &cmd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* retrieve response parameters */
|
||||
rsp_params = (struct dpni_rsp_get_irq_enable *)cmd.params;
|
||||
*en = dpni_get_field(rsp_params->enabled, ENABLE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dpni_set_irq_mask() - Set interrupt mask.
|
||||
* @mc_io: Pointer to MC portal's I/O object
|
||||
* @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
|
||||
* @token: Token of DPNI object
|
||||
* @irq_index: The interrupt index to configure
|
||||
* @mask: Event mask to trigger interrupt;
|
||||
* each bit:
|
||||
* 0 = ignore event
|
||||
* 1 = consider event for asserting IRQ
|
||||
*
|
||||
* Every interrupt can have up to 32 causes and the interrupt model supports
|
||||
* masking/unmasking each cause independently
|
||||
*
|
||||
* Return: '0' on Success; Error code otherwise.
|
||||
*/
|
||||
int dpni_set_irq_mask(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token,
|
||||
uint8_t irq_index,
|
||||
uint32_t mask)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
struct dpni_cmd_set_irq_mask *cmd_params;
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_IRQ_MASK,
|
||||
cmd_flags,
|
||||
token);
|
||||
cmd_params = (struct dpni_cmd_set_irq_mask *)cmd.params;
|
||||
cmd_params->mask = cpu_to_le32(mask);
|
||||
cmd_params->irq_index = irq_index;
|
||||
|
||||
/* send command to mc*/
|
||||
return mc_send_command(mc_io, &cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* dpni_get_irq_mask() - Get interrupt mask.
|
||||
* @mc_io: Pointer to MC portal's I/O object
|
||||
* @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
|
||||
* @token: Token of DPNI object
|
||||
* @irq_index: The interrupt index to configure
|
||||
* @mask: Returned event mask to trigger interrupt
|
||||
*
|
||||
* Every interrupt can have up to 32 causes and the interrupt model supports
|
||||
* masking/unmasking each cause independently
|
||||
*
|
||||
* Return: '0' on Success; Error code otherwise.
|
||||
*/
|
||||
int dpni_get_irq_mask(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token,
|
||||
uint8_t irq_index,
|
||||
uint32_t *mask)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
struct dpni_cmd_get_irq_mask *cmd_params;
|
||||
struct dpni_rsp_get_irq_mask *rsp_params;
|
||||
int err;
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_IRQ_MASK,
|
||||
cmd_flags,
|
||||
token);
|
||||
cmd_params = (struct dpni_cmd_get_irq_mask *)cmd.params;
|
||||
cmd_params->irq_index = irq_index;
|
||||
|
||||
/* send command to mc*/
|
||||
err = mc_send_command(mc_io, &cmd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* retrieve response parameters */
|
||||
rsp_params = (struct dpni_rsp_get_irq_mask *)cmd.params;
|
||||
*mask = le32_to_cpu(rsp_params->mask);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dpni_get_irq_status() - Get the current status of any pending interrupts.
|
||||
* @mc_io: Pointer to MC portal's I/O object
|
||||
* @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
|
||||
* @token: Token of DPNI object
|
||||
* @irq_index: The interrupt index to configure
|
||||
* @status: Returned interrupts status - one bit per cause:
|
||||
* 0 = no interrupt pending
|
||||
* 1 = interrupt pending
|
||||
*
|
||||
* Return: '0' on Success; Error code otherwise.
|
||||
*/
|
||||
int dpni_get_irq_status(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token,
|
||||
uint8_t irq_index,
|
||||
uint32_t *status)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
struct dpni_cmd_get_irq_status *cmd_params;
|
||||
struct dpni_rsp_get_irq_status *rsp_params;
|
||||
int err;
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_IRQ_STATUS,
|
||||
cmd_flags,
|
||||
token);
|
||||
cmd_params = (struct dpni_cmd_get_irq_status *)cmd.params;
|
||||
cmd_params->status = cpu_to_le32(*status);
|
||||
cmd_params->irq_index = irq_index;
|
||||
|
||||
/* send command to mc*/
|
||||
err = mc_send_command(mc_io, &cmd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* retrieve response parameters */
|
||||
rsp_params = (struct dpni_rsp_get_irq_status *)cmd.params;
|
||||
*status = le32_to_cpu(rsp_params->status);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dpni_clear_irq_status() - Clear a pending interrupt's status
|
||||
* @mc_io: Pointer to MC portal's I/O object
|
||||
* @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
|
||||
* @token: Token of DPNI object
|
||||
* @irq_index: The interrupt index to configure
|
||||
* @status: bits to clear (W1C) - one bit per cause:
|
||||
* 0 = don't change
|
||||
* 1 = clear status bit
|
||||
*
|
||||
* Return: '0' on Success; Error code otherwise.
|
||||
*/
|
||||
int dpni_clear_irq_status(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token,
|
||||
uint8_t irq_index,
|
||||
uint32_t status)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
struct dpni_cmd_clear_irq_status *cmd_params;
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPNI_CMDID_CLEAR_IRQ_STATUS,
|
||||
cmd_flags,
|
||||
token);
|
||||
cmd_params = (struct dpni_cmd_clear_irq_status *)cmd.params;
|
||||
cmd_params->irq_index = irq_index;
|
||||
cmd_params->status = cpu_to_le32(status);
|
||||
|
||||
/* send command to mc*/
|
||||
return mc_send_command(mc_io, &cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* dpni_get_attributes() - Retrieve DPNI attributes.
|
||||
* @mc_io: Pointer to MC portal's I/O object
|
||||
|
@ -246,6 +246,55 @@ int dpni_reset(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token);
|
||||
|
||||
/**
|
||||
* DPNI IRQ Index and Events
|
||||
*/
|
||||
|
||||
/**
|
||||
* IRQ index
|
||||
*/
|
||||
#define DPNI_IRQ_INDEX 0
|
||||
/**
|
||||
* IRQ event - indicates a change in link state
|
||||
*/
|
||||
#define DPNI_IRQ_EVENT_LINK_CHANGED 0x00000001
|
||||
|
||||
int dpni_set_irq_enable(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token,
|
||||
uint8_t irq_index,
|
||||
uint8_t en);
|
||||
|
||||
int dpni_get_irq_enable(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token,
|
||||
uint8_t irq_index,
|
||||
uint8_t *en);
|
||||
|
||||
int dpni_set_irq_mask(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token,
|
||||
uint8_t irq_index,
|
||||
uint32_t mask);
|
||||
|
||||
int dpni_get_irq_mask(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token,
|
||||
uint8_t irq_index,
|
||||
uint32_t *mask);
|
||||
|
||||
int dpni_get_irq_status(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token,
|
||||
uint8_t irq_index,
|
||||
uint32_t *status);
|
||||
|
||||
int dpni_clear_irq_status(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token,
|
||||
uint8_t irq_index,
|
||||
uint32_t status);
|
||||
|
||||
/**
|
||||
* struct dpni_attr - Structure representing DPNI attributes
|
||||
* @options: Any combination of the following options:
|
||||
|
@ -64,6 +64,13 @@
|
||||
#define DPNI_CMDID_RESET DPNI_CMD(0x005)
|
||||
#define DPNI_CMDID_IS_ENABLED DPNI_CMD(0x006)
|
||||
|
||||
#define DPNI_CMDID_SET_IRQ_ENABLE DPNI_CMD(0x012)
|
||||
#define DPNI_CMDID_GET_IRQ_ENABLE DPNI_CMD(0x013)
|
||||
#define DPNI_CMDID_SET_IRQ_MASK DPNI_CMD(0x014)
|
||||
#define DPNI_CMDID_GET_IRQ_MASK DPNI_CMD(0x015)
|
||||
#define DPNI_CMDID_GET_IRQ_STATUS DPNI_CMD(0x016)
|
||||
#define DPNI_CMDID_CLEAR_IRQ_STATUS DPNI_CMD(0x017)
|
||||
|
||||
#define DPNI_CMDID_SET_POOLS DPNI_CMD_V2(0x200)
|
||||
#define DPNI_CMDID_SET_ERRORS_BEHAVIOR DPNI_CMD(0x20B)
|
||||
|
||||
@ -169,6 +176,49 @@ struct dpni_rsp_is_enabled {
|
||||
uint8_t enabled;
|
||||
};
|
||||
|
||||
struct dpni_cmd_set_irq_enable {
|
||||
uint8_t enable;
|
||||
uint8_t pad[3];
|
||||
uint8_t irq_index;
|
||||
};
|
||||
|
||||
struct dpni_cmd_get_irq_enable {
|
||||
uint32_t pad;
|
||||
uint8_t irq_index;
|
||||
};
|
||||
|
||||
struct dpni_rsp_get_irq_enable {
|
||||
uint8_t enabled;
|
||||
};
|
||||
|
||||
struct dpni_cmd_set_irq_mask {
|
||||
uint32_t mask;
|
||||
uint8_t irq_index;
|
||||
};
|
||||
|
||||
struct dpni_cmd_get_irq_mask {
|
||||
uint32_t pad;
|
||||
uint8_t irq_index;
|
||||
};
|
||||
|
||||
struct dpni_rsp_get_irq_mask {
|
||||
uint32_t mask;
|
||||
};
|
||||
|
||||
struct dpni_cmd_get_irq_status {
|
||||
uint32_t status;
|
||||
uint8_t irq_index;
|
||||
};
|
||||
|
||||
struct dpni_rsp_get_irq_status {
|
||||
uint32_t status;
|
||||
};
|
||||
|
||||
struct dpni_cmd_clear_irq_status {
|
||||
uint32_t status;
|
||||
uint8_t irq_index;
|
||||
};
|
||||
|
||||
struct dpni_rsp_get_attr {
|
||||
/* response word 0 */
|
||||
uint32_t options;
|
||||
|
Loading…
Reference in New Issue
Block a user