Commit 8a0b0751 authored by David S. Miller's avatar David S. Miller

Merge branch 'qed-coalesce'

Sudarsana Reddy Kalluru says:

====================
qed*: coalesce parameters config support.

The patch series adds the support for config/read of the adapter coalesce
parameters. Patch (1) adds the qed infrastructure/APIs for the support and
patch (2) adds the driver support for following ethtool commands:
	ethtool -c|--show-coalesce ethX
	ethtool -C|--coalesce ethX [rx-usecs N] [tx-usecs N]
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents dc14341e d552fa84
......@@ -2222,6 +2222,110 @@ int qed_fw_rss_eng(struct qed_hwfn *p_hwfn,
return 0;
}
static int qed_set_coalesce(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
u32 hw_addr, void *p_eth_qzone,
size_t eth_qzone_size, u8 timeset)
{
struct coalescing_timeset *p_coal_timeset;
if (p_hwfn->cdev->int_coalescing_mode != QED_COAL_MODE_ENABLE) {
DP_NOTICE(p_hwfn, "Coalescing configuration not enabled\n");
return -EINVAL;
}
p_coal_timeset = p_eth_qzone;
memset(p_coal_timeset, 0, eth_qzone_size);
SET_FIELD(p_coal_timeset->value, COALESCING_TIMESET_TIMESET, timeset);
SET_FIELD(p_coal_timeset->value, COALESCING_TIMESET_VALID, 1);
qed_memcpy_to(p_hwfn, p_ptt, hw_addr, p_eth_qzone, eth_qzone_size);
return 0;
}
int qed_set_rxq_coalesce(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
u16 coalesce, u8 qid, u16 sb_id)
{
struct ustorm_eth_queue_zone eth_qzone;
u8 timeset, timer_res;
u16 fw_qid = 0;
u32 address;
int rc;
/* Coalesce = (timeset << timer-resolution), timeset is 7bit wide */
if (coalesce <= 0x7F) {
timer_res = 0;
} else if (coalesce <= 0xFF) {
timer_res = 1;
} else if (coalesce <= 0x1FF) {
timer_res = 2;
} else {
DP_ERR(p_hwfn, "Invalid coalesce value - %d\n", coalesce);
return -EINVAL;
}
timeset = (u8)(coalesce >> timer_res);
rc = qed_fw_l2_queue(p_hwfn, (u16)qid, &fw_qid);
if (rc)
return rc;
rc = qed_int_set_timer_res(p_hwfn, p_ptt, timer_res, sb_id, false);
if (rc)
goto out;
address = BAR0_MAP_REG_USDM_RAM + USTORM_ETH_QUEUE_ZONE_OFFSET(fw_qid);
rc = qed_set_coalesce(p_hwfn, p_ptt, address, &eth_qzone,
sizeof(struct ustorm_eth_queue_zone), timeset);
if (rc)
goto out;
p_hwfn->cdev->rx_coalesce_usecs = coalesce;
out:
return rc;
}
int qed_set_txq_coalesce(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
u16 coalesce, u8 qid, u16 sb_id)
{
struct xstorm_eth_queue_zone eth_qzone;
u8 timeset, timer_res;
u16 fw_qid = 0;
u32 address;
int rc;
/* Coalesce = (timeset << timer-resolution), timeset is 7bit wide */
if (coalesce <= 0x7F) {
timer_res = 0;
} else if (coalesce <= 0xFF) {
timer_res = 1;
} else if (coalesce <= 0x1FF) {
timer_res = 2;
} else {
DP_ERR(p_hwfn, "Invalid coalesce value - %d\n", coalesce);
return -EINVAL;
}
timeset = (u8)(coalesce >> timer_res);
rc = qed_fw_l2_queue(p_hwfn, (u16)qid, &fw_qid);
if (rc)
return rc;
rc = qed_int_set_timer_res(p_hwfn, p_ptt, timer_res, sb_id, true);
if (rc)
goto out;
address = BAR0_MAP_REG_XSDM_RAM + XSTORM_ETH_QUEUE_ZONE_OFFSET(fw_qid);
rc = qed_set_coalesce(p_hwfn, p_ptt, address, &eth_qzone,
sizeof(struct xstorm_eth_queue_zone), timeset);
if (rc)
goto out;
p_hwfn->cdev->tx_coalesce_usecs = coalesce;
out:
return rc;
}
/* Calculate final WFQ values for all vports and configure them.
* After this configuration each vport will have
* approx min rate = min_pf_rate * (vport_wfq / QED_WFQ_UNIT)
......
......@@ -212,6 +212,20 @@ qed_dmae_host2grc(struct qed_hwfn *p_hwfn,
u32 size_in_dwords,
u32 flags);
/**
* @brief qed_dmae_grc2host - Read data from dmae data offset
* to source address using the given ptt
*
* @param p_ptt
* @param grc_addr (dmae_data_offset)
* @param dest_addr
* @param size_in_dwords
* @param flags - one of the flags defined above
*/
int qed_dmae_grc2host(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
u32 grc_addr, dma_addr_t dest_addr, u32 size_in_dwords,
u32 flags);
/**
* @brief qed_dmae_host2host - copy data from to source address
* to a destination adress (for SRIOV) using the given ptt
......@@ -308,4 +322,37 @@ int qed_fw_rss_eng(struct qed_hwfn *p_hwfn,
int qed_final_cleanup(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt, u16 id, bool is_vf);
/**
* @brief qed_set_rxq_coalesce - Configure coalesce parameters for an Rx queue
* The fact that we can configure coalescing to up to 511, but on varying
* accuracy [the bigger the value the less accurate] up to a mistake of 3usec
* for the highest values.
*
* @param p_hwfn
* @param p_ptt
* @param coalesce - Coalesce value in micro seconds.
* @param qid - Queue index.
* @param qid - SB Id
*
* @return int
*/
int qed_set_rxq_coalesce(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
u16 coalesce, u8 qid, u16 sb_id);
/**
* @brief qed_set_txq_coalesce - Configure coalesce parameters for a Tx queue
* While the API allows setting coalescing per-qid, all tx queues sharing a
* SB should be in same range [i.e., either 0-0x7f, 0x80-0xff or 0x100-0x1ff]
* otherwise configuration would break.
*
* @param p_hwfn
* @param p_ptt
* @param coalesce - Coalesce value in micro seconds.
* @param qid - Queue index.
* @param qid - SB Id
*
* @return int
*/
int qed_set_txq_coalesce(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
u16 coalesce, u8 qid, u16 sb_id);
#endif
......@@ -768,6 +768,29 @@ int qed_dmae_host2grc(struct qed_hwfn *p_hwfn,
return rc;
}
int
qed_dmae_grc2host(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u32 grc_addr,
dma_addr_t dest_addr, u32 size_in_dwords, u32 flags)
{
u32 grc_addr_in_dw = grc_addr / sizeof(u32);
struct qed_dmae_params params;
int rc;
memset(&params, 0, sizeof(struct qed_dmae_params));
params.flags = flags;
mutex_lock(&p_hwfn->dmae_info.mutex);
rc = qed_dmae_execute_command(p_hwfn, p_ptt, grc_addr_in_dw,
dest_addr, QED_DMAE_ADDRESS_GRC,
QED_DMAE_ADDRESS_HOST_VIRT,
size_in_dwords, &params);
mutex_unlock(&p_hwfn->dmae_info.mutex);
return rc;
}
int
qed_dmae_host2host(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
......
......@@ -2418,6 +2418,7 @@ void qed_init_cau_sb_entry(struct qed_hwfn *p_hwfn,
{
struct qed_dev *cdev = p_hwfn->cdev;
u32 cau_state;
u8 timer_res;
memset(p_sb_entry, 0, sizeof(*p_sb_entry));
......@@ -2443,6 +2444,23 @@ void qed_init_cau_sb_entry(struct qed_hwfn *p_hwfn,
cdev->tx_coalesce_usecs = QED_CAU_DEF_TX_USECS;
}
/* Coalesce = (timeset << timer-res), timeset is 7bit wide */
if (cdev->rx_coalesce_usecs <= 0x7F)
timer_res = 0;
else if (cdev->rx_coalesce_usecs <= 0xFF)
timer_res = 1;
else
timer_res = 2;
SET_FIELD(p_sb_entry->params, CAU_SB_ENTRY_TIMER_RES0, timer_res);
if (cdev->tx_coalesce_usecs <= 0x7F)
timer_res = 0;
else if (cdev->tx_coalesce_usecs <= 0xFF)
timer_res = 1;
else
timer_res = 2;
SET_FIELD(p_sb_entry->params, CAU_SB_ENTRY_TIMER_RES1, timer_res);
SET_FIELD(p_sb_entry->data, CAU_SB_ENTRY_STATE0, cau_state);
SET_FIELD(p_sb_entry->data, CAU_SB_ENTRY_STATE1, cau_state);
}
......@@ -2484,17 +2502,28 @@ void qed_int_cau_conf_sb(struct qed_hwfn *p_hwfn,
/* Configure pi coalescing if set */
if (p_hwfn->cdev->int_coalescing_mode == QED_COAL_MODE_ENABLE) {
u8 timeset = p_hwfn->cdev->rx_coalesce_usecs >>
(QED_CAU_DEF_RX_TIMER_RES + 1);
u8 timeset, timer_res;
u8 num_tc = 1, i;
/* timeset = (coalesce >> timer-res), timeset is 7bit wide */
if (p_hwfn->cdev->rx_coalesce_usecs <= 0x7F)
timer_res = 0;
else if (p_hwfn->cdev->rx_coalesce_usecs <= 0xFF)
timer_res = 1;
else
timer_res = 2;
timeset = (u8)(p_hwfn->cdev->rx_coalesce_usecs >> timer_res);
qed_int_cau_conf_pi(p_hwfn, p_ptt, igu_sb_id, RX_PI,
QED_COAL_RX_STATE_MACHINE,
timeset);
timeset = p_hwfn->cdev->tx_coalesce_usecs >>
(QED_CAU_DEF_TX_TIMER_RES + 1);
if (p_hwfn->cdev->tx_coalesce_usecs <= 0x7F)
timer_res = 0;
else if (p_hwfn->cdev->tx_coalesce_usecs <= 0xFF)
timer_res = 1;
else
timer_res = 2;
timeset = (u8)(p_hwfn->cdev->tx_coalesce_usecs >> timer_res);
for (i = 0; i < num_tc; i++) {
qed_int_cau_conf_pi(p_hwfn, p_ptt,
igu_sb_id, TX_PI(i),
......@@ -3199,3 +3228,39 @@ void qed_int_disable_post_isr_release(struct qed_dev *cdev)
for_each_hwfn(cdev, i)
cdev->hwfns[i].b_int_requested = false;
}
int qed_int_set_timer_res(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
u8 timer_res, u16 sb_id, bool tx)
{
struct cau_sb_entry sb_entry;
int rc;
if (!p_hwfn->hw_init_done) {
DP_ERR(p_hwfn, "hardware not initialized yet\n");
return -EINVAL;
}
rc = qed_dmae_grc2host(p_hwfn, p_ptt, CAU_REG_SB_VAR_MEMORY +
sb_id * sizeof(u64),
(u64)(uintptr_t)&sb_entry, 2, 0);
if (rc) {
DP_ERR(p_hwfn, "dmae_grc2host failed %d\n", rc);
return rc;
}
if (tx)
SET_FIELD(sb_entry.params, CAU_SB_ENTRY_TIMER_RES1, timer_res);
else
SET_FIELD(sb_entry.params, CAU_SB_ENTRY_TIMER_RES0, timer_res);
rc = qed_dmae_host2grc(p_hwfn, p_ptt,
(u64)(uintptr_t)&sb_entry,
CAU_REG_SB_VAR_MEMORY +
sb_id * sizeof(u64), 2, 0);
if (rc) {
DP_ERR(p_hwfn, "dmae_host2grc failed %d\n", rc);
return rc;
}
return rc;
}
......@@ -389,6 +389,9 @@ void qed_init_cau_sb_entry(struct qed_hwfn *p_hwfn,
u16 vf_number,
u8 vf_valid);
int qed_int_set_timer_res(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
u8 timer_res, u16 sb_id, bool tx);
#define QED_MAPPING_MEMORY_SIZE(dev) (NUM_OF_SBS(dev))
#endif
......@@ -1303,6 +1303,38 @@ static int qed_drain(struct qed_dev *cdev)
return 0;
}
static void qed_get_coalesce(struct qed_dev *cdev, u16 *rx_coal, u16 *tx_coal)
{
*rx_coal = cdev->rx_coalesce_usecs;
*tx_coal = cdev->tx_coalesce_usecs;
}
static int qed_set_coalesce(struct qed_dev *cdev, u16 rx_coal, u16 tx_coal,
u8 qid, u16 sb_id)
{
struct qed_hwfn *hwfn;
struct qed_ptt *ptt;
int hwfn_index;
int status = 0;
hwfn_index = qid % cdev->num_hwfns;
hwfn = &cdev->hwfns[hwfn_index];
ptt = qed_ptt_acquire(hwfn);
if (!ptt)
return -EAGAIN;
status = qed_set_rxq_coalesce(hwfn, ptt, rx_coal,
qid / cdev->num_hwfns, sb_id);
if (status)
goto out;
status = qed_set_txq_coalesce(hwfn, ptt, tx_coal,
qid / cdev->num_hwfns, sb_id);
out:
qed_ptt_release(hwfn, ptt);
return status;
}
static int qed_set_led(struct qed_dev *cdev, enum qed_led_mode mode)
{
struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev);
......@@ -1349,5 +1381,7 @@ const struct qed_common_ops qed_common_ops_pass = {
.update_msglvl = &qed_init_dp,
.chain_alloc = &qed_chain_alloc,
.chain_free = &qed_chain_free,
.get_coalesce = &qed_get_coalesce,
.set_coalesce = &qed_set_coalesce,
.set_led = &qed_set_led,
};
......@@ -80,6 +80,8 @@
0x1f00000UL
#define BAR0_MAP_REG_TSDM_RAM \
0x1c80000UL
#define BAR0_MAP_REG_XSDM_RAM \
0x1e00000UL
#define NIG_REG_RX_LLH_BRB_GATE_DNTFWD_PERPF \
0x5011f4UL
#define PRS_REG_SEARCH_TCP \
......
......@@ -426,6 +426,57 @@ static u32 qede_get_link(struct net_device *dev)
return current_link.link_up;
}
static int qede_get_coalesce(struct net_device *dev,
struct ethtool_coalesce *coal)
{
struct qede_dev *edev = netdev_priv(dev);
memset(coal, 0, sizeof(struct ethtool_coalesce));
edev->ops->common->get_coalesce(edev->cdev,
(u16 *)&coal->rx_coalesce_usecs,
(u16 *)&coal->tx_coalesce_usecs);
return 0;
}
static int qede_set_coalesce(struct net_device *dev,
struct ethtool_coalesce *coal)
{
struct qede_dev *edev = netdev_priv(dev);
int i, rc = 0;
u16 rxc, txc;
u8 sb_id;
if (!netif_running(dev)) {
DP_INFO(edev, "Interface is down\n");
return -EINVAL;
}
if (coal->rx_coalesce_usecs > QED_COALESCE_MAX ||
coal->tx_coalesce_usecs > QED_COALESCE_MAX) {
DP_INFO(edev,
"Can't support requested %s coalesce value [max supported value %d]\n",
coal->rx_coalesce_usecs > QED_COALESCE_MAX ? "rx"
: "tx",
QED_COALESCE_MAX);
return -EINVAL;
}
rxc = (u16)coal->rx_coalesce_usecs;
txc = (u16)coal->tx_coalesce_usecs;
for_each_rss(i) {
sb_id = edev->fp_array[i].sb_info->igu_sb_id;
rc = edev->ops->common->set_coalesce(edev->cdev, rxc, txc,
(u8)i, sb_id);
if (rc) {
DP_INFO(edev, "Set coalesce error, rc = %d\n", rc);
return rc;
}
}
return rc;
}
static void qede_get_ringparam(struct net_device *dev,
struct ethtool_ringparam *ering)
{
......@@ -1139,6 +1190,8 @@ static const struct ethtool_ops qede_ethtool_ops = {
.set_msglevel = qede_set_msglevel,
.nway_reset = qede_nway_reset,
.get_link = qede_get_link,
.get_coalesce = qede_get_coalesce,
.set_coalesce = qede_set_coalesce,
.get_ringparam = qede_get_ringparam,
.set_ringparam = qede_set_ringparam,
.get_pauseparam = qede_get_pauseparam,
......
......@@ -488,6 +488,30 @@ struct qed_common_ops {
void (*chain_free)(struct qed_dev *cdev,
struct qed_chain *p_chain);
/**
* @brief get_coalesce - Get coalesce parameters in usec
*
* @param cdev
* @param rx_coal - Rx coalesce value in usec
* @param tx_coal - Tx coalesce value in usec
*
*/
void (*get_coalesce)(struct qed_dev *cdev, u16 *rx_coal, u16 *tx_coal);
/**
* @brief set_coalesce - Configure Rx coalesce value in usec
*
* @param cdev
* @param rx_coal - Rx coalesce value in usec
* @param tx_coal - Tx coalesce value in usec
* @param qid - Queue index
* @param sb_id - Status Block Id
*
* @return 0 on success, error otherwise.
*/
int (*set_coalesce)(struct qed_dev *cdev, u16 rx_coal, u16 tx_coal,
u8 qid, u16 sb_id);
/**
* @brief set_led - Configure LED mode
*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment