Commit ae535ba4 authored by David S. Miller's avatar David S. Miller
Browse files
parents 8feedbb4 ba62b2a8
Loading
Loading
Loading
Loading
+21 −15
Original line number Diff line number Diff line
@@ -656,12 +656,16 @@ static void efx_stop_datapath(struct efx_nic *efx)
	struct efx_channel *channel;
	struct efx_tx_queue *tx_queue;
	struct efx_rx_queue *rx_queue;
	struct pci_dev *dev = efx->pci_dev;
	int rc;

	EFX_ASSERT_RESET_SERIALISED(efx);
	BUG_ON(efx->port_enabled);

	/* Only perform flush if dma is enabled */
	if (dev->is_busmaster) {
		rc = efx_nic_flush_queues(efx);

		if (rc && EFX_WORKAROUND_7803(efx)) {
			/* Schedule a reset to recover from the flush failure. The
			 * descriptor caches reference memory we're about to free,
@@ -676,6 +680,7 @@ static void efx_stop_datapath(struct efx_nic *efx)
			netif_dbg(efx, drv, efx->net_dev,
				  "successfully flushed all queues\n");
		}
	}

	efx_for_each_channel(channel, efx) {
		/* RX packet processing is pipelined, so wait for the
@@ -2492,8 +2497,8 @@ static void efx_pci_remove(struct pci_dev *pci_dev)
	efx_fini_io(efx);
	netif_dbg(efx, drv, efx->net_dev, "shutdown successful\n");

	pci_set_drvdata(pci_dev, NULL);
	efx_fini_struct(efx);
	pci_set_drvdata(pci_dev, NULL);
	free_netdev(efx->net_dev);
};

@@ -2695,6 +2700,7 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev,
 fail2:
	efx_fini_struct(efx);
 fail1:
	pci_set_drvdata(pci_dev, NULL);
	WARN_ON(rc > 0);
	netif_dbg(efx, drv, efx->net_dev, "initialisation failed. rc=%d\n", rc);
	free_netdev(net_dev);
+35 −0
Original line number Diff line number Diff line
@@ -1108,6 +1108,39 @@ static int efx_ethtool_set_rxfh_indir(struct net_device *net_dev,
	return 0;
}

static int efx_ethtool_get_module_eeprom(struct net_device *net_dev,
					 struct ethtool_eeprom *ee,
					 u8 *data)
{
	struct efx_nic *efx = netdev_priv(net_dev);
	int ret;

	if (!efx->phy_op || !efx->phy_op->get_module_eeprom)
		return -EOPNOTSUPP;

	mutex_lock(&efx->mac_lock);
	ret = efx->phy_op->get_module_eeprom(efx, ee, data);
	mutex_unlock(&efx->mac_lock);

	return ret;
}

static int efx_ethtool_get_module_info(struct net_device *net_dev,
				       struct ethtool_modinfo *modinfo)
{
	struct efx_nic *efx = netdev_priv(net_dev);
	int ret;

	if (!efx->phy_op || !efx->phy_op->get_module_info)
		return -EOPNOTSUPP;

	mutex_lock(&efx->mac_lock);
	ret = efx->phy_op->get_module_info(efx, modinfo);
	mutex_unlock(&efx->mac_lock);

	return ret;
}

const struct ethtool_ops efx_ethtool_ops = {
	.get_settings		= efx_ethtool_get_settings,
	.set_settings		= efx_ethtool_set_settings,
@@ -1137,4 +1170,6 @@ const struct ethtool_ops efx_ethtool_ops = {
	.get_rxfh_indir_size	= efx_ethtool_get_rxfh_indir_size,
	.get_rxfh_indir		= efx_ethtool_get_rxfh_indir,
	.set_rxfh_indir		= efx_ethtool_set_rxfh_indir,
	.get_module_info	= efx_ethtool_get_module_info,
	.get_module_eeprom	= efx_ethtool_get_module_eeprom,
};
+76 −0
Original line number Diff line number Diff line
@@ -739,6 +739,80 @@ static const char *efx_mcdi_phy_test_name(struct efx_nic *efx,
	return NULL;
}

#define SFP_PAGE_SIZE	128
#define SFP_NUM_PAGES	2
static int efx_mcdi_phy_get_module_eeprom(struct efx_nic *efx,
					  struct ethtool_eeprom *ee, u8 *data)
{
	u8 outbuf[MC_CMD_GET_PHY_MEDIA_INFO_OUT_LENMAX];
	u8 inbuf[MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN];
	size_t outlen;
	int rc;
	unsigned int payload_len;
	unsigned int space_remaining = ee->len;
	unsigned int page;
	unsigned int page_off;
	unsigned int to_copy;
	u8 *user_data = data;

	BUILD_BUG_ON(SFP_PAGE_SIZE * SFP_NUM_PAGES != ETH_MODULE_SFF_8079_LEN);

	page_off = ee->offset % SFP_PAGE_SIZE;
	page = ee->offset / SFP_PAGE_SIZE;

	while (space_remaining && (page < SFP_NUM_PAGES)) {
		MCDI_SET_DWORD(inbuf, GET_PHY_MEDIA_INFO_IN_PAGE, page);

		rc = efx_mcdi_rpc(efx, MC_CMD_GET_PHY_MEDIA_INFO,
				  inbuf, sizeof(inbuf),
				  outbuf, sizeof(outbuf),
				  &outlen);
		if (rc)
			return rc;

		if (outlen < (MC_CMD_GET_PHY_MEDIA_INFO_OUT_DATA_OFST +
			      SFP_PAGE_SIZE))
			return -EIO;

		payload_len = MCDI_DWORD(outbuf,
					 GET_PHY_MEDIA_INFO_OUT_DATALEN);
		if (payload_len != SFP_PAGE_SIZE)
			return -EIO;

		/* Copy as much as we can into data */
		payload_len -= page_off;
		to_copy = (space_remaining < payload_len) ?
			space_remaining : payload_len;

		memcpy(user_data,
		       outbuf + page_off +
		       MC_CMD_GET_PHY_MEDIA_INFO_OUT_DATA_OFST,
		       to_copy);

		space_remaining -= to_copy;
		user_data += to_copy;
		page_off = 0;
		page++;
	}

	return 0;
}

