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

Merge branch 'ionic-locking-and-filter-fixes'



Shannon Nelson says:

====================
ionic: locking and filter fixes

These patches address an ethtool show regs problem, some locking sightings,
and issues with RSS hash and filter_id tracking after a managed FW update.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 5d93518e 0925e9db
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -103,15 +103,18 @@ static void ionic_get_regs(struct net_device *netdev, struct ethtool_regs *regs,
			   void *p)
{
	struct ionic_lif *lif = netdev_priv(netdev);
	unsigned int offset;
	unsigned int size;

	regs->version = IONIC_DEV_CMD_REG_VERSION;

	offset = 0;
	size = IONIC_DEV_INFO_REG_COUNT * sizeof(u32);
	memcpy_fromio(p, lif->ionic->idev.dev_info_regs->words, size);
	memcpy_fromio(p + offset, lif->ionic->idev.dev_info_regs->words, size);

	offset += size;
	size = IONIC_DEV_CMD_REG_COUNT * sizeof(u32);
	memcpy_fromio(p, lif->ionic->idev.dev_cmd_regs->words, size);
	memcpy_fromio(p + offset, lif->ionic->idev.dev_cmd_regs->words, size);
}

static int ionic_get_link_ksettings(struct net_device *netdev,
+25 −25
Original line number Diff line number Diff line
@@ -96,8 +96,7 @@ static void ionic_link_status_check(struct ionic_lif *lif)
	u16 link_status;
	bool link_up;

	if (!test_bit(IONIC_LIF_F_LINK_CHECK_REQUESTED, lif->state) ||
	    test_bit(IONIC_LIF_F_QUEUE_RESET, lif->state))
	if (!test_bit(IONIC_LIF_F_LINK_CHECK_REQUESTED, lif->state))
		return;

	link_status = le16_to_cpu(lif->info->status.link_status);
@@ -114,16 +113,22 @@ static void ionic_link_status_check(struct ionic_lif *lif)
			netif_carrier_on(netdev);
		}

		if (lif->netdev->flags & IFF_UP && netif_running(lif->netdev))
		if (lif->netdev->flags & IFF_UP && netif_running(lif->netdev)) {
			mutex_lock(&lif->queue_lock);
			ionic_start_queues(lif);
			mutex_unlock(&lif->queue_lock);
		}
	} else {
		if (netif_carrier_ok(netdev)) {
			netdev_info(netdev, "Link down\n");
			netif_carrier_off(netdev);
		}

		if (lif->netdev->flags & IFF_UP && netif_running(lif->netdev))
		if (lif->netdev->flags & IFF_UP && netif_running(lif->netdev)) {
			mutex_lock(&lif->queue_lock);
			ionic_stop_queues(lif);
			mutex_unlock(&lif->queue_lock);
		}
	}

	clear_bit(IONIC_LIF_F_LINK_CHECK_REQUESTED, lif->state);
@@ -863,8 +868,7 @@ static int ionic_lif_addr_add(struct ionic_lif *lif, const u8 *addr)
	if (f)
		return 0;

	netdev_dbg(lif->netdev, "rx_filter add ADDR %pM (id %d)\n", addr,
		   ctx.comp.rx_filter_add.filter_id);
	netdev_dbg(lif->netdev, "rx_filter add ADDR %pM\n", addr);

	memcpy(ctx.cmd.rx_filter_add.mac.addr, addr, ETH_ALEN);
	err = ionic_adminq_post_wait(lif, &ctx);
@@ -893,6 +897,9 @@ static int ionic_lif_addr_del(struct ionic_lif *lif, const u8 *addr)
		return -ENOENT;
	}

	netdev_dbg(lif->netdev, "rx_filter del ADDR %pM (id %d)\n",
		   addr, f->filter_id);

	ctx.cmd.rx_filter_del.filter_id = cpu_to_le32(f->filter_id);
	ionic_rx_filter_free(lif, f);
	spin_unlock_bh(&lif->rx_filters.lock);
@@ -901,9 +908,6 @@ static int ionic_lif_addr_del(struct ionic_lif *lif, const u8 *addr)
	if (err && err != -EEXIST)
		return err;

	netdev_dbg(lif->netdev, "rx_filter del ADDR %pM (id %d)\n", addr,
		   ctx.cmd.rx_filter_del.filter_id);

	return 0;
}

