Commit 92df825a authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'ionic-bug-fixes'

Shannon Nelson says:

====================
ionic: bug fixes

These are a couple of maintenance bug fixes for the Pensando ionic
networking driver.

Mohamed takes care of a "plays well with others" issue where the
VF spec is a bit vague on VF mac addresses, but certain customers
have come to expect behavior based on other vendor drivers.

Shannon addresses a couple of corner cases seen in internal
stress testing.
====================

Link: https://lore.kernel.org/r/20220824165051.6185-1-snelson@pensando.io


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents b0f571ec 19058be7
Loading
Loading
Loading
Loading
+90 −5
Original line number Diff line number Diff line
@@ -1564,8 +1564,67 @@ static int ionic_set_features(struct net_device *netdev,
	return err;
}

static int ionic_set_attr_mac(struct ionic_lif *lif, u8 *mac)
{
	struct ionic_admin_ctx ctx = {
		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
		.cmd.lif_setattr = {
			.opcode = IONIC_CMD_LIF_SETATTR,
			.index = cpu_to_le16(lif->index),
			.attr = IONIC_LIF_ATTR_MAC,
		},
	};

	ether_addr_copy(ctx.cmd.lif_setattr.mac, mac);
	return ionic_adminq_post_wait(lif, &ctx);
}

static int ionic_get_attr_mac(struct ionic_lif *lif, u8 *mac_addr)
{
	struct ionic_admin_ctx ctx = {
		.work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
		.cmd.lif_getattr = {
			.opcode = IONIC_CMD_LIF_GETATTR,
			.index = cpu_to_le16(lif->index),
			.attr = IONIC_LIF_ATTR_MAC,
		},
	};
	int err;

	err = ionic_adminq_post_wait(lif, &ctx);
	if (err)
		return err;

	ether_addr_copy(mac_addr, ctx.comp.lif_getattr.mac);
	return 0;
}

static int ionic_program_mac(struct ionic_lif *lif, u8 *mac)
{
	u8  get_mac[ETH_ALEN];
	int err;

	err = ionic_set_attr_mac(lif, mac);
	if (err)
		return err;

	err = ionic_get_attr_mac(lif, get_mac);
	if (err)
		return err;

	/* To deal with older firmware that silently ignores the set attr mac:
	 * doesn't actually change the mac and doesn't return an error, so we
	 * do the get attr to verify whether or not the set actually happened
	 */
	if (!ether_addr_equal(get_mac, mac))
		return 1;

	return 0;
}

static int ionic_set_mac_address(struct net_device *netdev, void *sa)
{
	struct ionic_lif *lif = netdev_priv(netdev);
	struct sockaddr *addr = sa;
	u8 *mac;
	int err;
@@ -1574,6 +1633,14 @@ static int ionic_set_mac_address(struct net_device *netdev, void *sa)
	if (ether_addr_equal(netdev->dev_addr, mac))
		return 0;

	err = ionic_program_mac(lif, mac);
	if (err < 0)
		return err;

	if (err > 0)
		netdev_dbg(netdev, "%s: SET and GET ATTR Mac are not equal-due to old FW running\n",
			   __func__);

	err = eth_prepare_mac_addr_change(netdev, addr);
	if (err)
		return err;
@@ -2963,6 +3030,9 @@ static void ionic_lif_handle_fw_up(struct ionic_lif *lif)

	mutex_lock(&lif->queue_lock);

	if (test_and_clear_bit(IONIC_LIF_F_BROKEN, lif->state))
		dev_info(ionic->dev, "FW Up: clearing broken state\n");

	err = ionic_qcqs_alloc(lif);
	if (err)
		goto err_unlock;
@@ -3169,6 +3239,7 @@ static int ionic_station_set(struct ionic_lif *lif)
			.attr = IONIC_LIF_ATTR_MAC,
		},
	};
	u8 mac_address[ETH_ALEN];
	struct sockaddr addr;
	int err;

@@ -3177,8 +3248,23 @@ static int ionic_station_set(struct ionic_lif *lif)
		return err;
	netdev_dbg(lif->netdev, "found initial MAC addr %pM\n",
		   ctx.comp.lif_getattr.mac);
	if (is_zero_ether_addr(ctx.comp.lif_getattr.mac))
	ether_addr_copy(mac_address, ctx.comp.lif_getattr.mac);

	if (is_zero_ether_addr(mac_address)) {
		eth_hw_addr_random(netdev);
		netdev_dbg(netdev, "Random Mac generated: %pM\n", netdev->dev_addr);
		ether_addr_copy(mac_address, netdev->dev_addr);

		err = ionic_program_mac(lif, mac_address);
		if (err < 0)
			return err;

		if (err > 0) {
			netdev_dbg(netdev, "%s:SET/GET ATTR Mac are not same-due to old FW running\n",
				   __func__);
			return 0;
		}
	}

	if (!is_zero_ether_addr(netdev->dev_addr)) {
		/* If the netdev mac is non-zero and doesn't match the default
@@ -3186,12 +3272,11 @@ static int ionic_station_set(struct ionic_lif *lif)
		 * likely here again after a fw-upgrade reset.  We need to be
		 * sure the netdev mac is in our filter list.
		 */
		if (!ether_addr_equal(ctx.comp.lif_getattr.mac,
				      netdev->dev_addr))
		if (!ether_addr_equal(mac_address, netdev->dev_addr))
			ionic_lif_addr_add(lif, netdev->dev_addr);
	} else {
		/* Update the netdev mac with the device's mac */
		memcpy(addr.sa_data, ctx.comp.lif_getattr.mac, netdev->addr_len);
		ether_addr_copy(addr.sa_data, mac_address);
		addr.sa_family = AF_INET;
		err = eth_prepare_mac_addr_change(netdev, &addr);
		if (err) {
+3 −1
Original line number Diff line number Diff line
@@ -474,8 +474,8 @@ static int __ionic_dev_cmd_wait(struct ionic *ionic, unsigned long max_seconds,
				ionic_opcode_to_str(opcode), opcode,
				ionic_error_to_str(err), err);

			msleep(1000);
			iowrite32(0, &idev->dev_cmd_regs->done);
			msleep(1000);
			iowrite32(1, &idev->dev_cmd_regs->doorbell);
			goto try_again;
		}
@@ -488,6 +488,8 @@ static int __ionic_dev_cmd_wait(struct ionic *ionic, unsigned long max_seconds,
		return ionic_error_to_errno(err);
	}

	ionic_dev_cmd_clean(ionic);

	return 0;
}