Commit 36195d86 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'liquidio-next'



Raghu Vatsavayi says:

====================
liquidio: updates and bug fixes

Please consider following patch series for liquidio bug fixes
and updates on top of net-next. Following patches should be
applied in the following order as some of them depend on
earlier patches in the series.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents b38066da 4b129ae3
Loading
Loading
Loading
Loading
+20 −19
Original line number Diff line number Diff line
@@ -367,7 +367,8 @@ void lio_cn6xxx_enable_io_queues(struct octeon_device *oct)

void lio_cn6xxx_disable_io_queues(struct octeon_device *oct)
{
	u32 mask, i, loop = HZ;
	int i;
	u32 mask, loop = HZ;
	u32 d32;

	/* Reset the Enable bits for Input Queues. */
@@ -376,7 +377,7 @@ void lio_cn6xxx_disable_io_queues(struct octeon_device *oct)
	octeon_write_csr(oct, CN6XXX_SLI_PKT_INSTR_ENB, mask);

	/* Wait until hardware indicates that the queues are out of reset. */
	mask = oct->io_qmask.iq;
	mask = (u32)oct->io_qmask.iq;
	d32 = octeon_read_csr(oct, CN6XXX_SLI_PORT_IN_RST_IQ);
	while (((d32 & mask) != mask) && loop--) {
		d32 = octeon_read_csr(oct, CN6XXX_SLI_PORT_IN_RST_IQ);
@@ -384,8 +385,8 @@ void lio_cn6xxx_disable_io_queues(struct octeon_device *oct)
	}

	/* Reset the doorbell register for each Input queue. */
	for (i = 0; i < MAX_OCTEON_INSTR_QUEUES; i++) {
		if (!(oct->io_qmask.iq & (1UL << i)))
	for (i = 0; i < MAX_OCTEON_INSTR_QUEUES(oct); i++) {
		if (!(oct->io_qmask.iq & (1ULL << i)))
			continue;
		octeon_write_csr(oct, CN6XXX_SLI_IQ_DOORBELL(i), 0xFFFFFFFF);
		d32 = octeon_read_csr(oct, CN6XXX_SLI_IQ_DOORBELL(i));
@@ -398,7 +399,7 @@ void lio_cn6xxx_disable_io_queues(struct octeon_device *oct)

	/* Wait until hardware indicates that the queues are out of reset. */
	loop = HZ;
	mask = oct->io_qmask.oq;
	mask = (u32)oct->io_qmask.oq;
	d32 = octeon_read_csr(oct, CN6XXX_SLI_PORT_IN_RST_OQ);
	while (((d32 & mask) != mask) && loop--) {
		d32 = octeon_read_csr(oct, CN6XXX_SLI_PORT_IN_RST_OQ);
@@ -408,8 +409,8 @@ void lio_cn6xxx_disable_io_queues(struct octeon_device *oct)

	/* Reset the doorbell register for each Output queue. */
	/* for (i = 0; i < oct->num_oqs; i++) { */
	for (i = 0; i < MAX_OCTEON_OUTPUT_QUEUES; i++) {
		if (!(oct->io_qmask.oq & (1UL << i)))
	for (i = 0; i < MAX_OCTEON_OUTPUT_QUEUES(oct); i++) {
		if (!(oct->io_qmask.oq & (1ULL << i)))
			continue;
		octeon_write_csr(oct, CN6XXX_SLI_OQ_PKTS_CREDIT(i), 0xFFFFFFFF);
		d32 = octeon_read_csr(oct, CN6XXX_SLI_OQ_PKTS_CREDIT(i));
@@ -429,16 +430,16 @@ void lio_cn6xxx_disable_io_queues(struct octeon_device *oct)

void lio_cn6xxx_reinit_regs(struct octeon_device *oct)
{
	u32 i;
	int i;

	for (i = 0; i < MAX_OCTEON_INSTR_QUEUES; i++) {
		if (!(oct->io_qmask.iq & (1UL << i)))
	for (i = 0; i < MAX_OCTEON_INSTR_QUEUES(oct); i++) {
		if (!(oct->io_qmask.iq & (1ULL << i)))
			continue;
		oct->fn_list.setup_iq_regs(oct, i);
	}

	for (i = 0; i < MAX_OCTEON_OUTPUT_QUEUES; i++) {
		if (!(oct->io_qmask.oq & (1UL << i)))
	for (i = 0; i < MAX_OCTEON_OUTPUT_QUEUES(oct); i++) {
		if (!(oct->io_qmask.oq & (1ULL << i)))
			continue;
		oct->fn_list.setup_oq_regs(oct, i);
	}
@@ -450,8 +451,8 @@ void lio_cn6xxx_reinit_regs(struct octeon_device *oct)
	oct->fn_list.enable_io_queues(oct);

	/* for (i = 0; i < oct->num_oqs; i++) { */
	for (i = 0; i < MAX_OCTEON_OUTPUT_QUEUES; i++) {
		if (!(oct->io_qmask.oq & (1UL << i)))
	for (i = 0; i < MAX_OCTEON_OUTPUT_QUEUES(oct); i++) {
		if (!(oct->io_qmask.oq & (1ULL << i)))
			continue;
		writel(oct->droq[i]->max_count, oct->droq[i]->pkts_credit_reg);
	}
@@ -495,8 +496,7 @@ u32 lio_cn6xxx_bar1_idx_read(struct octeon_device *oct, u32 idx)
}

u32
lio_cn6xxx_update_read_index(struct octeon_device *oct __attribute__((unused)),
			     struct octeon_instr_queue *iq)
lio_cn6xxx_update_read_index(struct octeon_instr_queue *iq)
{
	u32 new_idx = readl(iq->inst_cnt_reg);

@@ -557,7 +557,8 @@ lio_cn6xxx_process_pcie_error_intr(struct octeon_device *oct, u64 intr64)
int lio_cn6xxx_process_droq_intr_regs(struct octeon_device *oct)
{
	struct octeon_droq *droq;
	u32 oq_no, pkt_count, droq_time_mask, droq_mask, droq_int_enb;
	int oq_no;
	u32 pkt_count, droq_time_mask, droq_mask, droq_int_enb;
	u32 droq_cnt_enb, droq_cnt_mask;

	droq_cnt_enb = octeon_read_csr(oct, CN6XXX_SLI_PKT_CNT_INT_ENB);
@@ -573,8 +574,8 @@ int lio_cn6xxx_process_droq_intr_regs(struct octeon_device *oct)
	oct->droq_intr = 0;

	/* for (oq_no = 0; oq_no < oct->num_oqs; oq_no++) { */
	for (oq_no = 0; oq_no < MAX_OCTEON_OUTPUT_QUEUES; oq_no++) {
		if (!(droq_mask & (1 << oq_no)))
	for (oq_no = 0; oq_no < MAX_OCTEON_OUTPUT_QUEUES(oct); oq_no++) {
		if (!(droq_mask & (1ULL << oq_no)))
			continue;

		droq = oct->droq[oq_no];
+1 −2
Original line number Diff line number Diff line
@@ -91,8 +91,7 @@ void lio_cn6xxx_bar1_idx_setup(struct octeon_device *oct, u64 core_addr,
void lio_cn6xxx_bar1_idx_write(struct octeon_device *oct, u32 idx, u32 mask);
u32 lio_cn6xxx_bar1_idx_read(struct octeon_device *oct, u32 idx);
u32
lio_cn6xxx_update_read_index(struct octeon_device *oct __attribute__((unused)),
			     struct octeon_instr_queue *iq);
lio_cn6xxx_update_read_index(struct octeon_instr_queue *iq);
void lio_cn6xxx_enable_interrupt(void *chip);
void lio_cn6xxx_disable_interrupt(void *chip);
void cn6xxx_get_pcie_qlmport(struct octeon_device *oct);
+710 −189

File changed.

Preview size limit exceeded, changes collapsed.

+300 −98
Original line number Diff line number Diff line
@@ -72,6 +72,9 @@ MODULE_PARM_DESC(console_bitmask,

#define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK)

#define INCR_INSTRQUEUE_PKT_COUNT(octeon_dev_ptr, iq_no, field, count)  \
	(octeon_dev_ptr->instr_queue[iq_no]->stats.field += count)

static int debug = -1;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "NETIF_MSG debug bits");
@@ -224,8 +227,8 @@ static void octeon_droq_bh(unsigned long pdev)
		(struct octeon_device_priv *)oct->priv;

	/* for (q_no = 0; q_no < oct->num_oqs; q_no++) { */
	for (q_no = 0; q_no < MAX_OCTEON_OUTPUT_QUEUES; q_no++) {
		if (!(oct->io_qmask.oq & (1UL << q_no)))
	for (q_no = 0; q_no < MAX_OCTEON_OUTPUT_QUEUES(oct); q_no++) {
		if (!(oct->io_qmask.oq & (1ULL << q_no)))
			continue;
		reschedule |= octeon_droq_process_packets(oct, oct->droq[q_no],
							  MAX_PACKET_BUDGET);
@@ -245,8 +248,8 @@ static int lio_wait_for_oq_pkts(struct octeon_device *oct)
	do {
		pending_pkts = 0;

		for (i = 0; i < MAX_OCTEON_OUTPUT_QUEUES; i++) {
			if (!(oct->io_qmask.oq & (1UL << i)))
		for (i = 0; i < MAX_OCTEON_OUTPUT_QUEUES(oct); i++) {
			if (!(oct->io_qmask.oq & (1ULL << i)))
				continue;
			pkt_cnt += octeon_droq_check_hw_for_pkts(oct,
								 oct->droq[i]);
@@ -396,10 +399,10 @@ static inline void pcierror_quiesce_device(struct octeon_device *oct)
		dev_err(&oct->pci_dev->dev, "There were pending requests\n");

	/* Force all requests waiting to be fetched by OCTEON to complete. */
	for (i = 0; i < MAX_OCTEON_INSTR_QUEUES; i++) {
	for (i = 0; i < MAX_OCTEON_INSTR_QUEUES(oct); i++) {
		struct octeon_instr_queue *iq;

		if (!(oct->io_qmask.iq & (1UL << i)))
		if (!(oct->io_qmask.iq & (1ULL << i)))
			continue;
		iq = oct->instr_queue[i];

@@ -409,7 +412,7 @@ static inline void pcierror_quiesce_device(struct octeon_device *oct)
			iq->octeon_read_index = iq->host_write_index;
			iq->stats.instr_processed +=
				atomic_read(&iq->instr_pending);
			lio_process_iq_request_list(oct, iq);
			lio_process_iq_request_list(oct, iq, 0);
			spin_unlock_bh(&iq->lock);
		}
	}
@@ -682,13 +685,24 @@ static inline void txqs_start(struct net_device *netdev)
 */
static inline void txqs_wake(struct net_device *netdev)
{
	struct lio *lio = GET_LIO(netdev);

	if (netif_is_multiqueue(netdev)) {
		int i;

		for (i = 0; i < netdev->num_tx_queues; i++)
			if (__netif_subqueue_stopped(netdev, i))
		for (i = 0; i < netdev->num_tx_queues; i++) {
			int qno = lio->linfo.txpciq[i %
				(lio->linfo.num_txpciq)].s.q_no;

			if (__netif_subqueue_stopped(netdev, i)) {
				INCR_INSTRQUEUE_PKT_COUNT(lio->oct_dev, qno,
							  tx_restart, 1);
				netif_wake_subqueue(netdev, i);
			}
		}
	} else {
		INCR_INSTRQUEUE_PKT_COUNT(lio->oct_dev, lio->txq,
					  tx_restart, 1);
		netif_wake_queue(netdev);
	}
}
@@ -763,6 +777,8 @@ static inline int check_txq_status(struct lio *lio)
				continue;
			if (__netif_subqueue_stopped(lio->netdev, q)) {
				wake_q(lio->netdev, q);
				INCR_INSTRQUEUE_PKT_COUNT(lio->oct_dev, iq,
							  tx_restart, 1);
				ret_val++;
			}
		}
@@ -770,6 +786,8 @@ static inline int check_txq_status(struct lio *lio)
		if (octnet_iq_is_full(lio->oct_dev, lio->txq))
			return 0;
		wake_q(lio->netdev, lio->txq);
		INCR_INSTRQUEUE_PKT_COUNT(lio->oct_dev, lio->txq,
					  tx_restart, 1);
		ret_val = 1;
	}
	return ret_val;
@@ -959,6 +977,42 @@ static inline void update_link_status(struct net_device *netdev,
	}
}

/* Runs in interrupt context. */
static void update_txq_status(struct octeon_device *oct, int iq_num)
{
	struct net_device *netdev;
	struct lio *lio;
	struct octeon_instr_queue *iq = oct->instr_queue[iq_num];

	/*octeon_update_iq_read_idx(oct, iq);*/

	netdev = oct->props[iq->ifidx].netdev;

	/* This is needed because the first IQ does not have
	 * a netdev associated with it.
	 */
	if (!netdev)
		return;

	lio = GET_LIO(netdev);
	if (netif_is_multiqueue(netdev)) {
		if (__netif_subqueue_stopped(netdev, iq->q_index) &&
		    lio->linfo.link.s.link_up &&
		    (!octnet_iq_is_full(oct, iq_num))) {
			INCR_INSTRQUEUE_PKT_COUNT(lio->oct_dev, iq_num,
						  tx_restart, 1);
			netif_wake_subqueue(netdev, iq->q_index);
		} else {
			if (!octnet_iq_is_full(oct, lio->txq)) {
				INCR_INSTRQUEUE_PKT_COUNT(lio->oct_dev,
							  lio->txq,
							  tx_restart, 1);
				wake_q(netdev, lio->txq);
			}
		}
	}
}

/**
 * \brief Droq packet processor sceduler
 * @param oct octeon device
@@ -972,8 +1026,9 @@ void liquidio_schedule_droq_pkt_handlers(struct octeon_device *oct)
	struct octeon_droq *droq;

	if (oct->int_status & OCT_DEV_INTR_PKT_DATA) {
		for (oq_no = 0; oq_no < MAX_OCTEON_OUTPUT_QUEUES; oq_no++) {
			if (!(oct->droq_intr & (1 << oq_no)))
		for (oq_no = 0; oq_no < MAX_OCTEON_OUTPUT_QUEUES(oct);
		     oq_no++) {
			if (!(oct->droq_intr & (1ULL << oq_no)))
				continue;

			droq = oct->droq[oq_no];
@@ -1084,6 +1139,9 @@ static int liquidio_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
		return -ENOMEM;
	}

	oct_dev->rx_pause = 1;
	oct_dev->tx_pause = 1;

	dev_dbg(&oct_dev->pci_dev->dev, "Device is ready\n");

	return 0;
@@ -1149,19 +1207,13 @@ static void octeon_destroy_resources(struct octeon_device *oct)
		if (oct->flags & LIO_FLAG_MSI_ENABLED)
			pci_disable_msi(oct->pci_dev);

		/* Soft reset the octeon device before exiting */
		oct->fn_list.soft_reset(oct);

		/* Disable the device, releasing the PCI INT */
		pci_disable_device(oct->pci_dev);

		/* fallthrough */
	case OCT_DEV_IN_RESET:
	case OCT_DEV_DROQ_INIT_DONE:
		/*atomic_set(&oct->status, OCT_DEV_DROQ_INIT_DONE);*/
		mdelay(100);
		for (i = 0; i < MAX_OCTEON_OUTPUT_QUEUES; i++) {
			if (!(oct->io_qmask.oq & (1UL << i)))
		for (i = 0; i < MAX_OCTEON_OUTPUT_QUEUES(oct); i++) {
			if (!(oct->io_qmask.oq & (1ULL << i)))
				continue;
			octeon_delete_droq(oct, i);
		}
@@ -1188,8 +1240,8 @@ static void octeon_destroy_resources(struct octeon_device *oct)

		/* fallthrough */
	case OCT_DEV_INSTR_QUEUE_INIT_DONE:
		for (i = 0; i < MAX_OCTEON_INSTR_QUEUES; i++) {
			if (!(oct->io_qmask.iq & (1UL << i)))
		for (i = 0; i < MAX_OCTEON_INSTR_QUEUES(oct); i++) {
			if (!(oct->io_qmask.iq & (1ULL << i)))
				continue;
			octeon_delete_instr_queue(oct, i);
		}
@@ -1201,11 +1253,18 @@ static void octeon_destroy_resources(struct octeon_device *oct)

		/* fallthrough */
	case OCT_DEV_PCI_MAP_DONE:

		/* Soft reset the octeon device before exiting */
		oct->fn_list.soft_reset(oct);

		octeon_unmap_pci_barx(oct, 0);
		octeon_unmap_pci_barx(oct, 1);

		/* fallthrough */
	case OCT_DEV_BEGIN_STATE:
		/* Disable the device, releasing the PCI INT */
		pci_disable_device(oct->pci_dev);

		/* Nothing to be done here either */
		break;
	}                       /* end switch(oct->status) */
@@ -1245,6 +1304,7 @@ static void liquidio_destroy_nic_device(struct octeon_device *oct, int ifidx)
{
	struct net_device *netdev = oct->props[ifidx].netdev;
	struct lio *lio;
	struct napi_struct *napi, *n;

	if (!netdev) {
		dev_err(&oct->pci_dev->dev, "%s No netdevice ptr for index %d\n",
@@ -1261,6 +1321,13 @@ static void liquidio_destroy_nic_device(struct octeon_device *oct, int ifidx)
	if (atomic_read(&lio->ifstate) & LIO_IFSTATE_RUNNING)
		txqs_stop(netdev);

	if (oct->props[lio->ifidx].napi_enabled == 1) {
		list_for_each_entry_safe(napi, n, &netdev->napi_list, dev_list)
			napi_disable(napi);

		oct->props[lio->ifidx].napi_enabled = 0;
	}

	if (atomic_read(&lio->ifstate) & LIO_IFSTATE_REGISTERED)
		unregister_netdev(netdev);

@@ -1288,6 +1355,10 @@ static int liquidio_stop_nic_module(struct octeon_device *oct)
		return 1;
	}

	spin_lock_bh(&oct->cmd_resp_wqlock);
	oct->cmd_resp_state = OCT_DRV_OFFLINE;
	spin_unlock_bh(&oct->cmd_resp_wqlock);

	for (i = 0; i < oct->ifcount; i++) {
		lio = GET_LIO(oct->props[i].netdev);
		for (j = 0; j < lio->linfo.num_rxpciq; j++)
@@ -1336,6 +1407,7 @@ static int octeon_chip_specific_setup(struct octeon_device *oct)
{
	u32 dev_id, rev_id;
	int ret = 1;
	char *s;

	pci_read_config_dword(oct->pci_dev, 0, &dev_id);
	pci_read_config_dword(oct->pci_dev, 8, &rev_id);
@@ -1345,22 +1417,27 @@ static int octeon_chip_specific_setup(struct octeon_device *oct)
	case OCTEON_CN68XX_PCIID:
		oct->chip_id = OCTEON_CN68XX;
		ret = lio_setup_cn68xx_octeon_device(oct);
		s = "CN68XX";
		break;

	case OCTEON_CN66XX_PCIID:
		oct->chip_id = OCTEON_CN66XX;
		ret = lio_setup_cn66xx_octeon_device(oct);
		s = "CN66XX";
		break;

	default:
		s = "?";
		dev_err(&oct->pci_dev->dev, "Unknown device found (dev_id: %x)\n",
			dev_id);
	}

	if (!ret)
		dev_info(&oct->pci_dev->dev, "CN68XX PASS%d.%d %s\n",
		dev_info(&oct->pci_dev->dev, "%s PASS%d.%d %s Version: %s\n", s,
			 OCTEON_MAJOR_REV(oct),
			 OCTEON_MINOR_REV(oct),
			 octeon_get_conf(oct)->card_name);
			 octeon_get_conf(oct)->card_name,
			 LIQUIDIO_VERSION);

	return ret;
}
@@ -1418,8 +1495,10 @@ static inline int check_txq_state(struct lio *lio, struct sk_buff *skb)
	if (octnet_iq_is_full(lio->oct_dev, iq))
		return 0;

	if (__netif_subqueue_stopped(lio->netdev, q))
	if (__netif_subqueue_stopped(lio->netdev, q)) {
		INCR_INSTRQUEUE_PKT_COUNT(lio->oct_dev, iq, tx_restart, 1);
		wake_q(lio->netdev, q);
	}
	return 1;
}

@@ -1733,6 +1812,7 @@ static int load_firmware(struct octeon_device *oct)
	if (ret) {
		dev_err(&oct->pci_dev->dev, "Request firmware failed. Could not find file %s.\n.",
			fw_name);
		release_firmware(fw);
		return ret;
	}

@@ -1802,6 +1882,9 @@ static void if_cfg_callback(struct octeon_device *oct,
			CVM_CAST64(resp->status));
	ACCESS_ONCE(ctx->cond) = 1;

	snprintf(oct->fw_info.liquidio_firmware_version, 32, "%s",
		 resp->cfg_info.liquidio_firmware_version);

	/* This barrier is required to be sure that the response has been
	 * written fully before waking up the handler
	 */
@@ -1848,6 +1931,7 @@ liquidio_push_packet(u32 octeon_id,
	struct sk_buff *skb = (struct sk_buff *)skbuff;
	struct skb_shared_hwtstamps *shhwtstamps;
	u64 ns;
	u16 vtag = 0;
	struct net_device *netdev = (struct net_device *)arg;
	struct octeon_droq *droq = container_of(param, struct octeon_droq,
						napi);
@@ -1924,6 +2008,16 @@ liquidio_push_packet(u32 octeon_id,
		else
			skb->ip_summed = CHECKSUM_NONE;

		/* inbound VLAN tag */
		if ((netdev->features & NETIF_F_HW_VLAN_CTAG_RX) &&
		    (rh->r_dh.vlan != 0)) {
			u16 vid = rh->r_dh.vlan;
			u16 priority = rh->r_dh.priority;

			vtag = priority << 13 | vid;
			__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vtag);
		}

		packet_was_received = napi_gro_receive(napi, skb) != GRO_DROP;

		if (packet_was_received) {
@@ -1977,39 +2071,6 @@ static void liquidio_napi_drv_callback(void *arg)
	}
}

/**
 * \brief Main NAPI poll function
 * @param droq octeon output queue
 * @param budget maximum number of items to process
 */
static int liquidio_napi_do_rx(struct octeon_droq *droq, int budget)
{
	int work_done;
	struct lio *lio = GET_LIO(droq->napi.dev);
	struct octeon_device *oct = lio->oct_dev;

	work_done = octeon_process_droq_poll_cmd(oct, droq->q_no,
						 POLL_EVENT_PROCESS_PKTS,
						 budget);
	if (work_done < 0) {
		netif_info(lio, rx_err, lio->netdev,
			   "Receive work_done < 0, rxq:%d\n", droq->q_no);
		goto octnet_napi_finish;
	}

	if (work_done > budget)
		dev_err(&oct->pci_dev->dev, ">>>> %s work_done: %d budget: %d\n",
			__func__, work_done, budget);

	return work_done;

octnet_napi_finish:
	napi_complete(&droq->napi);
	octeon_process_droq_poll_cmd(oct, droq->q_no, POLL_EVENT_ENABLE_INTR,
				     0);
	return 0;
}

/**
 * \brief Entry point for NAPI polling
 * @param napi NAPI structure
@@ -2019,19 +2080,41 @@ static int liquidio_napi_poll(struct napi_struct *napi, int budget)
{
	struct octeon_droq *droq;
	int work_done;
	int tx_done = 0, iq_no;
	struct octeon_instr_queue *iq;
	struct octeon_device *oct;

	droq = container_of(napi, struct octeon_droq, napi);
	oct = droq->oct_dev;
	iq_no = droq->q_no;
	/* Handle Droq descriptors */
	work_done = octeon_process_droq_poll_cmd(oct, droq->q_no,
						 POLL_EVENT_PROCESS_PKTS,
						 budget);

	work_done = liquidio_napi_do_rx(droq, budget);
	/* Flush the instruction queue */
	iq = oct->instr_queue[iq_no];
	if (iq) {
		/* Process iq buffers with in the budget limits */
		tx_done = octeon_flush_iq(oct, iq, 1, budget);
		/* Update iq read-index rather than waiting for next interrupt.
		 * Return back if tx_done is false.
		 */
		update_txq_status(oct, iq_no);
		/*tx_done = (iq->flush_index == iq->octeon_read_index);*/
	} else {
		dev_err(&oct->pci_dev->dev, "%s:  iq (%d) num invalid\n",
			__func__, iq_no);
	}

	if (work_done < budget) {
	if ((work_done < budget) && (tx_done)) {
		napi_complete(napi);
		octeon_process_droq_poll_cmd(droq->oct_dev, droq->q_no,
					     POLL_EVENT_ENABLE_INTR, 0);
		return 0;
	}

	return work_done;
	return (!tx_done) ? (budget) : (work_done);
}

/**
@@ -2165,6 +2248,14 @@ static inline void setup_tx_poll_fn(struct net_device *netdev)
			   &lio->txq_status_wq.wk.work, msecs_to_jiffies(1));
}

static inline void cleanup_tx_poll_fn(struct net_device *netdev)
{
	struct lio *lio = GET_LIO(netdev);

	cancel_delayed_work_sync(&lio->txq_status_wq.wk.work);
	destroy_workqueue(lio->txq_status_wq.wq);
}

/**
 * \brief Net device open for LiquidIO
 * @param netdev network device
@@ -2175,17 +2266,22 @@ static int liquidio_open(struct net_device *netdev)
	struct octeon_device *oct = lio->oct_dev;
	struct napi_struct *napi, *n;

	if (oct->props[lio->ifidx].napi_enabled == 0) {
		list_for_each_entry_safe(napi, n, &netdev->napi_list, dev_list)
			napi_enable(napi);

		oct->props[lio->ifidx].napi_enabled = 1;
	}

	oct_ptp_open(netdev);

	ifstate_set(lio, LIO_IFSTATE_RUNNING);

	setup_tx_poll_fn(netdev);

	start_txq(netdev);

	netif_info(lio, ifup, lio->netdev, "Interface Open, ready for traffic\n");
	try_module_get(THIS_MODULE);

	/* tell Octeon to start forwarding packets to host */
	send_rx_ctrl_cmd(lio, 1);
@@ -2205,39 +2301,35 @@ static int liquidio_open(struct net_device *netdev)
 */
static int liquidio_stop(struct net_device *netdev)
{
	struct napi_struct *napi, *n;
	struct lio *lio = GET_LIO(netdev);
	struct octeon_device *oct = lio->oct_dev;

	netif_info(lio, ifdown, lio->netdev, "Stopping interface!\n");
	ifstate_reset(lio, LIO_IFSTATE_RUNNING);

	netif_tx_disable(netdev);

	/* Inform that netif carrier is down */
	netif_carrier_off(netdev);
	lio->intf_open = 0;
	lio->linfo.link.s.link_up = 0;
	lio->link_changes++;

	netif_carrier_off(netdev);
	/* Pause for a moment and wait for Octeon to flush out (to the wire) any
	 * egress packets that are in-flight.
	 */
	set_current_state(TASK_INTERRUPTIBLE);
	schedule_timeout(msecs_to_jiffies(100));

	/* tell Octeon to stop forwarding packets to host */
	/* Now it should be safe to tell Octeon that nic interface is down. */
	send_rx_ctrl_cmd(lio, 0);

	cancel_delayed_work_sync(&lio->txq_status_wq.wk.work);
	destroy_workqueue(lio->txq_status_wq.wq);
	cleanup_tx_poll_fn(netdev);

	if (lio->ptp_clock) {
		ptp_clock_unregister(lio->ptp_clock);
		lio->ptp_clock = NULL;
	}

	ifstate_reset(lio, LIO_IFSTATE_RUNNING);

	/* This is a hack that allows DHCP to continue working. */
	set_bit(__LINK_STATE_START, &lio->netdev->state);

	list_for_each_entry_safe(napi, n, &netdev->napi_list, dev_list)
		napi_disable(napi);

	txqs_stop(netdev);

	dev_info(&oct->pci_dev->dev, "%s interface is stopped\n", netdev->name);
	module_put(THIS_MODULE);

@@ -2298,12 +2390,31 @@ void liquidio_link_ctrl_cmd_completion(void *nctrl_ptr)
			 netdev->name);
		break;

	case OCTNET_CMD_ENABLE_VLAN_FILTER:
		dev_info(&oct->pci_dev->dev, "%s VLAN filter enabled\n",
			 netdev->name);
		break;

	case OCTNET_CMD_ADD_VLAN_FILTER:
		dev_info(&oct->pci_dev->dev, "%s VLAN filter %d added\n",
			 netdev->name, nctrl->ncmd.s.param1);
		break;

	case OCTNET_CMD_DEL_VLAN_FILTER:
		dev_info(&oct->pci_dev->dev, "%s VLAN filter %d removed\n",
			 netdev->name, nctrl->ncmd.s.param1);
		break;

	case OCTNET_CMD_SET_SETTINGS:
		dev_info(&oct->pci_dev->dev, "%s settings changed\n",
			 netdev->name);

		break;

	case OCTNET_CMD_SET_FLOW_CTL:
		netif_info(lio, probe, lio->netdev, "Set RX/TX flow control parameters\n");
		break;

	default:
		dev_err(&oct->pci_dev->dev, "%s Unknown cmd %d\n", __func__,
			nctrl->ncmd.s.cmd);
@@ -2898,6 +3009,13 @@ static int liquidio_xmit(struct sk_buff *skb, struct net_device *netdev)
	if (skb_shinfo(skb)->gso_size) {
		tx_info->s.gso_size = skb_shinfo(skb)->gso_size;
		tx_info->s.gso_segs = skb_shinfo(skb)->gso_segs;
		stats->tx_gso++;
	}

	/* HW insert VLAN tag */
	if (skb_vlan_tag_present(skb)) {
		irh->priority = skb_vlan_tag_get(skb) >> 13;
		irh->vlan = skb_vlan_tag_get(skb) & 0xfff;
	}

	xmit_more = skb->xmit_more;
@@ -2916,6 +3034,9 @@ static int liquidio_xmit(struct sk_buff *skb, struct net_device *netdev)

	netif_trans_update(netdev);

	if (skb_shinfo(skb)->gso_size)
		stats->tx_done += skb_shinfo(skb)->gso_segs;
	else
		stats->tx_done++;
	stats->tx_tot_bytes += skb->len;

@@ -2948,6 +3069,61 @@ static void liquidio_tx_timeout(struct net_device *netdev)
	txqs_wake(netdev);
}

static int liquidio_vlan_rx_add_vid(struct net_device *netdev,
				    __be16 proto __attribute__((unused)),
				    u16 vid)
{
	struct lio *lio = GET_LIO(netdev);
	struct octeon_device *oct = lio->oct_dev;
	struct octnic_ctrl_pkt nctrl;
	int ret = 0;

	memset(&nctrl, 0, sizeof(struct octnic_ctrl_pkt));

	nctrl.ncmd.u64 = 0;
	nctrl.ncmd.s.cmd = OCTNET_CMD_ADD_VLAN_FILTER;
	nctrl.ncmd.s.param1 = vid;
	nctrl.iq_no = lio->linfo.txpciq[0].s.q_no;
	nctrl.wait_time = 100;
	nctrl.netpndev = (u64)netdev;
	nctrl.cb_fn = liquidio_link_ctrl_cmd_completion;

	ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl);
	if (ret < 0) {
		dev_err(&oct->pci_dev->dev, "Add VLAN filter failed in core (ret: 0x%x)\n",
			ret);
	}

	return ret;
}

static int liquidio_vlan_rx_kill_vid(struct net_device *netdev,
				     __be16 proto __attribute__((unused)),
				     u16 vid)
{
	struct lio *lio = GET_LIO(netdev);
	struct octeon_device *oct = lio->oct_dev;
	struct octnic_ctrl_pkt nctrl;
	int ret = 0;

	memset(&nctrl, 0, sizeof(struct octnic_ctrl_pkt));

	nctrl.ncmd.u64 = 0;
	nctrl.ncmd.s.cmd = OCTNET_CMD_DEL_VLAN_FILTER;
	nctrl.ncmd.s.param1 = vid;
	nctrl.iq_no = lio->linfo.txpciq[0].s.q_no;
	nctrl.wait_time = 100;
	nctrl.netpndev = (u64)netdev;
	nctrl.cb_fn = liquidio_link_ctrl_cmd_completion;

	ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl);
	if (ret < 0) {
		dev_err(&oct->pci_dev->dev, "Add VLAN filter failed in core (ret: 0x%x)\n",
			ret);
	}
	return ret;
}

int liquidio_set_feature(struct net_device *netdev, int cmd, u16 param1)
{
	struct lio *lio = GET_LIO(netdev);
@@ -3039,6 +3215,9 @@ static struct net_device_ops lionetdevops = {
	.ndo_set_mac_address	= liquidio_set_mac,
	.ndo_set_rx_mode	= liquidio_set_mcast_list,
	.ndo_tx_timeout		= liquidio_tx_timeout,

	.ndo_vlan_rx_add_vid    = liquidio_vlan_rx_add_vid,
	.ndo_vlan_rx_kill_vid   = liquidio_vlan_rx_kill_vid,
	.ndo_change_mtu		= liquidio_change_mtu,
	.ndo_do_ioctl		= liquidio_ioctl,
	.ndo_fix_features	= liquidio_fix_features,
@@ -3300,11 +3479,18 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
				| NETIF_F_LRO;
		netif_set_gso_max_size(netdev, OCTNIC_GSO_MAX_SIZE);

		netdev->features = (lio->dev_capability & ~NETIF_F_LRO);

		netdev->vlan_features = lio->dev_capability;
		/* Add any unchangeable hw features */
		lio->dev_capability |=  NETIF_F_HW_VLAN_CTAG_FILTER |
					NETIF_F_HW_VLAN_CTAG_RX |
					NETIF_F_HW_VLAN_CTAG_TX;

		netdev->features = (lio->dev_capability & ~NETIF_F_LRO);

		netdev->hw_features = lio->dev_capability;
		/*HW_VLAN_RX and HW_VLAN_FILTER is always on*/
		netdev->hw_features = netdev->hw_features &
			~NETIF_F_HW_VLAN_CTAG_RX;

		/* Point to the  properties for octeon device to which this
		 * interface belongs.
@@ -3349,14 +3535,17 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)

		/* Register ethtool support */
		liquidio_set_ethtool_ops(netdev);
		octeon_dev->priv_flags = 0x0;

		if (netdev->features & NETIF_F_LRO)
		liquidio_set_feature(netdev, OCTNET_CMD_LRO_ENABLE,
				     OCTNIC_LROIPV4 | OCTNIC_LROIPV6);

		liquidio_set_feature(netdev, OCTNET_CMD_ENABLE_VLAN_FILTER, 0);

		if ((debug != -1) && (debug & NETIF_MSG_HW))
			liquidio_set_feature(netdev, OCTNET_CMD_VERBOSE_ENABLE,
					     0);
			liquidio_set_feature(netdev,
					     OCTNET_CMD_VERBOSE_ENABLE, 0);

		/* Register the network device with the OS */
		if (register_netdev(netdev)) {
@@ -3429,15 +3618,19 @@ static int liquidio_init_nic_module(struct octeon_device *oct)

	/* Initialize interrupt moderation params */
	intrmod_cfg = &((struct octeon_device *)oct)->intrmod;
	intrmod_cfg->intrmod_enable = 1;
	intrmod_cfg->intrmod_check_intrvl = LIO_INTRMOD_CHECK_INTERVAL;
	intrmod_cfg->intrmod_maxpkt_ratethr = LIO_INTRMOD_MAXPKT_RATETHR;
	intrmod_cfg->intrmod_minpkt_ratethr = LIO_INTRMOD_MINPKT_RATETHR;
	intrmod_cfg->intrmod_maxcnt_trigger = LIO_INTRMOD_MAXCNT_TRIGGER;
	intrmod_cfg->intrmod_maxtmr_trigger = LIO_INTRMOD_MAXTMR_TRIGGER;
	intrmod_cfg->intrmod_mintmr_trigger = LIO_INTRMOD_MINTMR_TRIGGER;
	intrmod_cfg->intrmod_mincnt_trigger = LIO_INTRMOD_MINCNT_TRIGGER;

	intrmod_cfg->rx_enable = 1;
	intrmod_cfg->check_intrvl =   LIO_INTRMOD_CHECK_INTERVAL;
	intrmod_cfg->maxpkt_ratethr = LIO_INTRMOD_MAXPKT_RATETHR;
	intrmod_cfg->minpkt_ratethr = LIO_INTRMOD_MINPKT_RATETHR;
	intrmod_cfg->rx_maxcnt_trigger = LIO_INTRMOD_RXMAXCNT_TRIGGER;
	intrmod_cfg->rx_maxtmr_trigger = LIO_INTRMOD_RXMAXTMR_TRIGGER;
	intrmod_cfg->rx_mintmr_trigger = LIO_INTRMOD_RXMINTMR_TRIGGER;
	intrmod_cfg->rx_mincnt_trigger = LIO_INTRMOD_RXMINCNT_TRIGGER;
	intrmod_cfg->tx_enable = 1;
	intrmod_cfg->tx_maxcnt_trigger = LIO_INTRMOD_TXMAXCNT_TRIGGER;
	intrmod_cfg->tx_mincnt_trigger = LIO_INTRMOD_TXMINCNT_TRIGGER;
	intrmod_cfg->rx_frames = CFG_GET_OQ_INTR_PKT(octeon_get_conf(oct));
	intrmod_cfg->rx_usecs = CFG_GET_OQ_INTR_TIME(octeon_get_conf(oct));
	dev_dbg(&oct->pci_dev->dev, "Network interfaces ready\n");

	return retval;
@@ -3500,6 +3693,7 @@ static void nic_starter(struct work_struct *work)
static int octeon_device_init(struct octeon_device *octeon_dev)
{
	int j, ret;
	char bootcmd[] = "\n";
	struct octeon_device_priv *oct_priv =
		(struct octeon_device_priv *)octeon_dev->priv;
	atomic_set(&octeon_dev->status, OCT_DEV_BEGIN_STATE);
@@ -3611,14 +3805,19 @@ static int octeon_device_init(struct octeon_device *octeon_dev)

	dev_dbg(&octeon_dev->pci_dev->dev, "Waiting for DDR initialization...\n");

	if (ddr_timeout == 0) {
		dev_info(&octeon_dev->pci_dev->dev,
			 "WAITING. Set ddr_timeout to non-zero value to proceed with initialization.\n");
	}
	if (ddr_timeout == 0)
		dev_info(&octeon_dev->pci_dev->dev, "WAITING. Set ddr_timeout to non-zero value to proceed with initialization.\n");

	schedule_timeout_uninterruptible(HZ * LIO_RESET_SECS);

	/* Wait for the octeon to initialize DDR after the soft-reset. */
	while (ddr_timeout == 0) {
		set_current_state(TASK_INTERRUPTIBLE);
		if (schedule_timeout(HZ / 10)) {
			/* user probably pressed Control-C */
			return 1;
		}
	}
	ret = octeon_wait_for_ddr_init(octeon_dev, &ddr_timeout);
	if (ret) {
		dev_err(&octeon_dev->pci_dev->dev,
@@ -3632,6 +3831,9 @@ static int octeon_device_init(struct octeon_device *octeon_dev)
		return 1;
	}

	/* Divert uboot to take commands from host instead. */
	ret = octeon_console_send_cmd(octeon_dev, bootcmd, 50);

	dev_dbg(&octeon_dev->pci_dev->dev, "Initializing consoles\n");
	ret = octeon_init_consoles(octeon_dev);
	if (ret) {
+80 −47

File changed.

Preview size limit exceeded, changes collapsed.

Loading