sfc: Changes for 2.6.29
Subsystems (3)
cover sfc: Changes for 2.6.29
This patch series includes one bug fix also submitted for .28, and a number of features that were removed from the out-of-tree driver before submission and have now been simplified and cleaned up.
The MTD driver exposes only the flash partition used for the "expansion ROM". We are working on gPXE support for our boards and this makes it easy for users and developers to update their boards. We do not want to expose flash through the ethtool EEPROM access functions because they are unsuitable for flash and we already map them to the gPXE configuration partition which really is in EEPROM.
The hardware monitoring code is now mostly contained in the lm87 and lm90 drivers. We just configure the sensor limits as necessary and shut down the PHY in case of an alarm.
Driverlink provides an API to share the NIC's resources with other drivers that implement hardware-assisted network device virtualisation. This has already been used to good effect in Xen Linux. We hope to do the same for mainline Linux kernels acting as a hypervisor or dom0.
Ben.
Ben Hutchings (6):
sfc: Correct address of gPXE boot configuration in EEPROM
sfc: Clean up non-volatile memory partitioning
sfc: Expose flash region storing boot code as MTD
sfc: Use lm87 and lm90 drivers for board temperature/power monitoring
sfc: Do not reset when hardware monitor detects a fault
sfc: Add driverlink API to support virtual NIC drivers
drivers/net/sfc/Kconfig | 8 + drivers/net/sfc/Makefile | 4 +- drivers/net/sfc/boards.c | 136 ++++++++++ drivers/net/sfc/driverlink.c | 481 +++++++++++++++++++++++++++++++++++ drivers/net/sfc/driverlink.h | 70 +++++ drivers/net/sfc/driverlink_api.h | 516 ++++++++++++++++++++++++++++++++++++++ drivers/net/sfc/efx.c | 70 ++++-- drivers/net/sfc/efx.h | 10 + drivers/net/sfc/enum.h | 4 +- drivers/net/sfc/ethtool.c | 15 +- drivers/net/sfc/falcon.c | 102 +++++++- drivers/net/sfc/falcon_hwdefs.h | 1 - drivers/net/sfc/mdio_10g.c | 35 +++ drivers/net/sfc/mdio_10g.h | 7 + drivers/net/sfc/mtd.c | 268 ++++++++++++++++++++ drivers/net/sfc/net_driver.h | 23 ++ drivers/net/sfc/sfe4001.c | 116 ++++----- drivers/net/sfc/spi.h | 34 +++- drivers/net/sfc/tenxpress.c | 18 ++- drivers/net/sfc/workarounds.h | 2 + drivers/net/sfc/xfp_phy.c | 9 + 21 files changed, 1818 insertions(+), 111 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 create mode 100644 drivers/net/sfc/mtd.c
Signature · 3 lines
Ben Hutchings, Senior Software Engineer, Solarflare Communications Not speaking for my employer; that's the marketing department's job. They asked us to note that Solarflare product names are trademarked.
PATCH 1/6 sfc: Correct address of gPXE boot configuration in EEPROM
Due to a hardware bug, the originally assigned range cannot reliably be used for boot configuration and must not be modifiable through ethtool.
--- drivers/net/sfc/ethtool.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)
drivers/net/sfc/ethtool.c +2 -2
@@ -174,8 +174,8 @@ static struct efx_ethtool_stat efx_ethtool_stats[] = {/* EEPROM range with gPXE configuration */ #define EFX_ETHTOOL_EEPROM_MAGIC 0xEFAB -#define EFX_ETHTOOL_EEPROM_MIN 0x100U -#define EFX_ETHTOOL_EEPROM_MAX 0x400U +#define EFX_ETHTOOL_EEPROM_MIN 0x800U +#define EFX_ETHTOOL_EEPROM_MAX 0x1800U/************************************************************************** *
Signature · 3 lines
Ben Hutchings, Senior Software Engineer, Solarflare Communications Not speaking for my employer; that's the marketing department's job. They asked us to note that Solarflare product names are trademarked.
Re: [PATCH 1/6] sfc: Correct address of gPXE boot configuration in EEPROM
Quoted 14 lines · Ben Hutchings
Due to a hardware bug, the originally assigned range cannot reliably be used for boot configuration and must not be modifiable through ethtool.
Signed-off-by Ben Hutchings <[email protected]>--- drivers/net/sfc/ethtool.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)drivers/net/sfc/ethtool.c +0
-0
drivers/net/sfc/ethtool.c static struct efx_ethtool_stat efx_ethtool_stats[] = { · line 178
Quoted 7 lines
drivers/net/sfc/ethtool.c +2
-2@@ -174,8 +174,8 @@ static struct efx_ethtool_stat efx_ethtool_stats[] = {/* EEPROM range with gPXE configuration */ #define EFX_ETHTOOL_EEPROM_MAGIC 0xEFAB -#define EFX_ETHTOOL_EEPROM_MIN 0x100U -#define EFX_ETHTOOL_EEPROM_MAX 0x400U +#define EFX_ETHTOOL_EEPROM_MIN 0x800U +#define EFX_ETHTOOL_EEPROM_MAX 0x1800U
this seems like something for 2.6.28-rc not 2.6.29, so why wait for 2.6.29?
Re: [PATCH 1/6] sfc: Correct address of gPXE boot configuration in EEPROM
Quoted 17 lines · Jeff Garzik
Quoted 16 lines · Ben Hutchings
Due to a hardware bug, the originally assigned range cannot reliably be used for boot configuration and must not be modifiable through ethtool.
Signed-off-by Ben Hutchings <[email protected]>--- drivers/net/sfc/ethtool.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)drivers/net/sfc/ethtool.c +0
-0@@ -174,8 +174,8 @@ static struct efx_ethtool_stat efx_ethtool_stats[] = {
Quoted 8 lines
drivers/net/sfc/ethtool.c static struct efx_ethtool_stat efx_ethtool_stats[] = { · line 178
Quoted 6 lines
drivers/net/sfc/ethtool.c +2
-2/* EEPROM range with gPXE configuration */ #define EFX_ETHTOOL_EEPROM_MAGIC 0xEFAB -#define EFX_ETHTOOL_EEPROM_MIN 0x100U -#define EFX_ETHTOOL_EEPROM_MAX 0x400U +#define EFX_ETHTOOL_EEPROM_MIN 0x800U +#define EFX_ETHTOOL_EEPROM_MAX 0x1800Uthis seems like something for 2.6.28-rc not 2.6.29, so why wait for 2.6.29?
nevermind, I see the other patch now...
Re: [PATCH 1/6] sfc: Correct address of gPXE boot configuration in EEPROM
In reply to Ben HutchingsQuoted 14 lines · Ben Hutchings
Due to a hardware bug, the originally assigned range cannot reliably be used for boot configuration and must not be modifiable through ethtool.
Signed-off-by Ben Hutchings <[email protected]>--- drivers/net/sfc/ethtool.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)drivers/net/sfc/ethtool.c +0
-0
drivers/net/sfc/ethtool.c static struct efx_ethtool_stat efx_ethtool_stats[] = { · line 178
Quoted 7 lines
drivers/net/sfc/ethtool.c +2
-2@@ -174,8 +174,8 @@ static struct efx_ethtool_stat efx_ethtool_stats[] = {/* EEPROM range with gPXE configuration */ #define EFX_ETHTOOL_EEPROM_MAGIC 0xEFAB -#define EFX_ETHTOOL_EEPROM_MIN 0x100U -#define EFX_ETHTOOL_EEPROM_MAX 0x400U +#define EFX_ETHTOOL_EEPROM_MIN 0x800U +#define EFX_ETHTOOL_EEPROM_MAX 0x1800U
applied 1-5, I want a bit more time to review #6
PATCH 2/6 sfc: Clean up non-volatile memory partitioning
In reply to Ben HutchingsMove flash and EEPROM partition boundary constants into spi.h and rename them to be consistent.
Add a comment on the partitioning.
--- drivers/net/sfc/ethtool.c | 11 ++++------- drivers/net/sfc/falcon.c | 6 +++--- drivers/net/sfc/falcon_hwdefs.h | 1 - drivers/net/sfc/spi.h | 17 +++++++++++++++++ 4 files changed, 24 insertions(+), 11 deletions(-)
drivers/net/sfc/ethtool.c +4 -7
@@ -172,10 +172,7 @@ static struct efx_ethtool_stat efx_ethtool_stats[] = {/* Number of ethtool statistics */ #define EFX_ETHTOOL_NUM_STATS ARRAY_SIZE(efx_ethtool_stats) -/* EEPROM range with gPXE configuration */ #define EFX_ETHTOOL_EEPROM_MAGIC 0xEFAB -#define EFX_ETHTOOL_EEPROM_MIN 0x800U -#define EFX_ETHTOOL_EEPROM_MAX 0x1800U/************************************************************************** *
@@ -545,8 +542,8 @@ static int efx_ethtool_get_eeprom_len(struct net_device *net_dev)if (!spi)return 0 ; -return min (spi->size,EFX_ETHTOOL_EEPROM_MAX ) - -min (spi->size,EFX_ETHTOOL_EEPROM_MIN ); +return min (spi->size,EFX_EEPROM_BOOTCONFIG_END ) - +min (spi->size,EFX_EEPROM_BOOTCONFIG_START ); } static int efx_ethtool_get_eeprom(struct net_device *net_dev,
@@ -557,7 +554,7 @@ static int efx_ethtool_get_eeprom(struct net_device *net_dev,size_t len;int rc; - rc =falcon_spi_read (spi, eeprom->offset +EFX_ETHTOOL_EEPROM_MIN , + rc =falcon_spi_read (spi, eeprom->offset +EFX_EEPROM_BOOTCONFIG_START , eeprom->len, &len, buf); eeprom->magic =EFX_ETHTOOL_EEPROM_MAGIC ; eeprom->len = len;
@@ -575,7 +572,7 @@ static int efx_ethtool_set_eeprom(struct net_device *net_dev,if (eeprom->magic !=EFX_ETHTOOL_EEPROM_MAGIC )return -EINVAL ; - rc =falcon_spi_write (spi, eeprom->offset +EFX_ETHTOOL_EEPROM_MIN , + rc =falcon_spi_write (spi, eeprom->offset +EFX_EEPROM_BOOTCONFIG_START , eeprom->len, &len, buf); eeprom->len = len;return rc;
drivers/net/sfc/falcon.c +3 -3
@@ -2253,13 +2253,13 @@ int falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out)__le16 *word, *limit;u32 csum; - region =kmalloc (NVCONFIG_END ,GFP_KERNEL ); + region =kmalloc (FALCON_NVCONFIG_END ,GFP_KERNEL );if (!region)return -ENOMEM ; nvconfig = region +NVCONFIG_OFFSET ; spi = efx->spi_flash ? efx->spi_flash : efx->spi_eeprom; - rc =falcon_spi_read (spi,0 ,NVCONFIG_END ,NULL , region); + rc =falcon_spi_read (spi,0 ,FALCON_NVCONFIG_END ,NULL , region);if (rc) {EFX_ERR (efx,"Failed to read %s\n" , efx->spi_flash ?"flash" :"EEPROM" );
@@ -2283,7 +2283,7 @@ int falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out) limit = (__le16 *) (nvconfig +1 ); }else { word = region; - limit = region +NVCONFIG_END ; + limit = region +FALCON_NVCONFIG_END ; }for (csum =0 ; word < limit; ++word) csum +=le16_to_cpu (*word);
drivers/net/sfc/falcon_hwdefs.h +0 -1
@@ -1150,7 +1150,6 @@ struct falcon_nvconfig_board_v3 { (((type) >> EFX_LOW_BIT(field)) & EFX_MASK32(EFX_WIDTH(field)))#define NVCONFIG_OFFSET 0x300 -#define NVCONFIG_END 0x400#define NVCONFIG_BOARD_MAGIC_NUM 0xFA1Cstruct falcon_nvconfig {
drivers/net/sfc/spi.h +17 -0
@@ -63,4 +63,21 @@ int falcon_spi_read(const struct efx_spi_device *spi, loff_t start,int falcon_spi_write (const struct efx_spi_device *spi,loff_t start,size_t len,size_t *retlen,const u8 *buffer); +/* +* SFC4000 flash is partitioned into: +* 0-0x400 chip and board config (see falcon_hwdefs.h) +* 0x400-0x8000 unused (or may contain VPD if EEPROM not present) +* 0x8000-end boot code (mapped to PCI expansion ROM) +* SFC4000 small EEPROM (size < 0x400) is used for VPD only. +* SFC4000 large EEPROM (size >= 0x400) is partitioned into: +* 0-0x400 chip and board config +* configurable VPD +* 0x800-0x1800 boot config +* Aside from the chip and board config, all of these are optional and may +* be absent or truncated depending on the devices used. +*/ +#define FALCON_NVCONFIG_END 0x400U +#define EFX_EEPROM_BOOTCONFIG_START 0x800U +#define EFX_EEPROM_BOOTCONFIG_END 0x1800U +#endif /* EFX_SPI_H */
Signature · 3 lines
Ben Hutchings, Senior Software Engineer, Solarflare Communications Not speaking for my employer; that's the marketing department's job. They asked us to note that Solarflare product names are trademarked.
PATCH 3/6 sfc: Expose flash region storing boot code as MTD
In reply to Ben HutchingsThe boot code that appears as a PCI expansion ROM on the SFC4000 is stored in flash. Expose this as a standard MTD device to allow for in-place upgrades.
--- drivers/net/sfc/Kconfig | 8 ++ drivers/net/sfc/Makefile | 1 + drivers/net/sfc/efx.c | 7 + drivers/net/sfc/efx.h | 10 ++ drivers/net/sfc/ethtool.c | 4 + drivers/net/sfc/falcon.c | 17 ++- drivers/net/sfc/mtd.c | 268 ++++++++++++++++++++++++++++++++++++++++++ drivers/net/sfc/net_driver.h | 2 + drivers/net/sfc/spi.h | 17 +++- 9 files changed, 327 insertions(+), 7 deletions(-) create mode 100644 drivers/net/sfc/mtd.c
drivers/net/sfc/Kconfig +8 -0
@@ -12,3 +12,11 @@ config SFC To compile this driver as a module, choose M here. The module will be called sfc. +config SFC_MTD + bool "Solarflare Solarstorm SFC4000 flash MTD support" + depends on SFC && MTD + default y + help + This exposes the on-board flash memory as an MTD device (e.g. + /dev/mtd1). This makes it possible to upload new boot code + to the NIC.
drivers/net/sfc/Makefile +1 -0
@@ -1,5 +1,6 @@ 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 +sfc-$(CONFIG_SFC_MTD) += mtd.o obj-$(CONFIG_SFC) += sfc.o
drivers/net/sfc/efx.c +7 -0
@@ -1459,6 +1459,7 @@ static int efx_netdev_event(struct notifier_block *this,struct efx_nic *efx =netdev_priv (net_dev);strcpy (efx->name, net_dev->name); +efx_mtd_rename (efx); }return NOTIFY_DONE ;
@@ -1550,6 +1551,7 @@ void efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd)efx_stop_all (efx);mutex_lock (&efx->mac_lock); +mutex_lock (&efx->spi_lock); rc =falcon_xmac_get_settings (efx, ecmd);if (rc)
@@ -1582,6 +1584,7 @@ int efx_reset_up(struct efx_nic *efx, struct ethtool_cmd *ecmd, bool ok)EFX_ERR (efx,"could not restore PHY settings\n" ); } +mutex_unlock (&efx->spi_lock);mutex_unlock (&efx->mac_lock);if (ok) {
@@ -1777,6 +1780,7 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type,memset (efx,0 ,sizeof (*efx));spin_lock_init (&efx->biu_lock);spin_lock_init (&efx->phy_lock); +mutex_init (&efx->spi_lock);INIT_WORK (&efx->reset_work, efx_reset_work);INIT_DELAYED_WORK (&efx->monitor_work, efx_monitor); efx->pci_dev = pci_dev;
@@ -1911,6 +1915,8 @@ static void efx_pci_remove(struct pci_dev *pci_dev)if (!efx)return ; +efx_mtd_remove (efx); +/* Mark the NIC as fini, then stop the interface */ rtnl_lock (); efx->state =STATE_FINI ;
@@ -2077,6 +2083,7 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev,EFX_LOG (efx,"initialisation successful\n" ); +efx_mtd_probe (efx);/* allowed to fail */ return 0 ; fail5:
drivers/net/sfc/efx.h +10 -0
@@ -58,6 +58,16 @@ extern int efx_port_dummy_op_int(struct efx_nic *efx);extern void efx_port_dummy_op_void (struct efx_nic *efx);extern void efx_port_dummy_op_blink (struct efx_nic *efx,bool blink); +/* MTD */ +#ifdef CONFIG_SFC_MTD +extern int efx_mtd_probe (struct efx_nic *efx); +extern void efx_mtd_rename (struct efx_nic *efx); +extern void efx_mtd_remove (struct efx_nic *efx); +#else +static inline int efx_mtd_probe (struct efx_nic *efx) {return 0 ; } +static inline void efx_mtd_rename (struct efx_nic *efx) {} +static inline void efx_mtd_remove (struct efx_nic *efx) {} +#endif extern unsigned int efx_monitor_interval;
drivers/net/sfc/ethtool.c +4 -0
@@ -554,8 +554,10 @@ static int efx_ethtool_get_eeprom(struct net_device *net_dev,size_t len;int rc; +mutex_lock (&efx->spi_lock); rc =falcon_spi_read (spi, eeprom->offset +EFX_EEPROM_BOOTCONFIG_START , eeprom->len, &len, buf); +mutex_unlock (&efx->spi_lock); eeprom->magic =EFX_ETHTOOL_EEPROM_MAGIC ; eeprom->len = len;return rc;
@@ -572,8 +574,10 @@ static int efx_ethtool_set_eeprom(struct net_device *net_dev,if (eeprom->magic !=EFX_ETHTOOL_EEPROM_MAGIC )return -EINVAL ; +mutex_lock (&efx->spi_lock); rc =falcon_spi_write (spi, eeprom->offset +EFX_EEPROM_BOOTCONFIG_START , eeprom->len, &len, buf); +mutex_unlock (&efx->spi_lock); eeprom->len = len;return rc; }
drivers/net/sfc/falcon.c +12 -5
@@ -1628,9 +1628,9 @@ static int falcon_spi_wait(struct efx_nic *efx) } } -static int falcon_spi_cmd (const struct efx_spi_device *spi, -unsigned int command,int address, -const void *in,void *out,unsigned int len) +int falcon_spi_cmd (const struct efx_spi_device *spi, +unsigned int command,int address, +const void *in,void *out,unsigned int len) {struct efx_nic *efx = spi->efx;bool addressed = (address >=0 );
@@ -1641,6 +1641,7 @@ static int falcon_spi_cmd(const struct efx_spi_device *spi,/* Input validation */ if (len >FALCON_SPI_MAX_LEN )return -EINVAL ; +BUG_ON (!mutex_is_locked (&efx->spi_lock));/* Check SPI not currently being accessed */ rc =falcon_spi_wait (efx);
@@ -1699,8 +1700,7 @@ efx_spi_munge_command(const struct efx_spi_device *spi,return command | (((address >>8 ) & spi->munge_address) <<3 ); } - -static int falcon_spi_fast_wait (const struct efx_spi_device *spi) +int falcon_spi_fast_wait (const struct efx_spi_device *spi) {u8 status;int i, rc;
@@ -2259,7 +2259,9 @@ int falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out) nvconfig = region +NVCONFIG_OFFSET ; spi = efx->spi_flash ? efx->spi_flash : efx->spi_eeprom; +mutex_lock (&efx->spi_lock); rc =falcon_spi_read (spi,0 ,FALCON_NVCONFIG_END ,NULL , region); +mutex_unlock (&efx->spi_lock);if (rc) {EFX_ERR (efx,"Failed to read %s\n" , efx->spi_flash ?"flash" :"EEPROM" );
@@ -2555,6 +2557,11 @@ static int falcon_spi_device_init(struct efx_nic *efx,SPI_DEV_TYPE_FIELD (device_type,SPI_DEV_TYPE_ADDR_LEN ); spi_device->munge_address = (spi_device->size ==1 <<9 && spi_device->addr_len ==1 ); + spi_device->erase_command = +SPI_DEV_TYPE_FIELD (device_type,SPI_DEV_TYPE_ERASE_CMD ); + spi_device->erase_size = +1 <<SPI_DEV_TYPE_FIELD (device_type, +SPI_DEV_TYPE_ERASE_SIZE ); spi_device->block_size =1 <<SPI_DEV_TYPE_FIELD (device_type,SPI_DEV_TYPE_BLOCK_SIZE );
drivers/net/sfc/mtd.c new file +268 -0
268 lines not on this page · raw message
drivers/net/sfc/net_driver.h +2 -0
@@ -655,6 +655,7 @@ union efx_multicast_hash {* This field will be %NULL if no flash device is present. * @spi_eeprom: SPI EEPROM device * This field will be %NULL if no EEPROM device is present. +* @spi_lock: SPI bus lock * @n_rx_nodesc_drop_cnt: RX no descriptor drop count * @nic_data: Hardware dependant state * @mac_lock: MAC access lock. Protects @port_enabled, @phy_mode,
@@ -731,6 +732,7 @@ struct efx_nic {struct efx_spi_device *spi_flash;struct efx_spi_device *spi_eeprom; +struct mutex spi_lock;unsigned n_rx_nodesc_drop_cnt;
drivers/net/sfc/spi.h +15 -2
@@ -25,6 +25,7 @@#define SPI_WRDI 0x04/* Reset write enable latch */ #define SPI_RDSR 0x05/* Read status register */ #define SPI_WREN 0x06/* Set write enable latch */ +#define SPI_SST_EWSR 0x50/* SST: Enable write to status register */ #define SPI_STATUS_WPEN 0x80/* Write-protect pin enabled */ #define SPI_STATUS_BP2 0x10/* Block protection bit 2 */
@@ -36,6 +37,7 @@/** * struct efx_spi_device - an Efx SPI (Serial Peripheral Interface) device * @efx: The Efx controller that owns this device +* @mtd: MTD state * @device_id: Controller's id for the device * @size: Size (in bytes) * @addr_len: Number of address bytes in read/write commands
@@ -44,20 +46,30 @@* use bit 3 of the command byte as address bit A8, rather * than having a two-byte address. If this flag is set, then * commands should be munged in this way. +* @erase_command: Erase command (or 0 if sector erase not needed). +* @erase_size: Erase sector size (in bytes) +* Erase commands affect sectors with this size and alignment. +* This must be a power of two. * @block_size: Write block size (in bytes). * Write commands are limited to blocks with this size and alignment. -* @read: Read function for the device -* @write: Write function for the device */ struct efx_spi_device {struct efx_nic *efx; +#ifdef CONFIG_SFC_MTD +void *mtd; +#endif int device_id;unsigned int size;unsigned int addr_len;unsigned int munge_address:1 ; +u8 erase_command; +unsigned int erase_size;unsigned int block_size; }; +int falcon_spi_cmd (const struct efx_spi_device *spi,unsigned int command, +int address,const void * in,void *out,unsigned int len); +int falcon_spi_fast_wait (const struct efx_spi_device *spi);int falcon_spi_read (const struct efx_spi_device *spi,loff_t start,size_t len,size_t *retlen,u8 *buffer); int falcon_spi_write(const struct efx_spi_device *spi, loff_t start,
@@ -77,6 +89,7 @@ int falcon_spi_write(const struct efx_spi_device *spi, loff_t start,* be absent or truncated depending on the devices used. */ #define FALCON_NVCONFIG_END 0x400U +#define FALCON_FLASH_BOOTCODE_START 0x8000U#define EFX_EEPROM_BOOTCONFIG_START 0x800U#define EFX_EEPROM_BOOTCONFIG_END 0x1800U
Signature · 3 lines
Ben Hutchings, Senior Software Engineer, Solarflare Communications Not speaking for my employer; that's the marketing department's job. They asked us to note that Solarflare product names are trademarked.
PATCH 4/6 sfc: Use lm87 and lm90 drivers for board temperature/power monitoring
In reply to Ben HutchingsAdd board monitoring to periodic work whenever link is down. For SFE4001, report when a fault has caused the PHY to turn off. For SFE4002, switch XFP PHY into low-power state in case of a fault.
--- drivers/net/sfc/boards.c | 136 +++++++++++++++++++++++++++++++++++++++++ drivers/net/sfc/mdio_10g.c | 35 +++++++++++ drivers/net/sfc/mdio_10g.h | 7 ++ drivers/net/sfc/net_driver.h | 6 ++ drivers/net/sfc/sfe4001.c | 116 ++++++++++++++++------------------- drivers/net/sfc/tenxpress.c | 18 +++++- drivers/net/sfc/workarounds.h | 2 + drivers/net/sfc/xfp_phy.c | 9 +++ 8 files changed, 265 insertions(+), 64 deletions(-)
drivers/net/sfc/boards.c +136 -0
@@ -11,6 +11,7 @@#include "phy.h" #include "boards.h" #include "efx.h" +#include "workarounds.h" /* Macros for unpacking the board revision */ /* The revision info is in host byte order. */
@@ -52,9 +53,128 @@ static void board_blink(struct efx_nic *efx, bool blink) }/***************************************************************************** +* Support for LM87 sensor chip used on several boards +*/ +#define LM87_REG_ALARMS1 0x41 +#define LM87_REG_ALARMS2 0x42 +#define LM87_IN_LIMITS (nr, _min, _max) \ + 0x2B + (nr) * 2, _max, 0x2C + (nr) * 2, _min +#define LM87_AIN_LIMITS (nr, _min, _max) \ + 0x3B + (nr), _max, 0x1A + (nr), _min +#define LM87_TEMP_INT_LIMITS (_min, _max) \ + 0x39, _max, 0x3A, _min +#define LM87_TEMP_EXT1_LIMITS (_min, _max) \ + 0x37, _max, 0x38, _min + +#define LM87_ALARM_TEMP_INT 0x10 +#define LM87_ALARM_TEMP_EXT1 0x20 + +#if defined(CONFIG_SENSORS_LM87 ) || defined(CONFIG_SENSORS_LM87_MODULE ) + +static int efx_init_lm87 (struct efx_nic *efx,struct i2c_board_info *info, +const u8 *reg_values) +{ +struct i2c_client *client =i2c_new_device (&efx->i2c_adap, info); +int rc; + +if (!client) +return -EIO ; + +while (*reg_values) { +u8 reg = *reg_values++; +u8 value = *reg_values++; + rc =i2c_smbus_write_byte_data (client, reg, value); +if (rc) + goto err; + } + + efx->board_info.hwmon_client = client; +return 0 ; + +err: +i2c_unregister_device (client); +return rc; +} + +static void efx_fini_lm87 (struct efx_nic *efx) +{ +i2c_unregister_device (efx->board_info.hwmon_client); +} + +static int efx_check_lm87 (struct efx_nic *efx,unsigned mask) +{ +struct i2c_client *client = efx->board_info.hwmon_client; +s32 alarms1, alarms2; + +/* If link is up then do not monitor temperature */ +if (EFX_WORKAROUND_7884 (efx) && efx->link_up) +return 0 ; + + alarms1 =i2c_smbus_read_byte_data (client,LM87_REG_ALARMS1 ); + alarms2 =i2c_smbus_read_byte_data (client,LM87_REG_ALARMS2 ); +if (alarms1 <0 ) +return alarms1; +if (alarms2 <0 ) +return alarms2; + alarms1 &= mask; + alarms2 &= mask >>8 ; +if (alarms1 || alarms2) { +EFX_ERR (efx, +"LM87 detected a hardware failure (status %02x:%02x)" +"%s%s\n" , + alarms1, alarms2, + (alarms1 &LM87_ALARM_TEMP_INT ) ?" INTERNAL" :"" , + (alarms1 &LM87_ALARM_TEMP_EXT1 ) ?" EXTERNAL" :"" ); +return -ERANGE ; + } + +return 0 ; +} + +#else /* !CONFIG_SENSORS_LM87 */ + +static inline int +efx_init_lm87 (struct efx_nic *efx,struct i2c_board_info *info, +const u8 *reg_values) +{ +return 0 ; +} +static inline void efx_fini_lm87 (struct efx_nic *efx) +{ +} +static inline int efx_check_lm87 (struct efx_nic *efx,unsigned mask) +{ +return 0 ; +} + +#endif /* CONFIG_SENSORS_LM87 */ + +/***************************************************************************** * Support for the SFE4002 * */ +static u8 sfe4002_lm87_channel =0x03 ;/* use AIN not FAN inputs */ + +static const u8 sfe4002_lm87_regs[] = { +LM87_IN_LIMITS (0 ,0x83 ,0x91 ),/* 2.5V: 1.8V +/- 5% */ +LM87_IN_LIMITS (1 ,0x51 ,0x5a ),/* Vccp1: 1.2V +/- 5% */ +LM87_IN_LIMITS (2 ,0xb6 ,0xca ),/* 3.3V: 3.3V +/- 5% */ +LM87_IN_LIMITS (3 ,0xb0 ,0xc9 ),/* 5V: 4.6-5.2V */ +LM87_IN_LIMITS (4 ,0xb0 ,0xe0 ),/* 12V: 11-14V */ +LM87_IN_LIMITS (5 ,0x44 ,0x4b ),/* Vccp2: 1.0V +/- 5% */ +LM87_AIN_LIMITS (0 ,0xa0 ,0xb2 ),/* AIN1: 1.66V +/- 5% */ +LM87_AIN_LIMITS (1 ,0x91 ,0xa1 ),/* AIN2: 1.5V +/- 5% */ +LM87_TEMP_INT_LIMITS (10 ,60 ),/* board */ +LM87_TEMP_EXT1_LIMITS (10 ,70 ),/* Falcon */ +0 +}; + +static struct i2c_board_info sfe4002_hwmon_info = { +I2C_BOARD_INFO ("lm87" ,0x2e ), + .platform_data = &sfe4002_lm87_channel, + .irq =-1 , +}; +/****************************************************************************/ /* LED allocations. Note that on rev A0 boards the schematic and the reality * differ: red and green are swapped. Below is the fixed (A1) layout (there
@@ -84,11 +204,27 @@ static void sfe4002_fault_led(struct efx_nic *efx, bool state) QUAKE_LED_OFF); } +static int sfe4002_check_hw (struct efx_nic *efx) +{ +/* A0 board rev. 4002s report a temperature fault the whole time +* (bad sensor) so we mask it out. */ +unsigned alarm_mask = + (efx->board_info.major ==0 && efx->board_info.minor ==0 ) ? + ~LM87_ALARM_TEMP_EXT1 : ~0 ; + +return efx_check_lm87 (efx, alarm_mask); +} +static int sfe4002_init (struct efx_nic *efx) { +int rc =efx_init_lm87 (efx, &sfe4002_hwmon_info, sfe4002_lm87_regs); +if (rc) +return rc; + efx->board_info.monitor = sfe4002_check_hw; efx->board_info.init_leds = sfe4002_init_leds; efx->board_info.set_fault_led = sfe4002_fault_led; efx->board_info.blink = board_blink; + efx->board_info.fini = efx_fini_lm87;return 0 ; }
drivers/net/sfc/mdio_10g.c +35 -0
@@ -260,6 +260,41 @@ void mdio_clause45_phy_reconfigure(struct efx_nic *efx) MDIO_MMDREG_CTRL1, ctrl2); } +static void mdio_clause45_set_mmd_lpower (struct efx_nic *efx, +int lpower,int mmd) +{ +int phy = efx->mii.phy_id; +int stat =mdio_clause45_read (efx, phy, mmd,MDIO_MMDREG_STAT1 ); +int ctrl1, ctrl2; + +EFX_TRACE (efx,"Setting low power mode for MMD %d to %d\n" , + mmd, lpower); + +if (stat & (1 <<MDIO_MMDREG_STAT1_LPABLE_LBN )) { + ctrl1 = ctrl2 =mdio_clause45_read (efx, phy, + mmd,MDIO_MMDREG_CTRL1 ); +if (lpower) + ctrl2 |= (1 <<MDIO_MMDREG_CTRL1_LPOWER_LBN ); +else + ctrl2 &= ~(1 <<MDIO_MMDREG_CTRL1_LPOWER_LBN ); +if (ctrl1 != ctrl2) +mdio_clause45_write (efx, phy, mmd, +MDIO_MMDREG_CTRL1 , ctrl2); + } +} + +void mdio_clause45_set_mmds_lpower (struct efx_nic *efx, +int low_power,unsigned int mmd_mask) +{ +int mmd =0 ; +while (mmd_mask) { +if (mmd_mask &1 ) +mdio_clause45_set_mmd_lpower (efx, low_power, mmd); + mmd_mask = (mmd_mask >>1 ); + mmd++; + } +} +/** * mdio_clause45_get_settings - Read (some of) the PHY settings over MDIO. * @efx: Efx NIC
drivers/net/sfc/mdio_10g.h +7 -0
@@ -54,6 +54,9 @@/* Loopback bit for WIS, PCS, PHYSX and DTEXS */ #define MDIO_MMDREG_CTRL1_LBACK_LBN (14)#define MDIO_MMDREG_CTRL1_LBACK_WIDTH (1) +/* Low power */ +#define MDIO_MMDREG_CTRL1_LPOWER_LBN (11) +#define MDIO_MMDREG_CTRL1_LPOWER_WIDTH (1)/* Bits in MMDREG_STAT1 */ #define MDIO_MMDREG_STAT1_FAULT_LBN (7)
@@ -240,6 +243,10 @@ extern void mdio_clause45_transmit_disable(struct efx_nic *efx);/* Generic part of reconfigure: set/clear loopback bits */ extern void mdio_clause45_phy_reconfigure (struct efx_nic *efx); +/* Set the power state of the specified MMDs */ +extern void mdio_clause45_set_mmds_lpower (struct efx_nic *efx, +int low_power,unsigned int mmd_mask); +/* Read (some of) the PHY settings over MDIO */ extern void mdio_clause45_get_settings (struct efx_nic *efx,struct ethtool_cmd *ecmd);
drivers/net/sfc/net_driver.h +6 -0
@@ -414,6 +414,7 @@ struct efx_blinker {* @init_leds: Sets up board LEDs * @set_fault_led: Turns the fault LED on or off * @blink: Starts/stops blinking +* @monitor: Board-specific health check function * @fini: Cleanup function * @blinker: used to blink LEDs in software * @hwmon_client: I2C client for hardware monitor
@@ -428,6 +429,7 @@ struct efx_board {* have a separate init callback that happens later than * board init. */ int (*init_leds)(struct efx_nic *efx); +int (*monitor) (struct efx_nic *nic);void (*set_fault_led) (struct efx_nic *efx,bool state);void (*blink) (struct efx_nic *efx,bool start);void (*fini) (struct efx_nic *nic);
@@ -525,11 +527,15 @@ struct efx_phy_operations {* @enum efx_phy_mode - PHY operating mode flags * @PHY_MODE_NORMAL: on and should pass traffic * @PHY_MODE_TX_DISABLED: on with TX disabled +* @PHY_MODE_LOW_POWER: set to low power through MDIO +* @PHY_MODE_OFF: switched off through external control * @PHY_MODE_SPECIAL: on but will not pass traffic */ enum efx_phy_mode {PHY_MODE_NORMAL =0 ,PHY_MODE_TX_DISABLED =1 , +PHY_MODE_LOW_POWER =2 , +PHY_MODE_OFF =4 ,PHY_MODE_SPECIAL =8 , };
drivers/net/sfc/sfe4001.c +53 -63
174 lines not on this page · raw message
drivers/net/sfc/tenxpress.c +17 -1
@@ -376,6 +376,7 @@ static int tenxpress_phy_check_hw(struct efx_nic *efx) {struct tenxpress_phy_data *phy_data = efx->phy_data;bool link_ok; +int rc =0 ; link_ok =tenxpress_link_ok (efx, true);
@@ -391,7 +392,22 @@ static int tenxpress_phy_check_hw(struct efx_nic *efx)atomic_set (&phy_data->bad_crc_count,0 ); } -return 0 ; + rc = efx->board_info.monitor (efx); +if (rc) { +EFX_ERR (efx,"Board sensor %s; shutting down PHY\n" , + (rc == -ERANGE ) ?"reported fault" :"failed" ); +if (efx->phy_mode &PHY_MODE_OFF ) { +/* Assume that board has shut PHY off */ + phy_data->phy_mode =PHY_MODE_OFF ; + }else { + efx->phy_mode |=PHY_MODE_LOW_POWER ; +mdio_clause45_set_mmds_lpower (efx, true, + efx->phy_op->mmds); + phy_data->phy_mode |=PHY_MODE_LOW_POWER ; + } + } + +return rc; }static void tenxpress_phy_fini (struct efx_nic *efx)
drivers/net/sfc/workarounds.h +2 -0
@@ -22,6 +22,8 @@#define EFX_WORKAROUND_5147 EFX_WORKAROUND_ALWAYS/* RX PCIe double split performance issue */ #define EFX_WORKAROUND_7575 EFX_WORKAROUND_ALWAYS +/* Bit-bashed I2C reads cause performance drop */ +#define EFX_WORKAROUND_7884 EFX_WORKAROUND_ALWAYS/* TX pkt parser problem with <= 16 byte TXes */ #define EFX_WORKAROUND_9141 EFX_WORKAROUND_ALWAYS/* Low rate CRC errors require XAUI reset */
drivers/net/sfc/xfp_phy.c +9 -0
@@ -128,6 +128,15 @@ static int xfp_phy_check_hw(struct efx_nic *efx)if (link_up != efx->link_up)falcon_xmac_sim_phy_event (efx); + rc = efx->board_info.monitor (efx); +if (rc) { +struct xfp_phy_data *phy_data = efx->phy_data; +EFX_ERR (efx,"XFP sensor alert; putting PHY into low power\n" ); + efx->phy_mode |=PHY_MODE_LOW_POWER ; +mdio_clause45_set_mmds_lpower (efx,1 ,XFP_REQUIRED_DEVS ); + phy_data->phy_mode |=PHY_MODE_LOW_POWER ; + } +return rc; }
Signature · 3 lines
Ben Hutchings, Senior Software Engineer, Solarflare Communications Not speaking for my employer; that's the marketing department's job. They asked us to note that Solarflare product names are trademarked.
PATCH 5/6 sfc: Do not reset when hardware monitor detects a fault
In reply to Ben HutchingsThe TX watchdog should trigger a reset, but a temperature/power alarm should not as this is unlikely to solve the problem.
--- drivers/net/sfc/efx.c | 25 ++++--------------------- drivers/net/sfc/enum.h | 4 ++-- 2 files changed, 6 insertions(+), 23 deletions(-)
drivers/net/sfc/efx.c +4 -21
@@ -77,11 +77,6 @@ static int napi_weight = 64;*/ unsigned int efx_monitor_interval =1 *HZ ; -/* This controls whether or not the hardware monitor will trigger a -* reset when it detects an error condition. -*/ -static unsigned int monitor_reset = true; -/* This controls whether or not the driver will initialise devices * with invalid MAC addresses stored in the EEPROM or flash. If true, * such devices will be initialised with a random locally-generated
@@ -1176,17 +1171,6 @@ static void efx_monitor(struct work_struct *data) rc =falcon_check_xmac (efx);mutex_unlock (&efx->mac_lock); -if (rc) { -if (monitor_reset) { -EFX_ERR (efx,"hardware monitor detected a fault: " -"triggering reset\n" ); -efx_schedule_reset (efx,RESET_TYPE_MONITOR ); - }else { -EFX_ERR (efx,"hardware monitor detected a fault, " -"skipping reset\n" ); - } - } -queue_delayed_work (efx->workqueue, &efx->monitor_work, efx_monitor_interval); }
@@ -1358,12 +1342,11 @@ static void efx_watchdog(struct net_device *net_dev) {struct efx_nic *efx =netdev_priv (net_dev); -EFX_ERR (efx,"TX stuck with stop_count=%d port_enabled=%d: %s\n" , -atomic_read (&efx->netif_stop_count), efx->port_enabled, - monitor_reset ?"resetting channels" :"skipping reset" ); +EFX_ERR (efx,"TX stuck with stop_count=%d port_enabled=%d:" +" resetting channels\n" , +atomic_read (&efx->netif_stop_count), efx->port_enabled); -if (monitor_reset) -efx_schedule_reset (efx,RESET_TYPE_MONITOR ); +efx_schedule_reset (efx,RESET_TYPE_TX_WATCHDOG ); }
drivers/net/sfc/enum.h +2 -2
@@ -72,7 +72,7 @@ extern const char *efx_loopback_mode_names[];* @RESET_TYPE_ALL: reset everything but PCI core blocks * @RESET_TYPE_WORLD: reset everything, save & restore PCI config * @RESET_TYPE_DISABLE: disable NIC -* @RESET_TYPE_MONITOR: reset due to hardware monitor +* @RESET_TYPE_TX_WATCHDOG: reset due to TX watchdog * @RESET_TYPE_INT_ERROR: reset due to internal error * @RESET_TYPE_RX_RECOVERY: reset to recover from RX datapath errors * @RESET_TYPE_RX_DESC_FETCH: pcie error during rx descriptor fetch
@@ -86,7 +86,7 @@ enum reset_type {RESET_TYPE_WORLD =2 ,RESET_TYPE_DISABLE =3 ,RESET_TYPE_MAX_METHOD , -RESET_TYPE_MONITOR , +RESET_TYPE_TX_WATCHDOG ,RESET_TYPE_INT_ERROR ,RESET_TYPE_RX_RECOVERY , RESET_TYPE_RX_DESC_FETCH,
Signature · 3 lines
Ben Hutchings, Senior Software Engineer, Solarflare Communications Not speaking for my employer; that's the marketing department's job. They asked us to note that Solarflare product names are trademarked.
PATCH 6/6 sfc: Add driverlink API to support virtual NIC drivers
In reply to Ben HutchingsThe driverlink API allows other drivers to coordinate their access to the network controller with the sfc driver. These other drivers may create virtual NICs mapped into user processes or VM guests.
--- drivers/net/sfc/Makefile | 3 +- drivers/net/sfc/driverlink.c | 481 +++++++++++++++++++++++++++++++++++ drivers/net/sfc/driverlink.h | 70 +++++ drivers/net/sfc/driverlink_api.h | 516 ++++++++++++++++++++++++++++++++++++++ drivers/net/sfc/efx.c | 38 +++ drivers/net/sfc/falcon.c | 79 ++++++- drivers/net/sfc/net_driver.h | 15 ++ 7 files changed, 1196 insertions(+), 6 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 -1
@@ -1,6 +1,7 @@ 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 sfc-$(CONFIG_SFC_MTD) += mtd.o obj-$(CONFIG_SFC) += sfc.o
drivers/net/sfc/driverlink.c new file +481 -0
481 lines not on this page · raw message
drivers/net/sfc/driverlink.h new file +70 -0
70 lines not on this page · raw message
drivers/net/sfc/driverlink_api.h new file +516 -0
516 lines not on this page · raw message
drivers/net/sfc/efx.c +38 -0
@@ -1517,6 +1517,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 (); +}/* Tears down the entire software state and most of the hardware state * before reset. */
@@ -1592,6 +1609,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 ();
@@ -1634,6 +1655,8 @@ static int efx_reset(struct efx_nic *efx)EFX_LOG (efx,"reset complete\n" ); unlock_rtnl:rtnl_unlock (); +efx_dl_reset_resume (efx,1 ); +efx_dl_reset_unlock ();return 0 ; fail:
@@ -1645,6 +1668,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; }
@@ -1779,6 +1804,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 );
@@ -1900,6 +1928,9 @@ static void efx_pci_remove(struct pci_dev *pci_dev)efx_mtd_remove (efx); +/* 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 ;
@@ -2066,9 +2097,16 @@ 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; +efx_mtd_probe (efx);/* allowed to fail */ return 0 ; + fail6: +efx_unregister_netdev (efx); fail5:efx_pci_remove_main (efx); fail4:
drivers/net/sfc/falcon.c +74 -5
162 lines not on this page · raw message
drivers/net/sfc/net_driver.h +15 -0
@@ -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
@@ -701,6 +703,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.
@@ -783,6 +791,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 · 3 lines
Ben Hutchings, Senior Software Engineer, Solarflare Communications Not speaking for my employer; that's the marketing department's job. They asked us to note that Solarflare product names are trademarked.