Skip to content

Commit

Permalink
Merge branch 'thunderx-fixes'
Browse files Browse the repository at this point in the history
Aleksey Makarov says:

====================
net: thunderx: Misc fixes

Miscellaneous fixes for the ThunderX VNIC driver

All the patches can be applied individually.
It's ok to drop some if the maintainer feels uncomfortable
with applying for 4.2.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Jul 30, 2015
2 parents c8507fb + 60f83c8 commit f68b123
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 37 deletions.
12 changes: 11 additions & 1 deletion drivers/net/ethernet/cavium/thunder/nic.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,15 @@
*/
#define NICPF_CLK_PER_INT_TICK 2

/* Time to wait before we decide that a SQ is stuck.
*
* Since both pkt rx and tx notifications are done with same CQ,
* when packets are being received at very high rate (eg: L2 forwarding)
* then freeing transmitted skbs will be delayed and watchdog
* will kick in, resetting interface. Hence keeping this value high.
*/
#define NICVF_TX_TIMEOUT (50 * HZ)

struct nicvf_cq_poll {
u8 cq_idx; /* Completion queue index */
struct napi_struct napi;
Expand Down Expand Up @@ -216,8 +225,9 @@ struct nicvf_drv_stats {
/* Tx */
u64 tx_frames_ok;
u64 tx_drops;
u64 tx_busy;
u64 tx_tso;
u64 txq_stop;
u64 txq_wake;
};

struct nicvf {
Expand Down
26 changes: 16 additions & 10 deletions drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,10 @@ static const struct nicvf_stat nicvf_drv_stats[] = {
NICVF_DRV_STAT(rx_frames_jumbo),
NICVF_DRV_STAT(rx_drops),
NICVF_DRV_STAT(tx_frames_ok),
NICVF_DRV_STAT(tx_busy),
NICVF_DRV_STAT(tx_tso),
NICVF_DRV_STAT(tx_drops),
NICVF_DRV_STAT(txq_stop),
NICVF_DRV_STAT(txq_wake),
};

static const struct nicvf_stat nicvf_queue_stats[] = {
Expand Down Expand Up @@ -126,6 +127,7 @@ static void nicvf_set_msglevel(struct net_device *netdev, u32 lvl)

static void nicvf_get_strings(struct net_device *netdev, u32 sset, u8 *data)
{
struct nicvf *nic = netdev_priv(netdev);
int stats, qidx;

if (sset != ETH_SS_STATS)
Expand All @@ -141,15 +143,15 @@ static void nicvf_get_strings(struct net_device *netdev, u32 sset, u8 *data)
data += ETH_GSTRING_LEN;
}

for (qidx = 0; qidx < MAX_RCV_QUEUES_PER_QS; qidx++) {
for (qidx = 0; qidx < nic->qs->rq_cnt; qidx++) {
for (stats = 0; stats < nicvf_n_queue_stats; stats++) {
sprintf(data, "rxq%d: %s", qidx,
nicvf_queue_stats[stats].name);
data += ETH_GSTRING_LEN;
}
}

for (qidx = 0; qidx < MAX_SND_QUEUES_PER_QS; qidx++) {
for (qidx = 0; qidx < nic->qs->sq_cnt; qidx++) {
for (stats = 0; stats < nicvf_n_queue_stats; stats++) {
sprintf(data, "txq%d: %s", qidx,
nicvf_queue_stats[stats].name);
Expand All @@ -170,12 +172,14 @@ static void nicvf_get_strings(struct net_device *netdev, u32 sset, u8 *data)

static int nicvf_get_sset_count(struct net_device *netdev, int sset)
{
struct nicvf *nic = netdev_priv(netdev);

if (sset != ETH_SS_STATS)
return -EINVAL;

return nicvf_n_hw_stats + nicvf_n_drv_stats +
(nicvf_n_queue_stats *
(MAX_RCV_QUEUES_PER_QS + MAX_SND_QUEUES_PER_QS)) +
(nic->qs->rq_cnt + nic->qs->sq_cnt)) +
BGX_RX_STATS_COUNT + BGX_TX_STATS_COUNT;
}

Expand All @@ -197,13 +201,13 @@ static void nicvf_get_ethtool_stats(struct net_device *netdev,
*(data++) = ((u64 *)&nic->drv_stats)
[nicvf_drv_stats[stat].index];

for (qidx = 0; qidx < MAX_RCV_QUEUES_PER_QS; qidx++) {
for (qidx = 0; qidx < nic->qs->rq_cnt; qidx++) {
for (stat = 0; stat < nicvf_n_queue_stats; stat++)
*(data++) = ((u64 *)&nic->qs->rq[qidx].stats)
[nicvf_queue_stats[stat].index];
}

for (qidx = 0; qidx < MAX_SND_QUEUES_PER_QS; qidx++) {
for (qidx = 0; qidx < nic->qs->sq_cnt; qidx++) {
for (stat = 0; stat < nicvf_n_queue_stats; stat++)
*(data++) = ((u64 *)&nic->qs->sq[qidx].stats)
[nicvf_queue_stats[stat].index];
Expand Down Expand Up @@ -543,6 +547,7 @@ static int nicvf_set_channels(struct net_device *dev,
{
struct nicvf *nic = netdev_priv(dev);
int err = 0;
bool if_up = netif_running(dev);

if (!channel->rx_count || !channel->tx_count)
return -EINVAL;
Expand All @@ -551,6 +556,9 @@ static int nicvf_set_channels(struct net_device *dev,
if (channel->tx_count > MAX_SND_QUEUES_PER_QS)
return -EINVAL;

if (if_up)
nicvf_stop(dev);

nic->qs->rq_cnt = channel->rx_count;
nic->qs->sq_cnt = channel->tx_count;
nic->qs->cq_cnt = max(nic->qs->rq_cnt, nic->qs->sq_cnt);
Expand All @@ -559,11 +567,9 @@ static int nicvf_set_channels(struct net_device *dev,
if (err)
return err;

if (!netif_running(dev))
return err;
if (if_up)
nicvf_open(dev);

nicvf_stop(dev);
nicvf_open(dev);
netdev_info(dev, "Setting num Tx rings to %d, Rx rings to %d success\n",
nic->qs->sq_cnt, nic->qs->rq_cnt);

Expand Down
55 changes: 39 additions & 16 deletions drivers/net/ethernet/cavium/thunder/nicvf_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ static void nicvf_handle_mbx_intr(struct nicvf *nic)
nic->duplex == DUPLEX_FULL ?
"Full duplex" : "Half duplex");
netif_carrier_on(nic->netdev);
netif_tx_wake_all_queues(nic->netdev);
netif_tx_start_all_queues(nic->netdev);
} else {
netdev_info(nic->netdev, "%s: Link is Down\n",
nic->netdev->name);
Expand Down Expand Up @@ -425,6 +425,7 @@ static void nicvf_snd_pkt_handler(struct net_device *netdev,
if (skb) {
prefetch(skb);
dev_consume_skb_any(skb);
sq->skbuff[cqe_tx->sqe_ptr] = (u64)NULL;
}
}

Expand Down Expand Up @@ -476,12 +477,13 @@ static void nicvf_rcv_pkt_handler(struct net_device *netdev,
static int nicvf_cq_intr_handler(struct net_device *netdev, u8 cq_idx,
struct napi_struct *napi, int budget)
{
int processed_cqe, work_done = 0;
int processed_cqe, work_done = 0, tx_done = 0;
int cqe_count, cqe_head;
struct nicvf *nic = netdev_priv(netdev);
struct queue_set *qs = nic->qs;
struct cmp_queue *cq = &qs->cq[cq_idx];
struct cqe_rx_t *cq_desc;
struct netdev_queue *txq;

spin_lock_bh(&cq->lock);
loop:
Expand All @@ -496,8 +498,8 @@ static int nicvf_cq_intr_handler(struct net_device *netdev, u8 cq_idx,
cqe_head = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_HEAD, cq_idx) >> 9;
cqe_head &= 0xFFFF;

netdev_dbg(nic->netdev, "%s cqe_count %d cqe_head %d\n",
__func__, cqe_count, cqe_head);
netdev_dbg(nic->netdev, "%s CQ%d cqe_count %d cqe_head %d\n",
__func__, cq_idx, cqe_count, cqe_head);
while (processed_cqe < cqe_count) {
/* Get the CQ descriptor */
cq_desc = (struct cqe_rx_t *)GET_CQ_DESC(cq, cqe_head);
Expand All @@ -511,8 +513,8 @@ static int nicvf_cq_intr_handler(struct net_device *netdev, u8 cq_idx,
break;
}

netdev_dbg(nic->netdev, "cq_desc->cqe_type %d\n",
cq_desc->cqe_type);
netdev_dbg(nic->netdev, "CQ%d cq_desc->cqe_type %d\n",
cq_idx, cq_desc->cqe_type);
switch (cq_desc->cqe_type) {
case CQE_TYPE_RX:
nicvf_rcv_pkt_handler(netdev, napi, cq,
Expand All @@ -522,6 +524,7 @@ static int nicvf_cq_intr_handler(struct net_device *netdev, u8 cq_idx,
case CQE_TYPE_SEND:
nicvf_snd_pkt_handler(netdev, cq,
(void *)cq_desc, CQE_TYPE_SEND);
tx_done++;
break;
case CQE_TYPE_INVALID:
case CQE_TYPE_RX_SPLIT:
Expand All @@ -532,8 +535,9 @@ static int nicvf_cq_intr_handler(struct net_device *netdev, u8 cq_idx,
}
processed_cqe++;
}
netdev_dbg(nic->netdev, "%s processed_cqe %d work_done %d budget %d\n",
__func__, processed_cqe, work_done, budget);
netdev_dbg(nic->netdev,
"%s CQ%d processed_cqe %d work_done %d budget %d\n",
__func__, cq_idx, processed_cqe, work_done, budget);

/* Ring doorbell to inform H/W to reuse processed CQEs */
nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_DOOR,
Expand All @@ -543,6 +547,19 @@ static int nicvf_cq_intr_handler(struct net_device *netdev, u8 cq_idx,
goto loop;

done:
/* Wakeup TXQ if its stopped earlier due to SQ full */
if (tx_done) {
txq = netdev_get_tx_queue(netdev, cq_idx);
if (netif_tx_queue_stopped(txq)) {
netif_tx_start_queue(txq);
nic->drv_stats.txq_wake++;
if (netif_msg_tx_err(nic))
netdev_warn(netdev,
"%s: Transmit queue wakeup SQ%d\n",
netdev->name, cq_idx);
}
}

spin_unlock_bh(&cq->lock);
return work_done;
}
Expand All @@ -554,15 +571,10 @@ static int nicvf_poll(struct napi_struct *napi, int budget)
struct net_device *netdev = napi->dev;
struct nicvf *nic = netdev_priv(netdev);
struct nicvf_cq_poll *cq;
struct netdev_queue *txq;

cq = container_of(napi, struct nicvf_cq_poll, napi);
work_done = nicvf_cq_intr_handler(netdev, cq->cq_idx, napi, budget);

txq = netdev_get_tx_queue(netdev, cq->cq_idx);
if (netif_tx_queue_stopped(txq))
netif_tx_wake_queue(txq);

if (work_done < budget) {
/* Slow packet rate, exit polling */
napi_complete(napi);
Expand Down Expand Up @@ -833,9 +845,9 @@ static netdev_tx_t nicvf_xmit(struct sk_buff *skb, struct net_device *netdev)
return NETDEV_TX_OK;
}

if (!nicvf_sq_append_skb(nic, skb) && !netif_tx_queue_stopped(txq)) {
if (!netif_tx_queue_stopped(txq) && !nicvf_sq_append_skb(nic, skb)) {
netif_tx_stop_queue(txq);
nic->drv_stats.tx_busy++;
nic->drv_stats.txq_stop++;
if (netif_msg_tx_err(nic))
netdev_warn(netdev,
"%s: Transmit ring full, stopping SQ%d\n",
Expand All @@ -859,7 +871,6 @@ int nicvf_stop(struct net_device *netdev)
nicvf_send_msg_to_pf(nic, &mbx);

netif_carrier_off(netdev);
netif_tx_disable(netdev);

/* Disable RBDR & QS error interrupts */
for (qidx = 0; qidx < qs->rbdr_cnt; qidx++) {
Expand Down Expand Up @@ -894,6 +905,8 @@ int nicvf_stop(struct net_device *netdev)
kfree(cq_poll);
}

netif_tx_disable(netdev);

/* Free resources */
nicvf_config_data_transfer(nic, false);

Expand Down Expand Up @@ -988,6 +1001,9 @@ int nicvf_open(struct net_device *netdev)
for (qidx = 0; qidx < qs->rbdr_cnt; qidx++)
nicvf_enable_intr(nic, NICVF_INTR_RBDR, qidx);

nic->drv_stats.txq_stop = 0;
nic->drv_stats.txq_wake = 0;

netif_carrier_on(netdev);
netif_tx_start_all_queues(netdev);

Expand Down Expand Up @@ -1278,6 +1294,7 @@ static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
netdev->hw_features = netdev->features;

netdev->netdev_ops = &nicvf_netdev_ops;
netdev->watchdog_timeo = NICVF_TX_TIMEOUT;

INIT_WORK(&nic->reset_task, nicvf_reset_task);

Expand Down Expand Up @@ -1318,11 +1335,17 @@ static void nicvf_remove(struct pci_dev *pdev)
pci_disable_device(pdev);
}

static void nicvf_shutdown(struct pci_dev *pdev)
{
nicvf_remove(pdev);
}

static struct pci_driver nicvf_driver = {
.name = DRV_NAME,
.id_table = nicvf_id_table,
.probe = nicvf_probe,
.remove = nicvf_remove,
.shutdown = nicvf_shutdown,
};

static int __init nicvf_init_module(void)
Expand Down
17 changes: 11 additions & 6 deletions drivers/net/ethernet/cavium/thunder/nicvf_queues.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,11 @@ static inline int nicvf_alloc_rcv_buffer(struct nicvf *nic, gfp_t gfp,

/* Allocate a new page */
if (!nic->rb_page) {
nic->rb_page = alloc_pages(gfp | __GFP_COMP, order);
nic->rb_page = alloc_pages(gfp | __GFP_COMP | __GFP_NOWARN,
order);
if (!nic->rb_page) {
netdev_err(nic->netdev, "Failed to allocate new rcv buffer\n");
netdev_err(nic->netdev,
"Failed to allocate new rcv buffer\n");
return -ENOMEM;
}
nic->rb_page_offset = 0;
Expand Down Expand Up @@ -382,7 +384,8 @@ static void nicvf_free_snd_queue(struct nicvf *nic, struct snd_queue *sq)
return;

if (sq->tso_hdrs)
dma_free_coherent(&nic->pdev->dev, sq->dmem.q_len,
dma_free_coherent(&nic->pdev->dev,
sq->dmem.q_len * TSO_HEADER_SIZE,
sq->tso_hdrs, sq->tso_hdrs_phys);

kfree(sq->skbuff);
Expand Down Expand Up @@ -863,10 +866,11 @@ void nicvf_sq_free_used_descs(struct net_device *netdev, struct snd_queue *sq,
continue;
}
skb = (struct sk_buff *)sq->skbuff[sq->head];
if (skb)
dev_kfree_skb_any(skb);
atomic64_add(1, (atomic64_t *)&netdev->stats.tx_packets);
atomic64_add(hdr->tot_len,
(atomic64_t *)&netdev->stats.tx_bytes);
dev_kfree_skb_any(skb);
nicvf_put_sq_desc(sq, hdr->subdesc_cnt + 1);
}
}
Expand Down Expand Up @@ -992,7 +996,7 @@ static inline void nicvf_sq_add_gather_subdesc(struct snd_queue *sq, int qentry,

memset(gather, 0, SND_QUEUE_DESC_SIZE);
gather->subdesc_type = SQ_DESC_TYPE_GATHER;
gather->ld_type = NIC_SEND_LD_TYPE_E_LDWB;
gather->ld_type = NIC_SEND_LD_TYPE_E_LDD;
gather->size = size;
gather->addr = data;
}
Expand Down Expand Up @@ -1048,7 +1052,7 @@ static int nicvf_sq_append_tso(struct nicvf *nic, struct snd_queue *sq,
}
nicvf_sq_add_hdr_subdesc(sq, hdr_qentry,
seg_subdescs - 1, skb, seg_len);
sq->skbuff[hdr_qentry] = 0;
sq->skbuff[hdr_qentry] = (u64)NULL;
qentry = nicvf_get_nxt_sqentry(sq, qentry);

desc_cnt += seg_subdescs;
Expand All @@ -1062,6 +1066,7 @@ static int nicvf_sq_append_tso(struct nicvf *nic, struct snd_queue *sq,
/* Inform HW to xmit all TSO segments */
nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_DOOR,
skb_get_queue_mapping(skb), desc_cnt);
nic->drv_stats.tx_tso++;
return 1;
}

Expand Down
Loading

0 comments on commit f68b123

Please sign in to comment.