Skip to contentSkip to conversation

Making use of VNICs in the sfc driver

RFC PATCH New Robert Stonehouse 1 participant 1 message Jun 13, 2008

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

RFC PATCH 1/2 Making use of VNICs in the sfc driver

---
 drivers/net/sfc/Makefile         |    4 +-
 drivers/net/sfc/driverlink.c     |  525 ++++++++++++++++++++++++++++++++
 drivers/net/sfc/driverlink.h     |   76 +++++
 drivers/net/sfc/driverlink_api.h |  614 ++++++++++++++++++++++++++++++++++++++
 drivers/net/sfc/efx.c            |   47 +++-
 drivers/net/sfc/falcon.c         |   88 ++++++-
 drivers/net/sfc/net_driver.h     |   15 +
 7 files changed, 1365 insertions(+), 4 deletions(-)
 create mode 100644 drivers/net/sfc/driverlink.c
 create mode 100644 drivers/net/sfc/driverlink.h
 create mode 100644 drivers/net/sfc/driverlink_api.h
drivers/net/sfc/Makefile +2 -2
index c8f5704..aa3bff7 100644
@@ -1,5 +1,5 @@
 sfc-y			+= efx.o falcon.o tx.o rx.o falcon_xmac.o \
 			   selftest.o ethtool.o xfp_phy.o \
-			   mdio_10g.o tenxpress.o boards.o sfe4001.o
-
+			   mdio_10g.o tenxpress.o boards.o sfe4001.o \
+			   driverlink.o
 obj-$(CONFIG_SFC)	+= sfc.o
drivers/net/sfc/driverlink.c new file +525 -0

525 lines not on this page · raw message

drivers/net/sfc/driverlink.h new file +76 -0

76 lines not on this page · raw message

drivers/net/sfc/driverlink_api.h new file +614 -0

614 lines not on this page · raw message

drivers/net/sfc/efx.c +33 -1
index 74265d8..0e153cb 100644
@@ -544,6 +544,9 @@ static void efx_link_status_changed(struct efx_nic *efx)
 			netif_carrier_off(efx->net_dev);
 	}
 
+	/* Inform driverlink client */
+	EFX_DL_CALLBACK(efx, link_change, efx->link_up);
+
 	/* Status message for kernel log */
 	if (efx->link_up) {
 		struct mii_if_info *gmii = &efx->mii;
@@ -1410,6 +1413,8 @@ static int efx_change_mtu(struct net_device *net_dev, int new_mtu)
 
 	efx_stop_all(efx);
 
+	/* Ask driverlink client if we can change MTU */
+	rc = EFX_DL_CALLBACK(efx, request_mtu, new_mtu);
 	EFX_LOG(efx, "changing MTU to %d\n", new_mtu);
 
 	efx_fini_channels(efx);
@@ -1418,6 +1423,9 @@ static int efx_change_mtu(struct net_device *net_dev, int new_mtu)
 	if (rc)
 		goto fail;
 
+	/* Notify driverlink client of new MTU */
+	EFX_DL_CALLBACK(efx, mtu_changed, new_mtu);
+
 	efx_start_all(efx);
 	return rc;
 
@@ -1570,6 +1578,23 @@ static void efx_unregister_netdev(struct efx_nic *efx)
  * Device reset and suspend
  *
  **************************************************************************/
+/* Serialise access to the driverlink callbacks, by quiescing event processing
+ * (without flushing the descriptor queues), and acquiring the rtnl_lock */
+void efx_suspend(struct efx_nic *efx)
+{
+	EFX_LOG(efx, "suspending operations\n");
+
+	rtnl_lock();
+	efx_stop_all(efx);
+}
+
+void efx_resume(struct efx_nic *efx)
+{
+	EFX_LOG(efx, "resuming operations\n");
+
+	efx_start_all(efx);
+	rtnl_unlock();
+}
 
 /* The final hardware and software finalisation before reset. */
 static int efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd)
@@ -1632,6 +1657,10 @@ static int efx_reset(struct efx_nic *efx)
 	enum reset_type method = efx->reset_pending;
 	int rc;
 
+	/* Notify driverlink clients of imminent reset. */
+	efx_dl_reset_lock();
+	efx_dl_reset_suspend(efx);
+
 	/* Serialise with kernel interfaces */
 	rtnl_lock();
 
@@ -1701,8 +1730,9 @@ static int efx_reset(struct efx_nic *efx)
 
  unlock_rtnl:
 	rtnl_unlock();
+	efx_dl_reset_resume(efx, 1);
+	efx_dl_reset_unlock();
 	return 0;
-
  fail5:
  fail4:
  fail3:
@@ -1715,6 +1745,8 @@ static int efx_reset(struct efx_nic *efx)
 	rtnl_unlock();
 	efx_unregister_netdev(efx);
 	efx_fini_port(efx);
+	efx_dl_reset_resume(efx, 0);
+	efx_dl_reset_unlock();
 	return rc;
 }
 