@@ -1351,13 +1355,11 @@ static int ionic_vlan_rx_add_vid(struct net_device *netdev, __be16 proto,
	};
	int err;

	netdev_dbg(netdev, "rx_filter add VLAN %d\n", vid);
	err = ionic_adminq_post_wait(lif, &ctx);
	if (err)
		return err;

	netdev_dbg(netdev, "rx_filter add VLAN %d (id %d)\n", vid,
		   ctx.comp.rx_filter_add.filter_id);

	return ionic_rx_filter_save(lif, 0, IONIC_RXQ_INDEX_ANY, 0, &ctx);
}

@@ -1382,8 +1384,8 @@ static int ionic_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto,
		return -ENOENT;
	}

	netdev_dbg(netdev, "rx_filter del VLAN %d (id %d)\n", vid,
		   le32_to_cpu(ctx.cmd.rx_filter_del.filter_id));
	netdev_dbg(netdev, "rx_filter del VLAN %d (id %d)\n",
		   vid, f->filter_id);

	ctx.cmd.rx_filter_del.filter_id = cpu_to_le32(f->filter_id);
	ionic_rx_filter_free(lif, f);
@@ -1993,16 +1995,13 @@ int ionic_reset_queues(struct ionic_lif *lif, ionic_reset_cb cb, void *arg)
	bool running;
	int err = 0;

	err = ionic_wait_for_bit(lif, IONIC_LIF_F_QUEUE_RESET);
	if (err)
		return err;

	mutex_lock(&lif->queue_lock);
	running = netif_running(lif->netdev);
	if (running) {
		netif_device_detach(lif->netdev);
		err = ionic_stop(lif->netdev);
		if (err)
			goto reset_out;
			return err;
	}

	if (cb)
@@ -2012,9 +2011,7 @@ int ionic_reset_queues(struct ionic_lif *lif, ionic_reset_cb cb, void *arg)
		err = ionic_open(lif->netdev);
		netif_device_attach(lif->netdev);
	}

reset_out:
	clear_bit(IONIC_LIF_F_QUEUE_RESET, lif->state);
	mutex_unlock(&lif->queue_lock);

	return err;
}
@@ -2161,7 +2158,9 @@ static void ionic_lif_handle_fw_down(struct ionic_lif *lif)

	if (test_bit(IONIC_LIF_F_UP, lif->state)) {
		dev_info(ionic->dev, "Surprise FW stop, stopping queues\n");
		mutex_lock(&lif->queue_lock);
		ionic_stop_queues(lif);
		mutex_unlock(&lif->queue_lock);
	}

	if (netif_running(lif->netdev)) {
@@ -2280,15 +2279,15 @@ static void ionic_lif_deinit(struct ionic_lif *lif)
		cancel_work_sync(&lif->deferred.work);
		cancel_work_sync(&lif->tx_timeout_work);
		ionic_rx_filters_deinit(lif);
	}

		if (lif->netdev->features & NETIF_F_RXHASH)
			ionic_lif_rss_deinit(lif);
	}

	napi_disable(&lif->adminqcq->napi);
	ionic_lif_qcq_deinit(lif, lif->notifyqcq);
	ionic_lif_qcq_deinit(lif, lif->adminqcq);

	mutex_destroy(&lif->queue_lock);
	ionic_lif_reset(lif);
}

@@ -2465,6 +2464,7 @@ static int ionic_lif_init(struct ionic_lif *lif)
		return err;

	lif->hw_index = le16_to_cpu(comp.hw_index);
	mutex_init(&lif->queue_lock);

	/* now that we have the hw_index we can figure out our doorbell page */
	lif->dbid_count = le32_to_cpu(lif->ionic->ident.dev.ndbpgs_per_lif);