static int efx_mcdi_phy_get_module_info(struct efx_nic *efx,
					struct ethtool_modinfo *modinfo)
{
	struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;

	switch (phy_cfg->media) {
	case MC_CMD_MEDIA_SFP_PLUS:
		modinfo->type = ETH_MODULE_SFF_8079;
		modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN;
		return 0;
	default:
		return -EOPNOTSUPP;
	}
}

const struct efx_phy_operations efx_mcdi_phy_ops = {
	.probe		= efx_mcdi_phy_probe,
	.init		= efx_port_dummy_op_int,
@@ -751,4 +825,6 @@ const struct efx_phy_operations efx_mcdi_phy_ops = {
	.test_alive	= efx_mcdi_phy_test_alive,
	.run_tests	= efx_mcdi_phy_run_tests,
	.test_name	= efx_mcdi_phy_test_name,
	.get_module_eeprom = efx_mcdi_phy_get_module_eeprom,
	.get_module_info = efx_mcdi_phy_get_module_info,
};
+5 −3
Original line number Diff line number Diff line
@@ -252,8 +252,6 @@ struct efx_rx_page_state {
 * @max_fill: RX descriptor maximum fill level (<= ring size)
 * @fast_fill_trigger: RX descriptor fill level that will trigger a fast fill
 *	(<= @max_fill)
 * @fast_fill_limit: The level to which a fast fill will fill
 *	(@fast_fill_trigger <= @fast_fill_limit <= @max_fill)
 * @min_fill: RX descriptor minimum non-zero fill level.
 *	This records the minimum fill level observed when a ring
 *	refill was triggered.
@@ -274,7 +272,6 @@ struct efx_rx_queue {
	int removed_count;
	unsigned int max_fill;
	unsigned int fast_fill_trigger;
	unsigned int fast_fill_limit;
	unsigned int min_fill;
	unsigned int min_overfill;
	unsigned int alloc_page_count;
@@ -522,6 +519,11 @@ struct efx_phy_operations {
	int (*test_alive) (struct efx_nic *efx);
	const char *(*test_name) (struct efx_nic *efx, unsigned int index);
	int (*run_tests) (struct efx_nic *efx, int *results, unsigned flags);
	int (*get_module_eeprom) (struct efx_nic *efx,
			       struct ethtool_eeprom *ee,
			       u8 *data);
	int (*get_module_info) (struct efx_nic *efx,
				struct ethtool_modinfo *modinfo);
};

/**
+33 −0
Original line number Diff line number Diff line
@@ -449,6 +449,37 @@ static void qt202x_phy_remove(struct efx_nic *efx)
	efx->phy_data = NULL;
}

static int qt202x_phy_get_module_info(struct efx_nic *efx,
				      struct ethtool_modinfo *modinfo)
{
	modinfo->type = ETH_MODULE_SFF_8079;
	modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN;
	return 0;
}

static int qt202x_phy_get_module_eeprom(struct efx_nic *efx,
					struct ethtool_eeprom *ee, u8 *data)
{
	int mmd, reg_base, rc, i;		

	if (efx->phy_type == PHY_TYPE_QT2025C) {
		mmd = MDIO_MMD_PCS;
		reg_base = 0xd000;
	} else {
		mmd = MDIO_MMD_PMAPMD;
		reg_base = 0x8007;
	}

	for (i = 0; i < ee->len; i++) {
		rc = efx_mdio_read(efx, mmd, reg_base + ee->offset + i);
		if (rc < 0)
			return rc;
		data[i] = rc;
	}

	return 0;
}

const struct efx_phy_operations falcon_qt202x_phy_ops = {
	.probe		 = qt202x_phy_probe,
	.init		 = qt202x_phy_init,
@@ -459,4 +490,6 @@ const struct efx_phy_operations falcon_qt202x_phy_ops = {
	.get_settings	 = qt202x_phy_get_settings,
	.set_settings	 = efx_mdio_set_settings,
	.test_alive	 = efx_mdio_test_alive,
	.get_module_eeprom = qt202x_phy_get_module_eeprom,
	.get_module_info = qt202x_phy_get_module_info,
};
Loading