@@ -1854,6 +1886,9 @@ static int efx_init_struct(struct efx_nic *efx, struct

efx_nic_type *type,
mutex_init(&efx->mac_lock);
efx->phy_op = &efx_dummy_phy_operations; efx->mii.dev = net_dev;
+ INIT_LIST_HEAD(&efx->dl_node);
+ INIT_LIST_HEAD(&efx->dl_device_list);
+ efx->dl_cb = efx_default_callbacks;
INIT_WORK(&efx->reconfigure_work, efx_reconfigure_work); atomic_set(&efx->netif_stop_count, 1);

@@ -1960,6 +1995,9 @@ static void efx_pci_remove(struct pci_dev *pci_dev)
if (!efx)
return;

+ /* Unregister driver from driverlink layer */
+ efx_dl_unregister_nic(efx);
+
/* Mark the NIC as fini, then stop the interface */ rtnl_lock();
efx->state = STATE_FINI;
@@ -2126,8 +2164,15 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev,

EFX_LOG(efx, "initialisation successful\n");

+ /* Register with driverlink layer */
+ rc = efx_dl_register_nic(efx);
+ if (rc)
+ goto fail6;
+
return 0;

+ fail6:
+ efx_unregister_netdev(efx);
fail5:
efx_pci_remove_main(efx);
fail4:

drivers/net/sfc/falcon.c +9 -0
index 630406e..959e06a 100644
@@ -36,14 +36,23 @@
 
 /**
  * struct falcon_nic_data - Falcon NIC state
+ * @tx_dc_entries: Number of entries in each TX queue descriptor cache
+ * @rx_dc_entries: Number of entries in each RX queue descriptor cache
+ * @tx_dc_base: Base address in SRAM of TX queue descriptor caches
+ * @rx_dc_base: Base address in SRAM of RX queue descriptor caches
  * @next_buffer_table: First available buffer table id
  * @pci_dev2: The secondary PCI device if present
  * @i2c_data: Operations and state for I2C bit-bashing algorithm
  */
 struct falcon_nic_data {
+	unsigned tx_dc_entries;
+	unsigned rx_dc_entries;
+	unsigned tx_dc_base;
+	unsigned rx_dc_base;
 	unsigned next_buffer_table;
 	struct pci_dev *pci_dev2;
 	struct i2c_algo_bit_data i2c_data;
+	struct efx_dl_falcon_resources resources;
 };
 
 /**************************************************************************
@@ -1120,10 +1129,12 @@ static void falcon_handle_driver_event(struct efx_channel

*channel,
case TX_DESCQ_FLS_DONE_EV_DECODE:
EFX_TRACE(efx, "channel %d TXQ %d flushed\n",
channel->channel, ev_sub_data);
+ EFX_DL_CALLBACK(efx, event, event);
break;
case RX_DESCQ_FLS_DONE_EV_DECODE:
EFX_TRACE(efx, "channel %d RXQ %d flushed\n",
channel->channel, ev_sub_data);
+ EFX_DL_CALLBACK(efx, event, event);
break;
case EVQ_INIT_DONE_EV_DECODE:
EFX_LOG(efx, "channel %d EVQ %d initialised\n",
@@ -1132,14 +1143,17 @@ static void falcon_handle_driver_event(struct efx_channel *channel,
case SRM_UPD_DONE_EV_DECODE:
EFX_TRACE(efx, "channel %d SRAM update done\n",
channel->channel);
+ EFX_DL_CALLBACK(efx, event, event);
break;
case WAKE_UP_EV_DECODE:
EFX_TRACE(efx, "channel %d RXQ %d wakeup event\n",
channel->channel, ev_sub_data);
+ EFX_DL_CALLBACK(efx, event, event);
break;
case TIMER_EV_DECODE:
EFX_TRACE(efx, "channel %d RX queue %d timer expired\n",
channel->channel, ev_sub_data);
+ EFX_DL_CALLBACK(efx, event, event);
break;
case RX_RECOVERY_EV_DECODE:
EFX_ERR(efx, "channel %d seen DRIVER RX_RESET event. "
@@ -1164,6 +1178,7 @@ static void falcon_handle_driver_event(struct efx_channel *channel,
EFX_TRACE(efx, "channel %d unknown driver event code %d "
"data %04x\n", channel->channel, ev_sub_code, ev_sub_data);
+ EFX_DL_CALLBACK(efx, event, event);
break;
}
}
@@ -2376,6 +2391,70 @@ static int falcon_probe_nvconfig(struct efx_nic *efx)
return rc;
}

+/* Looks at available SRAM resources and silicon revision, and works out
+ * how many queues we can support, and where things like descriptor caches
+ * should live. */
+static int falcon_dimension_resources(struct efx_nic *efx)
+{
+ unsigned buffer_entry_bytes, internal_dcs_entries;
+ struct falcon_nic_data *nic_data = efx->nic_data;
+ struct efx_dl_falcon_resources *res = &nic_data->resources;
+
+ /* Fill out the driverlink resource list */
+ res->hdr.type = EFX_DL_FALCON_RESOURCES;
+ res->biu_lock = &efx->biu_lock;
+ efx->dl_info = &res->hdr;
+ nic_data->tx_dc_entries = 16;
+
+ /* Set the RX descriptor cache size. Values 16, 32 and 64 are
+ * supported (8 won't work). Bigger is better, especially on B
+ * silicon.
+ */
+ nic_data->rx_dc_entries = 64;
+
+ /* NB. The minimum values get increased as this driver initialises
+ * its resources, so this should prevent any overlap.
+ */
+ switch (falcon_rev(efx)) {
+ case FALCON_REV_A1:
+ res->rxq_min = 16;
+ res->txq_min = 16;
+ res->evq_int_min = 4;
+ res->evq_int_lim = 5;
+ res->evq_timer_min = 5;
+ res->evq_timer_lim = 4096;
+ internal_dcs_entries = 8192;
+ break;
+ case FALCON_REV_B0:
+ default:
+ res->rxq_min = 0;
+ res->txq_min = 0;
+ res->evq_int_min = 0;
+ res->evq_int_lim = 64;
+ res->evq_timer_min = 64;
+ res->evq_timer_lim = 4096;
+ internal_dcs_entries = 4096;
+ break;
+ }
+
+ buffer_entry_bytes = 8;
+
+ res->rxq_lim = internal_dcs_entries / nic_data->rx_dc_entries;
+ res->txq_lim = internal_dcs_entries / nic_data->tx_dc_entries;
+ /* Internal SRAM only for now */
+ res->buffer_table_lim = 8192;
+ nic_data->tx_dc_base = 0x130000;
+ nic_data->rx_dc_base = 0x100000;
+
+ if (FALCON_IS_DUAL_FUNC(efx))
+ res->flags |= EFX_DL_FALCON_DUAL_FUNC;
+
+ if (EFX_INT_MODE_USE_MSI(efx))
+ res->flags |= EFX_DL_FALCON_USE_MSI;
+
+ return 0;
+}
+
/* Probe the NIC variant (revision, ASIC vs FPGA, function count, port
* count, port speed). Set workaround and feature flags accordingly. */
@@ -2477,6 +2556,10 @@ int falcon_probe_nic(struct efx_nic *efx)
if (rc)
goto fail5;

+ rc = falcon_dimension_resources(efx);
+ if (rc)
+ goto fail6;
+
/* Initialise I2C adapter */ efx->i2c_adap.owner = THIS_MODULE; efx->i2c_adap.class = I2C_CLASS_HWMON;
@@ -2487,10 +2570,12 @@ int falcon_probe_nic(struct efx_nic *efx)
strcpy(efx->i2c_adap.name, "SFC4000 GPIO");
rc = i2c_bit_add_bus(&efx->i2c_adap);
if (rc)
- goto fail5;
+ goto fail6;

return 0;

+ fail6:
+ efx->dl_info = NULL;
fail5:
falcon_free_buffer(efx, &efx->irq_status);
fail4:
@@ -2681,6 +2766,7 @@ void falcon_remove_nic(struct efx_nic *efx)
/* Tear down the private nic state */ kfree(efx->nic_data);
efx->nic_data = NULL;
+ efx->dl_info = NULL;
}

