net/ice: support link update
Add ops link_update. LSC interrupt is also enabled in this patch. Signed-off-by: Wenzhuo Lu <wenzhuo.lu@intel.com> Signed-off-by: Qiming Yang <qiming.yang@intel.com> Signed-off-by: Xiaoyun Li <xiaoyun.li@intel.com> Signed-off-by: Jingjing Wu <jingjing.wu@intel.com> Reviewed-by: Ferruh Yigit <ferruh.yigit@intel.com> Reviewed-by: Qi Zhang <qi.z.zhang@intel.com>
This commit is contained in:
parent
690175ee51
commit
cf911d90e3
@ -5,6 +5,8 @@
|
||||
;
|
||||
[Features]
|
||||
Speed capabilities = Y
|
||||
Link status = Y
|
||||
Link status event = Y
|
||||
Queue start/stop = Y
|
||||
BSD nic_uio = Y
|
||||
Linux UIO = Y
|
||||
|
@ -21,6 +21,8 @@ static void ice_dev_close(struct rte_eth_dev *dev);
|
||||
static int ice_dev_reset(struct rte_eth_dev *dev);
|
||||
static void ice_dev_info_get(struct rte_eth_dev *dev,
|
||||
struct rte_eth_dev_info *dev_info);
|
||||
static int ice_link_update(struct rte_eth_dev *dev,
|
||||
int wait_to_complete);
|
||||
|
||||
static const struct rte_pci_id pci_id_ice_map[] = {
|
||||
{ RTE_PCI_DEVICE(ICE_INTEL_VENDOR_ID, ICE_DEV_ID_E810C_BACKPLANE) },
|
||||
@ -44,6 +46,7 @@ static const struct eth_dev_ops ice_eth_dev_ops = {
|
||||
.tx_queue_setup = ice_tx_queue_setup,
|
||||
.tx_queue_release = ice_tx_queue_release,
|
||||
.dev_infos_get = ice_dev_info_get,
|
||||
.link_update = ice_link_update,
|
||||
};
|
||||
|
||||
static void
|
||||
@ -330,6 +333,187 @@ ice_init_mac_address(struct rte_eth_dev *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Enable IRQ0 */
|
||||
static void
|
||||
ice_pf_enable_irq0(struct ice_hw *hw)
|
||||
{
|
||||
/* reset the registers */
|
||||
ICE_WRITE_REG(hw, PFINT_OICR_ENA, 0);
|
||||
ICE_READ_REG(hw, PFINT_OICR);
|
||||
|
||||
#ifdef ICE_LSE_SPT
|
||||
ICE_WRITE_REG(hw, PFINT_OICR_ENA,
|
||||
(uint32_t)(PFINT_OICR_ENA_INT_ENA_M &
|
||||
(~PFINT_OICR_LINK_STAT_CHANGE_M)));
|
||||
|
||||
ICE_WRITE_REG(hw, PFINT_OICR_CTL,
|
||||
(0 & PFINT_OICR_CTL_MSIX_INDX_M) |
|
||||
((0 << PFINT_OICR_CTL_ITR_INDX_S) &
|
||||
PFINT_OICR_CTL_ITR_INDX_M) |
|
||||
PFINT_OICR_CTL_CAUSE_ENA_M);
|
||||
|
||||
ICE_WRITE_REG(hw, PFINT_FW_CTL,
|
||||
(0 & PFINT_FW_CTL_MSIX_INDX_M) |
|
||||
((0 << PFINT_FW_CTL_ITR_INDX_S) &
|
||||
PFINT_FW_CTL_ITR_INDX_M) |
|
||||
PFINT_FW_CTL_CAUSE_ENA_M);
|
||||
#else
|
||||
ICE_WRITE_REG(hw, PFINT_OICR_ENA, PFINT_OICR_ENA_INT_ENA_M);
|
||||
#endif
|
||||
|
||||
ICE_WRITE_REG(hw, GLINT_DYN_CTL(0),
|
||||
GLINT_DYN_CTL_INTENA_M |
|
||||
GLINT_DYN_CTL_CLEARPBA_M |
|
||||
GLINT_DYN_CTL_ITR_INDX_M);
|
||||
|
||||
ice_flush(hw);
|
||||
}
|
||||
|
||||
/* Disable IRQ0 */
|
||||
static void
|
||||
ice_pf_disable_irq0(struct ice_hw *hw)
|
||||
{
|
||||
/* Disable all interrupt types */
|
||||
ICE_WRITE_REG(hw, GLINT_DYN_CTL(0), GLINT_DYN_CTL_WB_ON_ITR_M);
|
||||
ice_flush(hw);
|
||||
}
|
||||
|
||||
#ifdef ICE_LSE_SPT
|
||||
static void
|
||||
ice_handle_aq_msg(struct rte_eth_dev *dev)
|
||||
{
|
||||
struct ice_hw *hw = ICE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
|
||||
struct ice_ctl_q_info *cq = &hw->adminq;
|
||||
struct ice_rq_event_info event;
|
||||
uint16_t pending, opcode;
|
||||
int ret;
|
||||
|
||||
event.buf_len = ICE_AQ_MAX_BUF_LEN;
|
||||
event.msg_buf = rte_zmalloc(NULL, event.buf_len, 0);
|
||||
if (!event.msg_buf) {
|
||||
PMD_DRV_LOG(ERR, "Failed to allocate mem");
|
||||
return;
|
||||
}
|
||||
|
||||
pending = 1;
|
||||
while (pending) {
|
||||
ret = ice_clean_rq_elem(hw, cq, &event, &pending);
|
||||
|
||||
if (ret != ICE_SUCCESS) {
|
||||
PMD_DRV_LOG(INFO,
|
||||
"Failed to read msg from AdminQ, "
|
||||
"adminq_err: %u",
|
||||
hw->adminq.sq_last_status);
|
||||
break;
|
||||
}
|
||||
opcode = rte_le_to_cpu_16(event.desc.opcode);
|
||||
|
||||
switch (opcode) {
|
||||
case ice_aqc_opc_get_link_status:
|
||||
ret = ice_link_update(dev, 0);
|
||||
if (!ret)
|
||||
_rte_eth_dev_callback_process
|
||||
(dev, RTE_ETH_EVENT_INTR_LSC, NULL);
|
||||
break;
|
||||
default:
|
||||
PMD_DRV_LOG(DEBUG, "Request %u is not supported yet",
|
||||
opcode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
rte_free(event.msg_buf);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Interrupt handler triggered by NIC for handling
|
||||
* specific interrupt.
|
||||
*
|
||||
* @param handle
|
||||
* Pointer to interrupt handle.
|
||||
* @param param
|
||||
* The address of parameter (struct rte_eth_dev *) regsitered before.
|
||||
*
|
||||
* @return
|
||||
* void
|
||||
*/
|
||||
static void
|
||||
ice_interrupt_handler(void *param)
|
||||
{
|
||||
struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
|
||||
struct ice_hw *hw = ICE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
|
||||
uint32_t oicr;
|
||||
uint32_t reg;
|
||||
uint8_t pf_num;
|
||||
uint8_t event;
|
||||
uint16_t queue;
|
||||
#ifdef ICE_LSE_SPT
|
||||
uint32_t int_fw_ctl;
|
||||
#endif
|
||||
|
||||
/* Disable interrupt */
|
||||
ice_pf_disable_irq0(hw);
|
||||
|
||||
/* read out interrupt causes */
|
||||
oicr = ICE_READ_REG(hw, PFINT_OICR);
|
||||
#ifdef ICE_LSE_SPT
|
||||
int_fw_ctl = ICE_READ_REG(hw, PFINT_FW_CTL);
|
||||
#endif
|
||||
|
||||
/* No interrupt event indicated */
|
||||
if (!(oicr & PFINT_OICR_INTEVENT_M)) {
|
||||
PMD_DRV_LOG(INFO, "No interrupt event");
|
||||
goto done;
|
||||
}
|
||||
|
||||
#ifdef ICE_LSE_SPT
|
||||
if (int_fw_ctl & PFINT_FW_CTL_INTEVENT_M) {
|
||||
PMD_DRV_LOG(INFO, "FW_CTL: link state change event");
|
||||
ice_handle_aq_msg(dev);
|
||||
}
|
||||
#else
|
||||
if (oicr & PFINT_OICR_LINK_STAT_CHANGE_M) {
|
||||
PMD_DRV_LOG(INFO, "OICR: link state change event");
|
||||
ice_link_update(dev, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (oicr & PFINT_OICR_MAL_DETECT_M) {
|
||||
PMD_DRV_LOG(WARNING, "OICR: MDD event");
|
||||
reg = ICE_READ_REG(hw, GL_MDET_TX_PQM);
|
||||
if (reg & GL_MDET_TX_PQM_VALID_M) {
|
||||
pf_num = (reg & GL_MDET_TX_PQM_PF_NUM_M) >>
|
||||
GL_MDET_TX_PQM_PF_NUM_S;
|
||||
event = (reg & GL_MDET_TX_PQM_MAL_TYPE_M) >>
|
||||
GL_MDET_TX_PQM_MAL_TYPE_S;
|
||||
queue = (reg & GL_MDET_TX_PQM_QNUM_M) >>
|
||||
GL_MDET_TX_PQM_QNUM_S;
|
||||
|
||||
PMD_DRV_LOG(WARNING, "Malicious Driver Detection event "
|
||||
"%d by PQM on TX queue %d PF# %d",
|
||||
event, queue, pf_num);
|
||||
}
|
||||
|
||||
reg = ICE_READ_REG(hw, GL_MDET_TX_TCLAN);
|
||||
if (reg & GL_MDET_TX_TCLAN_VALID_M) {
|
||||
pf_num = (reg & GL_MDET_TX_TCLAN_PF_NUM_M) >>
|
||||
GL_MDET_TX_TCLAN_PF_NUM_S;
|
||||
event = (reg & GL_MDET_TX_TCLAN_MAL_TYPE_M) >>
|
||||
GL_MDET_TX_TCLAN_MAL_TYPE_S;
|
||||
queue = (reg & GL_MDET_TX_TCLAN_QNUM_M) >>
|
||||
GL_MDET_TX_TCLAN_QNUM_S;
|
||||
|
||||
PMD_DRV_LOG(WARNING, "Malicious Driver Detection event "
|
||||
"%d by TCLAN on TX queue %d PF# %d",
|
||||
event, queue, pf_num);
|
||||
}
|
||||
}
|
||||
done:
|
||||
/* Enable interrupt */
|
||||
ice_pf_enable_irq0(hw);
|
||||
rte_intr_enable(dev->intr_handle);
|
||||
}
|
||||
|
||||
/* Initialize SW parameters of PF */
|
||||
static int
|
||||
ice_pf_sw_init(struct rte_eth_dev *dev)
|
||||
@ -487,6 +671,7 @@ static int
|
||||
ice_dev_init(struct rte_eth_dev *dev)
|
||||
{
|
||||
struct rte_pci_device *pci_dev;
|
||||
struct rte_intr_handle *intr_handle;
|
||||
struct ice_hw *hw = ICE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
|
||||
struct ice_pf *pf = ICE_DEV_PRIVATE_TO_PF(dev->data->dev_private);
|
||||
int ret;
|
||||
@ -494,6 +679,7 @@ ice_dev_init(struct rte_eth_dev *dev)
|
||||
dev->dev_ops = &ice_eth_dev_ops;
|
||||
|
||||
pci_dev = RTE_DEV_TO_PCI(dev->device);
|
||||
intr_handle = &pci_dev->intr_handle;
|
||||
|
||||
pf->adapter = ICE_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
|
||||
pf->adapter->eth_dev = dev;
|
||||
@ -539,6 +725,15 @@ ice_dev_init(struct rte_eth_dev *dev)
|
||||
goto err_pf_setup;
|
||||
}
|
||||
|
||||
/* register callback func to eal lib */
|
||||
rte_intr_callback_register(intr_handle,
|
||||
ice_interrupt_handler, dev);
|
||||
|
||||
ice_pf_enable_irq0(hw);
|
||||
|
||||
/* enable uio intr after callback register */
|
||||
rte_intr_enable(intr_handle);
|
||||
|
||||
return 0;
|
||||
|
||||
err_pf_setup:
|
||||
@ -585,6 +780,8 @@ ice_dev_stop(struct rte_eth_dev *dev)
|
||||
{
|
||||
struct rte_eth_dev_data *data = dev->data;
|
||||
struct ice_pf *pf = ICE_DEV_PRIVATE_TO_PF(dev->data->dev_private);
|
||||
struct rte_pci_device *pci_dev = ICE_DEV_TO_PCI(dev);
|
||||
struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
|
||||
uint16_t i;
|
||||
|
||||
/* avoid stopping again */
|
||||
@ -602,6 +799,13 @@ ice_dev_stop(struct rte_eth_dev *dev)
|
||||
/* Clear all queues and release mbufs */
|
||||
ice_clear_queues(dev);
|
||||
|
||||
/* Clean datapath event and queue/vec mapping */
|
||||
rte_intr_efd_disable(intr_handle);
|
||||
if (intr_handle->intr_vec) {
|
||||
rte_free(intr_handle->intr_vec);
|
||||
intr_handle->intr_vec = NULL;
|
||||
}
|
||||
|
||||
pf->adapter_stopped = true;
|
||||
}
|
||||
|
||||
@ -627,6 +831,8 @@ ice_dev_uninit(struct rte_eth_dev *dev)
|
||||
{
|
||||
struct ice_hw *hw = ICE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
|
||||
struct ice_pf *pf = ICE_DEV_PRIVATE_TO_PF(dev->data->dev_private);
|
||||
struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
|
||||
struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
|
||||
|
||||
ice_dev_close(dev);
|
||||
|
||||
@ -637,6 +843,13 @@ ice_dev_uninit(struct rte_eth_dev *dev)
|
||||
rte_free(dev->data->mac_addrs);
|
||||
dev->data->mac_addrs = NULL;
|
||||
|
||||
/* disable uio intr before callback unregister */
|
||||
rte_intr_disable(intr_handle);
|
||||
|
||||
/* register callback func to eal lib */
|
||||
rte_intr_callback_unregister(intr_handle,
|
||||
ice_interrupt_handler, dev);
|
||||
|
||||
ice_release_vsi(pf->main_vsi);
|
||||
ice_sched_cleanup_all(hw);
|
||||
rte_free(hw->port_info);
|
||||
@ -755,6 +968,9 @@ ice_dev_start(struct rte_eth_dev *dev)
|
||||
if (ret != ICE_SUCCESS)
|
||||
PMD_DRV_LOG(WARNING, "Fail to set phy mask");
|
||||
|
||||
/* Call get_link_info aq commond to enable/disable LSE */
|
||||
ice_link_update(dev, 0);
|
||||
|
||||
pf->adapter_stopped = false;
|
||||
|
||||
return 0;
|
||||
@ -893,6 +1109,122 @@ ice_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
|
||||
dev_info->default_txportconf.ring_size = ICE_BUF_SIZE_MIN;
|
||||
}
|
||||
|
||||
static inline int
|
||||
ice_atomic_read_link_status(struct rte_eth_dev *dev,
|
||||
struct rte_eth_link *link)
|
||||
{
|
||||
struct rte_eth_link *dst = link;
|
||||
struct rte_eth_link *src = &dev->data->dev_link;
|
||||
|
||||
if (rte_atomic64_cmpset((uint64_t *)dst, *(uint64_t *)dst,
|
||||
*(uint64_t *)src) == 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
ice_atomic_write_link_status(struct rte_eth_dev *dev,
|
||||
struct rte_eth_link *link)
|
||||
{
|
||||
struct rte_eth_link *dst = &dev->data->dev_link;
|
||||
struct rte_eth_link *src = link;
|
||||
|
||||
if (rte_atomic64_cmpset((uint64_t *)dst, *(uint64_t *)dst,
|
||||
*(uint64_t *)src) == 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ice_link_update(struct rte_eth_dev *dev, __rte_unused int wait_to_complete)
|
||||
{
|
||||
#define CHECK_INTERVAL 100 /* 100ms */
|
||||
#define MAX_REPEAT_TIME 10 /* 1s (10 * 100ms) in total */
|
||||
struct ice_hw *hw = ICE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
|
||||
struct ice_link_status link_status;
|
||||
struct rte_eth_link link, old;
|
||||
int status;
|
||||
unsigned int rep_cnt = MAX_REPEAT_TIME;
|
||||
bool enable_lse = dev->data->dev_conf.intr_conf.lsc ? true : false;
|
||||
|
||||
memset(&link, 0, sizeof(link));
|
||||
memset(&old, 0, sizeof(old));
|
||||
memset(&link_status, 0, sizeof(link_status));
|
||||
ice_atomic_read_link_status(dev, &old);
|
||||
|
||||
do {
|
||||
/* Get link status information from hardware */
|
||||
status = ice_aq_get_link_info(hw->port_info, enable_lse,
|
||||
&link_status, NULL);
|
||||
if (status != ICE_SUCCESS) {
|
||||
link.link_speed = ETH_SPEED_NUM_100M;
|
||||
link.link_duplex = ETH_LINK_FULL_DUPLEX;
|
||||
PMD_DRV_LOG(ERR, "Failed to get link info");
|
||||
goto out;
|
||||
}
|
||||
|
||||
link.link_status = link_status.link_info & ICE_AQ_LINK_UP;
|
||||
if (!wait_to_complete || link.link_status)
|
||||
break;
|
||||
|
||||
rte_delay_ms(CHECK_INTERVAL);
|
||||
} while (--rep_cnt);
|
||||
|
||||
if (!link.link_status)
|
||||
goto out;
|
||||
|
||||
/* Full-duplex operation at all supported speeds */
|
||||
link.link_duplex = ETH_LINK_FULL_DUPLEX;
|
||||
|
||||
/* Parse the link status */
|
||||
switch (link_status.link_speed) {
|
||||
case ICE_AQ_LINK_SPEED_10MB:
|
||||
link.link_speed = ETH_SPEED_NUM_10M;
|
||||
break;
|
||||
case ICE_AQ_LINK_SPEED_100MB:
|
||||
link.link_speed = ETH_SPEED_NUM_100M;
|
||||
break;
|
||||
case ICE_AQ_LINK_SPEED_1000MB:
|
||||
link.link_speed = ETH_SPEED_NUM_1G;
|
||||
break;
|
||||
case ICE_AQ_LINK_SPEED_2500MB:
|
||||
link.link_speed = ETH_SPEED_NUM_2_5G;
|
||||
break;
|
||||
case ICE_AQ_LINK_SPEED_5GB:
|
||||
link.link_speed = ETH_SPEED_NUM_5G;
|
||||
break;
|
||||
case ICE_AQ_LINK_SPEED_10GB:
|
||||
link.link_speed = ETH_SPEED_NUM_10G;
|
||||
break;
|
||||
case ICE_AQ_LINK_SPEED_20GB:
|
||||
link.link_speed = ETH_SPEED_NUM_20G;
|
||||
break;
|
||||
case ICE_AQ_LINK_SPEED_25GB:
|
||||
link.link_speed = ETH_SPEED_NUM_25G;
|
||||
break;
|
||||
case ICE_AQ_LINK_SPEED_40GB:
|
||||
link.link_speed = ETH_SPEED_NUM_40G;
|
||||
break;
|
||||
case ICE_AQ_LINK_SPEED_UNKNOWN:
|
||||
default:
|
||||
PMD_DRV_LOG(ERR, "Unknown link speed");
|
||||
link.link_speed = ETH_SPEED_NUM_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
link.link_autoneg = !(dev->data->dev_conf.link_speeds &
|
||||
ETH_LINK_SPEED_FIXED);
|
||||
|
||||
out:
|
||||
ice_atomic_write_link_status(dev, &link);
|
||||
if (link.link_status == old.link_status)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ice_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
|
||||
struct rte_pci_device *pci_dev)
|
||||
|
Loading…
x
Reference in New Issue
Block a user