+1 −7
Original line number Diff line number Diff line
@@ -135,7 +135,6 @@ enum ionic_lif_state_flags {
	IONIC_LIF_F_SW_DEBUG_STATS,
	IONIC_LIF_F_UP,
	IONIC_LIF_F_LINK_CHECK_REQUESTED,
	IONIC_LIF_F_QUEUE_RESET,
	IONIC_LIF_F_FW_RESET,

	/* leave this as last */
@@ -165,6 +164,7 @@ struct ionic_lif {
	unsigned int hw_index;
	unsigned int kern_pid;
	u64 __iomem *kern_dbpage;
	struct mutex queue_lock;	/* lock for queue structures */
	spinlock_t adminq_lock;		/* lock for AdminQ operations */
	struct ionic_qcq *adminqcq;
	struct ionic_qcq *notifyqcq;
@@ -213,12 +213,6 @@ struct ionic_lif {
#define lif_to_txq(lif, i)	(&lif_to_txqcq((lif), i)->q)
#define lif_to_rxq(lif, i)	(&lif_to_txqcq((lif), i)->q)

/* return 0 if successfully set the bit, else non-zero */
static inline int ionic_wait_for_bit(struct ionic_lif *lif, int bitname)
{
	return wait_on_bit_lock(lif->state, bitname, TASK_INTERRUPTIBLE);
}

static inline u32 ionic_coal_usec_to_hw(struct ionic *ionic, u32 usecs)
{
	u32 mult = le32_to_cpu(ionic->ident.dev.intr_coal_mult);
+29 −0
Original line number Diff line number Diff line
@@ -21,13 +21,16 @@ void ionic_rx_filter_free(struct ionic_lif *lif, struct ionic_rx_filter *f)
void ionic_rx_filter_replay(struct ionic_lif *lif)
{
	struct ionic_rx_filter_add_cmd *ac;
	struct hlist_head new_id_list;
	struct ionic_admin_ctx ctx;
	struct ionic_rx_filter *f;
	struct hlist_head *head;
	struct hlist_node *tmp;
	unsigned int key;
	unsigned int i;
	int err;

	INIT_HLIST_HEAD(&new_id_list);
	ac = &ctx.cmd.rx_filter_add;

	for (i = 0; i < IONIC_RX_FILTER_HLISTS; i++) {
@@ -58,9 +61,30 @@ void ionic_rx_filter_replay(struct ionic_lif *lif)
						    ac->mac.addr);
					break;
				}
				spin_lock_bh(&lif->rx_filters.lock);
				ionic_rx_filter_free(lif, f);
				spin_unlock_bh(&lif->rx_filters.lock);

				continue;
			}

			/* remove from old id list, save new id in tmp list */
			spin_lock_bh(&lif->rx_filters.lock);
			hlist_del(&f->by_id);
			spin_unlock_bh(&lif->rx_filters.lock);
			f->filter_id = le32_to_cpu(ctx.comp.rx_filter_add.filter_id);
			hlist_add_head(&f->by_id, &new_id_list);
		}
	}

	/* rebuild the by_id hash lists with the new filter ids */
	spin_lock_bh(&lif->rx_filters.lock);
	hlist_for_each_entry_safe(f, tmp, &new_id_list, by_id) {
		key = f->filter_id & IONIC_RX_FILTER_HLISTS_MASK;
		head = &lif->rx_filters.by_id[key];
		hlist_add_head(&f->by_id, head);
	}
	spin_unlock_bh(&lif->rx_filters.lock);
}

int ionic_rx_filters_init(struct ionic_lif *lif)
@@ -69,10 +93,12 @@ int ionic_rx_filters_init(struct ionic_lif *lif)

	spin_lock_init(&lif->rx_filters.lock);

	spin_lock_bh(&lif->rx_filters.lock);
	for (i = 0; i < IONIC_RX_FILTER_HLISTS; i++) {
		INIT_HLIST_HEAD(&lif->rx_filters.by_hash[i]);
		INIT_HLIST_HEAD(&lif->rx_filters.by_id[i]);
	}
	spin_unlock_bh(&lif->rx_filters.lock);

	return 0;
}
@@ -84,11 +110,13 @@ void ionic_rx_filters_deinit(struct ionic_lif *lif)
	struct hlist_node *tmp;
	unsigned int i;

	spin_lock_bh(&lif->rx_filters.lock);
	for (i = 0; i < IONIC_RX_FILTER_HLISTS; i++) {
		head = &lif->rx_filters.by_id[i];
		hlist_for_each_entry_safe(f, tmp, head, by_id)
			ionic_rx_filter_free(lif, f);
	}
	spin_unlock_bh(&lif->rx_filters.lock);
}

int ionic_rx_filter_save(struct ionic_lif *lif, u32 flow_id, u16 rxq_index,
@@ -124,6 +152,7 @@ int ionic_rx_filter_save(struct ionic_lif *lif, u32 flow_id, u16 rxq_index,
	f->filter_id = le32_to_cpu(ctx->comp.rx_filter_add.filter_id);
	f->rxq_index = rxq_index;
	memcpy(&f->cmd, ac, sizeof(f->cmd));
	netdev_dbg(lif->netdev, "rx_filter add filter_id %d\n", f->filter_id);

	INIT_HLIST_NODE(&f->by_hash);
	INIT_HLIST_NODE(&f->by_id);
+0 −6
Original line number Diff line number Diff line
@@ -161,12 +161,6 @@ static void ionic_rx_clean(struct ionic_queue *q,
		return;
	}

	/* no packet processing while resetting */
	if (unlikely(test_bit(IONIC_LIF_F_QUEUE_RESET, q->lif->state))) {
		stats->dropped++;
		return;
	}

	stats->pkts++;
	stats->bytes += le16_to_cpu(comp->len);