void falcon_update_nic_stats(struct efx_nic *efx)

drivers/net/sfc/net_driver.h +15 -0
index d803b86..2a84468 100644
@@ -30,6 +30,8 @@
 
 #include "enum.h"
 #include "bitfield.h"
+#include "driverlink_api.h"
+#include "driverlink.h"
 
 #define EFX_MAX_LRO_DESCRIPTORS 8
 #define EFX_MAX_LRO_AGGR MAX_SKB_FRAGS
@@ -674,6 +676,12 @@ union efx_multicast_hash {
  * @loopback_mode: Loopback status
  * @loopback_modes: Supported loopback mode bitmask
  * @loopback_selftest: Offline self-test private state
+ * @silicon_rev: Silicon revision description for driverlink
+ * @dl_info: Linked list of hardware parameters exposed through driverlink
+ * @dl_node: Driverlink port list
+ * @dl_device_list: Driverlink device list
+ * @dl_cb: Driverlink callbacks table
+ * @dl_cb_dev: Driverlink callback owner devices
  *
  * The @priv field of the corresponding &struct net_device points to
  * this.
@@ -749,6 +757,13 @@ struct efx_nic {
 	unsigned int loopback_modes;
 
 	void *loopback_selftest;
+
+	const char *silicon_rev;
+	struct efx_dl_device_info *dl_info;
+	struct list_head dl_node;
+	struct list_head dl_device_list;
+	struct efx_dl_callbacks dl_cb;
+	struct efx_dl_cb_devices dl_cb_dev;
 };
 
 static inline int efx_dev_registered(struct efx_nic *efx)
Signature · 1 line
1.5.3.7