diff --git a/MAINTAINERS b/MAINTAINERS index b6c3193b7362..8882132d9cbe 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -16242,6 +16242,13 @@ S: Maintained F: drivers/input/touchscreen/silead.c F: drivers/platform/x86/touchscreen_dmi.c +SILICOM PAC N5010 DRIVER +M: Esa Leskinen +L: netdev@vger.kernel.org +S: Maintained +F: drivers/net/ethernet/silicom/n5010-hssi.c +F: drivers/net/ethernet/silicom/n5010-phy.c + SILICON LABS WIRELESS DRIVERS (for WFxxx series) M: Jérôme Pouiller S: Supported diff --git a/configs/n5010_defconfig b/configs/n5010_defconfig new file mode 100644 index 000000000000..55f4853399c6 --- /dev/null +++ b/configs/n5010_defconfig @@ -0,0 +1,33 @@ +CONFIG_FPGA_DFL=m +CONFIG_FPGA_DFL_FME=m +CONFIG_FPGA_DFL_FME_MGR=m +CONFIG_FPGA_DFL_FME_BRIDGE=m +CONFIG_FPGA_DFL_FME_REGION=m +CONFIG_FPGA_DFL_AFU=m +CONFIG_FPGA_DFL_SPI_ALTERA=m +CONFIG_FPGA_DFL_PCI=m + +CONFIG_FPGA_VFIO_MDEV_DFL=m + +CONFIG_FPGA=m +CONFIG_FPGA_MGR=m +CONFIG_FPGA_BRIDGE=m +CONFIG_FPGA_REGION=m +CONFIG_FPGA_SEC_MGR=m +CONFIG_IFPGA_M10_BMC_SECURE=m + +CONFIG_SPI=y +CONFIG_SPI_MASTER=y +CONFIG_MFD_INTEL_M10_BMC=m +CONFIG_SENSORS_INTEL_M10_BMC_HWMON=m + +CONFIG_SPI_ALTERA=m + +CONFIG_FIXED_PHY=m +CONFIG_NET_VENDOR_SILICOM=y +CONFIG_N5010_HSSI=m +CONFIG_n5010_PHY=m + +CONFIG_REGMAP_MMIO=m +CONFIG_REGMAP_INDIRECT_REGISTER=m +CONFIG_REGMAP_SPI_AVMM=m diff --git a/drivers/fpga/dfl-pci.c b/drivers/fpga/dfl-pci.c index d844bebb4cd4..6813eb83f1dc 100644 --- a/drivers/fpga/dfl-pci.c +++ b/drivers/fpga/dfl-pci.c @@ -67,6 +67,8 @@ static void cci_pci_free_irq(struct pci_dev *pcidev) #define PCIE_DEVICE_ID_INTEL_PAC_N3000 0x0B30 #define PCIE_DEVICE_ID_INTEL_PAC_D5005 0x0B2B #define PCIE_DEVCIE_ID_INTEL_OFS 0xaf00 +#define PCIE_DEVICE_ID_SILICOM_PAC_N5010 0x1000 + /* VF Device */ #define PCIE_DEVICE_ID_VF_INT_5_X 0xBCBF #define PCIE_DEVICE_ID_VF_INT_6_X 0xBCC1 @@ -84,6 +86,7 @@ static struct pci_device_id cci_pcie_id_tbl[] = { {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_PAC_D5005),}, {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_PAC_D5005_VF),}, {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVCIE_ID_INTEL_OFS),}, + {PCI_DEVICE(PCI_VENDOR_ID_SILICOM_DENMARK, PCIE_DEVICE_ID_SILICOM_PAC_N5010),}, {0,} }; MODULE_DEVICE_TABLE(pci, cci_pcie_id_tbl); diff --git a/drivers/fpga/dfl-spi-altera.c b/drivers/fpga/dfl-spi-altera.c index 8ddfc5d5e2ba..50a3d0ef4771 100644 --- a/drivers/fpga/dfl-spi-altera.c +++ b/drivers/fpga/dfl-spi-altera.c @@ -22,6 +22,11 @@ #include #include +#include "dfl.h" + +#define FME_FEATURE_ID_MAX10_SPI 0xe +#define FME_FEATURE_REV_MAX10_SPI_N5010 0x1 + struct dfl_altera_spi { void __iomem *base; struct regmap *regmap; @@ -117,6 +122,13 @@ static struct spi_board_info m10_bmc_info = { .chip_select = 0, }; +static struct spi_board_info m10_n5010_bmc_info = { + .modalias = "m10-n5010", + .max_speed_hz = 12500000, + .bus_num = 0, + .chip_select = 0, +}; + static struct platform_device *create_cntrl(struct device *dev, void __iomem *base, struct spi_board_info *m10_info) @@ -180,7 +192,10 @@ static int dfl_spi_altera_probe(struct dfl_device *dfl_dev) if (IS_ERR(aspi->regmap)) return PTR_ERR(aspi->regmap); - aspi->altr_spi = create_cntrl(dev, aspi->base, &m10_bmc_info); + if (dfl_feature_revision(aspi->base) == FME_FEATURE_REV_MAX10_SPI_N5010) + aspi->altr_spi = create_cntrl(dev, aspi->base, &m10_n5010_bmc_info); + else + aspi->altr_spi = create_cntrl(dev, aspi->base, &m10_bmc_info); if (IS_ERR(aspi->altr_spi)) { dev_err(dev, "%s failed to create spi platform driver\n", @@ -198,8 +213,6 @@ static void dfl_spi_altera_remove(struct dfl_device *dfl_dev) platform_device_unregister(aspi->altr_spi); } -#define FME_FEATURE_ID_MAX10_SPI 0xe - static const struct dfl_device_id dfl_spi_altera_ids[] = { { FME_ID, FME_FEATURE_ID_MAX10_SPI }, { } diff --git a/drivers/fpga/dfl.c b/drivers/fpga/dfl.c index 79ee44a7e7b6..e21004565990 100644 --- a/drivers/fpga/dfl.c +++ b/drivers/fpga/dfl.c @@ -487,6 +487,15 @@ EXPORT_SYMBOL(dfl_driver_unregister); #define is_header_feature(feature) ((feature)->id == FEATURE_ID_FIU_HEADER) +struct device *dfl_dev_get_base_dev(struct dfl_device *dfl_dev) +{ + if (!dfl_dev || !dfl_dev->cdev) + return NULL; + + return dfl_dev->cdev->parent; +} +EXPORT_SYMBOL(dfl_dev_get_base_dev); + /** * dfl_fpga_dev_feature_uinit - uinit for sub features of dfl feature device * @pdev: feature device. diff --git a/drivers/fpga/intel-m10-bmc-secure.c b/drivers/fpga/intel-m10-bmc-secure.c index aaa581eccd3e..832c4efc15a6 100644 --- a/drivers/fpga/intel-m10-bmc-secure.c +++ b/drivers/fpga/intel-m10-bmc-secure.c @@ -792,6 +792,10 @@ static const struct platform_device_id intel_m10bmc_secure_ids[] = { .name = "d5005bmc-secure", .driver_data = (unsigned long)M10_D5005, }, + { + .name = "n5010bmc-secure", + .driver_data = (unsigned long)M10_N5010, + }, { } }; diff --git a/drivers/hwmon/intel-m10-bmc-hwmon.c b/drivers/hwmon/intel-m10-bmc-hwmon.c index bd7ed2ed3a1e..7a08e4c44a4b 100644 --- a/drivers/hwmon/intel-m10-bmc-hwmon.c +++ b/drivers/hwmon/intel-m10-bmc-hwmon.c @@ -228,6 +228,118 @@ static const struct m10bmc_hwmon_board_data d5005bmc_hwmon_bdata = { .hinfo = d5005bmc_hinfo, }; +static const struct m10bmc_sdata n5010bmc_temp_tbl[] = { + { 0x100, 0x0, 0x104, 0x0, 0x0, 1000, "Board Local Temperature" }, + { 0x108, 0x0, 0x10c, 0x0, 0x0, 1000, "FPGA 1 Temperature" }, + { 0x110, 0x0, 0x114, 0x0, 0x0, 1000, "FPGA 2 Temperature" }, + { 0x118, 0x0, 0x0, 0x0, 0x0, 1000, "Card Top Temperature" }, + { 0x11c, 0x0, 0x0, 0x0, 0x0, 1000, "Card Bottom Temperature" }, + { 0x128, 0x0, 0x0, 0x0, 0x0, 1000, "FPGA 1.2V Temperature" }, + { 0x134, 0x0, 0x0, 0x0, 0x0, 1000, "FPGA 5V Temperature" }, + { 0x140, 0x0, 0x0, 0x0, 0x0, 1000, "FPGA 0.9V Temperature" }, + { 0x14c, 0x0, 0x0, 0x0, 0x0, 1000, "FPGA 0.85V Temperature" }, + { 0x158, 0x0, 0x0, 0x0, 0x0, 1000, "AUX 12V Temperature" }, + { 0x164, 0x0, 0x0, 0x0, 0x0, 1000, "Backplane 12V Temperature" }, + { 0x1a8, 0x0, 0x0, 0x0, 0x0, 1000, "QSFP28-1 Temperature" }, + { 0x1ac, 0x0, 0x0, 0x0, 0x0, 1000, "QSFP28-2 Temperature" }, + { 0x1b0, 0x0, 0x0, 0x0, 0x0, 1000, "QSFP28-3 Temperature" }, + { 0x1b4, 0x0, 0x0, 0x0, 0x0, 1000, "QSFP28-4 Temperature" }, + { 0x1b8, 0x0, 0x0, 0x0, 0x0, 1000, "CVL1 Internal Temperature" }, + { 0x1bc, 0x0, 0x0, 0x0, 0x0, 1000, "CVL2 Internal Temperature" }, +}; + +static const struct m10bmc_sdata n5010bmc_in_tbl[] = { + { 0x120, 0x0, 0x0, 0x0, 0x0, 1, "FPGA 1.2V Voltage" }, + { 0x12c, 0x0, 0x0, 0x0, 0x0, 1, "FPGA 5V Voltage" }, + { 0x138, 0x0, 0x0, 0x0, 0x0, 1, "FPGA 0.9V Voltage" }, + { 0x144, 0x0, 0x0, 0x0, 0x0, 1, "FPGA 0.85V Voltage" }, + { 0x150, 0x0, 0x0, 0x0, 0x0, 1, "AUX 12V Voltage" }, + { 0x15c, 0x0, 0x0, 0x0, 0x0, 1, "Backplane 12V Voltage" }, + { 0x16c, 0x0, 0x0, 0x0, 0x0, 1, "DDR4 1.2V Voltage" }, + { 0x17c, 0x0, 0x0, 0x0, 0x0, 1, "FPGA 1.8V Voltage" }, + { 0x184, 0x0, 0x0, 0x0, 0x0, 1, "QDR 1.3V Voltage" }, + { 0x18c, 0x0, 0x0, 0x0, 0x0, 1, "CVL1 0.8V Voltage" }, + { 0x194, 0x0, 0x0, 0x0, 0x0, 1, "CVL1 1.05V Voltage" }, + { 0x19c, 0x0, 0x0, 0x0, 0x0, 1, "CVL2 1.05V Voltage" }, + { 0x1a4, 0x0, 0x0, 0x0, 0x0, 1, "CVL2 0.8V Voltage" }, +}; + +static const struct m10bmc_sdata n5010bmc_curr_tbl[] = { + { 0x124, 0x0, 0x0, 0x0, 0x0, 1, "FPGA 1.2V Current" }, + { 0x130, 0x0, 0x0, 0x0, 0x0, 1, "FPGA 5V Current" }, + { 0x13c, 0x0, 0x0, 0x0, 0x0, 1, "FPGA 0.9V Current" }, + { 0x148, 0x0, 0x0, 0x0, 0x0, 1, "FPGA 0.85V Current" }, + { 0x154, 0x0, 0x0, 0x0, 0x0, 1, "AUX 12V Current" }, + { 0x160, 0x0, 0x0, 0x0, 0x0, 1, "Backplane 12V Current" }, + { 0x168, 0x0, 0x0, 0x0, 0x0, 1, "DDR4 1.2V Current" }, + { 0x178, 0x0, 0x0, 0x0, 0x0, 1, "FPGA 1.8V Current" }, + { 0x180, 0x0, 0x0, 0x0, 0x0, 1, "QDR 1.3V Current" }, + { 0x188, 0x0, 0x0, 0x0, 0x0, 1, "CVL1 0.8V Current" }, + { 0x190, 0x0, 0x0, 0x0, 0x0, 1, "CVL1 1.05V Current" }, + { 0x198, 0x0, 0x0, 0x0, 0x0, 1, "CVL2 1.05V Current" }, + { 0x1a0, 0x0, 0x0, 0x0, 0x0, 1, "CVL2 0.8V Current" }, +}; + +static const struct hwmon_channel_info *n5010bmc_hinfo[] = { + HWMON_CHANNEL_INFO(temp, + HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL), + HWMON_CHANNEL_INFO(in, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL), + HWMON_CHANNEL_INFO(curr, + HWMON_C_INPUT | HWMON_C_LABEL, + HWMON_C_INPUT | HWMON_C_LABEL, + HWMON_C_INPUT | HWMON_C_LABEL, + HWMON_C_INPUT | HWMON_C_LABEL, + HWMON_C_INPUT | HWMON_C_LABEL, + HWMON_C_INPUT | HWMON_C_LABEL, + HWMON_C_INPUT | HWMON_C_LABEL, + HWMON_C_INPUT | HWMON_C_LABEL, + HWMON_C_INPUT | HWMON_C_LABEL, + HWMON_C_INPUT | HWMON_C_LABEL, + HWMON_C_INPUT | HWMON_C_LABEL, + HWMON_C_INPUT | HWMON_C_LABEL, + HWMON_C_INPUT | HWMON_C_LABEL), + NULL +}; + +static const struct m10bmc_hwmon_board_data n5010bmc_hwmon_bdata = { + .tables = { + [hwmon_temp] = n5010bmc_temp_tbl, + [hwmon_in] = n5010bmc_in_tbl, + [hwmon_curr] = n5010bmc_curr_tbl, + }, + + .hinfo = n5010bmc_hinfo, +}; + static umode_t m10bmc_hwmon_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr, int channel) @@ -438,6 +550,10 @@ static const struct platform_device_id intel_m10bmc_hwmon_ids[] = { .name = "d5005bmc-hwmon", .driver_data = (unsigned long)&d5005bmc_hwmon_bdata, }, + { + .name = "n5010bmc-hwmon", + .driver_data = (unsigned long)&n5010bmc_hwmon_bdata, + }, { } }; diff --git a/drivers/mfd/intel-m10-bmc.c b/drivers/mfd/intel-m10-bmc.c index fbea467b8fdb..bace35ab6064 100644 --- a/drivers/mfd/intel-m10-bmc.c +++ b/drivers/mfd/intel-m10-bmc.c @@ -41,6 +41,12 @@ static struct mfd_cell m10bmc_pacn3000_subdevs[] = { { .name = "n3000bmc-secure" }, }; +static struct mfd_cell m10bmc_n5010_bmc_subdevs[] = { + { .name = "n5010bmc-hwmon" }, + { .name = "n5010bmc-secure" }, + { .name = "n5010bmc-phy" }, +}; + static const struct regmap_range n3000_fw_handshake_regs[] = { regmap_reg_range(M10BMC_TELEM_START, M10BMC_TELEM_END), }; @@ -293,6 +299,10 @@ static int intel_m10_bmc_spi_probe(struct spi_device *spi) cells = m10bmc_bmc_subdevs; n_cell = ARRAY_SIZE(m10bmc_bmc_subdevs); break; + case M10_N5010: + cells = m10bmc_n5010_bmc_subdevs; + n_cell = ARRAY_SIZE(m10bmc_n5010_bmc_subdevs); + break; default: return -ENODEV; } @@ -308,6 +318,7 @@ static int intel_m10_bmc_spi_probe(struct spi_device *spi) static const struct spi_device_id m10bmc_spi_id[] = { { "m10-n3000", M10_N3000 }, { "m10-d5005", M10_D5005 }, + { "m10-n5010", M10_N5010 }, { } }; MODULE_DEVICE_TABLE(spi, m10bmc_spi_id); diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig index de50e8b9e656..e8204ff04500 100644 --- a/drivers/net/ethernet/Kconfig +++ b/drivers/net/ethernet/Kconfig @@ -167,6 +167,7 @@ source "drivers/net/ethernet/seeq/Kconfig" source "drivers/net/ethernet/sfc/Kconfig" source "drivers/net/ethernet/sgi/Kconfig" source "drivers/net/ethernet/silan/Kconfig" +source "drivers/net/ethernet/silicom/Kconfig" source "drivers/net/ethernet/sis/Kconfig" source "drivers/net/ethernet/smsc/Kconfig" source "drivers/net/ethernet/socionext/Kconfig" diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile index f8f38dcb5f8a..d6f889f89dbe 100644 --- a/drivers/net/ethernet/Makefile +++ b/drivers/net/ethernet/Makefile @@ -78,6 +78,7 @@ obj-$(CONFIG_NET_VENDOR_ROCKER) += rocker/ obj-$(CONFIG_NET_VENDOR_SAMSUNG) += samsung/ obj-$(CONFIG_NET_VENDOR_SEEQ) += seeq/ obj-$(CONFIG_NET_VENDOR_SILAN) += silan/ +obj-$(CONFIG_NET_VENDOR_SILICOM) += silicom/ obj-$(CONFIG_NET_VENDOR_SIS) += sis/ obj-$(CONFIG_NET_VENDOR_SOLARFLARE) += sfc/ obj-$(CONFIG_NET_VENDOR_SGI) += sgi/ diff --git a/drivers/net/ethernet/silicom/Kconfig b/drivers/net/ethernet/silicom/Kconfig new file mode 100644 index 000000000000..2366418f5f25 --- /dev/null +++ b/drivers/net/ethernet/silicom/Kconfig @@ -0,0 +1,37 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Silicom network device configuration +# + +config NET_VENDOR_SILICOM + bool "Silicom devices" + default y + help + If you have a network (Ethernet) card belonging to this class, say Y. + + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause the configurator to skip all + the questions about Silicom cards. If you say Y, you will be asked for + your specific card in the following questions. + +if NET_VENDOR_SILICOM + +config N5010_PHY + tristate "Fixed Phy Driver for Silicom PAC N5010" + depends on MFD_INTEL_M10_BMC && FIXED_PHY + help + The n5010 card consists of a primary FPGA running the network controller, + and a side-fpga running the board management controller (bmc). This driver + reads status bits and controls link LEDs via the bmc. + +config N5010_HSSI + tristate "Control Plane Driver for Silicom PAC N5010 HSSI" + select N5010_PHY + select REGMAP_INDIRECT_REGISTER + help + This driver provides control plane support for the Silicom N5010 + Programmable Acceleration Card. This driver adds network interfaces + for the line-side QFSP modules, supporting various control/status + operations. + +endif # NET_VENDOR_SILICOM diff --git a/drivers/net/ethernet/silicom/Makefile b/drivers/net/ethernet/silicom/Makefile new file mode 100644 index 000000000000..e613043ae1c1 --- /dev/null +++ b/drivers/net/ethernet/silicom/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for the Silicom network device drivers. +# + +obj-$(CONFIG_N5010_PHY) += n5010-phy.o +obj-$(CONFIG_N5010_HSSI) += n5010-hssi.o diff --git a/drivers/net/ethernet/silicom/n5010-hssi.c b/drivers/net/ethernet/silicom/n5010-hssi.c new file mode 100644 index 000000000000..22bfb3d1fd18 --- /dev/null +++ b/drivers/net/ethernet/silicom/n5010-hssi.c @@ -0,0 +1,600 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* Silicom(R) Low Latency 100G Network Driver + * + * Copyright (C) 2020 Silicom Denmark. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "n5010-phy.h" + +#define CAPABILITY_OFFSET 0x08 +#define CAP_AVAILABLE_RATES GENMASK_ULL(7, 0) +#define CAP_CONTAINS_PCS GENMASK_ULL(15, 8) +#define CAP_CONTAINS_FEC GENMASK_ULL(23, 16) +#define CAP_PORT_CNT GENMASK_ULL(43, 40) +#define CAP_RATE_1G BIT_ULL(0) +#define CAP_RATE_10G BIT_ULL(1) +#define CAP_RATE_25G BIT_ULL(2) +#define CAP_RATE_40G BIT_ULL(3) +#define CAP_RATE_50G BIT_ULL(4) +#define CAP_RATE_100G BIT_ULL(5) +#define CAP_RATE_200G BIT_ULL(6) +#define CAP_RATE_400G BIT_ULL(7) + +#define MB_MAC_OFFSET 0x28 +#define MB_FEC_OFFSET 0x68 +#define MB_PHY_OFFSET 0xa8 +#define MB_PORT_SIZE 0x10 + +#define PHY_BASE_OFF 0x2000 +#define PHY_RX_SER_LOOP_BACK 0x4e1 + +#define FEC_RX_STATUS 0x180 +#define FEC_RX_STATUS_LINK 0x0ULL +#define FEC_RX_STATUS_LINK_NO 0x3ULL + +#define MAC_TX_SRC_ADDR_LO 0x40c +#define MAC_TX_SRC_ADDR_HI 0x40d +#define MAC_RX_MTU 0x506 +#define MAC_MAX_MTU 9600 + +#define ILL_100G_TX_STATS_CLR 0x845 +#define ILL_100G_RX_STATS_CLR 0x945 +#define ILL_100G_LPBK_OFF 0x313 +#define ILL_100G_LPBK_EN_VAL 0xffff + +#define STATS_CLR_INT_US 1 +#define STATS_CLR_INT_TIMEOUT_US 1000 + +struct n5010_hssi_ops_params { + struct stat_info *stats; + u32 num_stats; + u32 tx_clr_off; + u32 rx_clr_off; +}; + +struct n5010_hssi_regmaps { + struct regmap *regmap; +}; + +struct n5010_hssi_netdata { + struct dfl_device *dfl_dev; + struct regmap *regmap_mac; + struct regmap *regmap_fec; + struct regmap *regmap_phy; + u32 link_status; + const struct n5010_hssi_ops_params *ops_params; +}; + +struct n5010_hssi_drvdata { + struct dfl_device *dfl_dev; + void __iomem *base; + u64 port_cnt; + struct net_device *netdev[]; +}; + +static bool n5010_hssi_update_link(struct net_device *netdev) +{ + struct n5010_hssi_netdata *npriv = netdev_priv(netdev); + u32 link_status = FEC_RX_STATUS_LINK_NO; + + regmap_read(npriv->regmap_fec, FEC_RX_STATUS, &link_status); + + return link_status == FEC_RX_STATUS_LINK; +} + +static int netdev_open(struct net_device *netdev) +{ + if (netdev->phydev) + phy_start(netdev->phydev); + + return 0; +} + +static int netdev_stop(struct net_device *netdev) +{ + if (netdev->phydev) + phy_stop(netdev->phydev); + + return 0; +} + +static int netdev_change_mtu(struct net_device *netdev, int new_mtu) +{ + struct n5010_hssi_netdata *npriv = netdev_priv(netdev); + + netdev->mtu = new_mtu; + + return regmap_write(npriv->regmap_mac, MAC_RX_MTU, new_mtu); +} + +static int netdev_set_features(struct net_device *netdev, + netdev_features_t features) +{ + return 0; +} + +static int netdev_set_mac_address(struct net_device *netdev, void *p) +{ + struct n5010_hssi_netdata *npriv = netdev_priv(netdev); + struct sockaddr *addr = p; + u32 mac_part1, mac_part2; + int ret; + + memcpy(netdev->dev_addr, addr->sa_data, ETH_ALEN); + + mac_part1 = (addr->sa_data[0] << 8) | addr->sa_data[1]; + mac_part2 = (addr->sa_data[2] << 24) | (addr->sa_data[3] << 16) | + (addr->sa_data[4] << 8) | addr->sa_data[5]; + + ret = regmap_write(npriv->regmap_mac, MAC_TX_SRC_ADDR_HI, mac_part1); + if (ret) + return ret; + + return regmap_write(npriv->regmap_mac, MAC_TX_SRC_ADDR_LO, mac_part2); +} + +static const struct net_device_ops netdev_ops = { + .ndo_open = netdev_open, + .ndo_stop = netdev_stop, + .ndo_change_mtu = netdev_change_mtu, + .ndo_set_features = netdev_set_features, + .ndo_set_mac_address = netdev_set_mac_address, +}; + +struct stat_info { + unsigned int addr; + char string[ETH_GSTRING_LEN]; +}; + +#define STAT_INFO(_addr, _string) \ + .addr = _addr, .string = _string, + +static void ethtool_get_strings(struct net_device *netdev, u32 stringset, + u8 *s) +{ + struct n5010_hssi_netdata *npriv = netdev_priv(netdev); + unsigned int i, stats_num = 0; + struct stat_info *stat; + + if (stringset != ETH_SS_STATS) + return; + + stat = npriv->ops_params->stats; + stats_num = npriv->ops_params->num_stats; + + for (i = 0; i < stats_num; i++, s += ETH_GSTRING_LEN) + memcpy(s, stat[i].string, ETH_GSTRING_LEN); +} + +static int ethtool_get_sset_count(struct net_device *netdev, int stringset) +{ + struct n5010_hssi_netdata *npriv = netdev_priv(netdev); + + if (stringset == ETH_SS_STATS) + return npriv->ops_params->num_stats; + + return 0; +} + +static u64 read_mac_stat(struct regmap *regmap, unsigned int addr) +{ + u32 data_l, data_h; + + regmap_read(regmap, addr, &data_l); + regmap_read(regmap, addr + 1, &data_h); + + return data_l + ((u64)data_h << 32); +} + +static int ethtool_reset(struct net_device *netdev, u32 *flags) +{ + struct n5010_hssi_netdata *npriv = netdev_priv(netdev); + struct regmap *regmap = npriv->regmap_mac; + u32 reg, val; + int ret; + + if (*flags | ETH_RESET_MGMT) { + reg = npriv->ops_params->tx_clr_off; + + ret = regmap_write(regmap, reg, 1); + if (ret) + return ret; + + ret = regmap_write(regmap, reg, 0); + if (ret) + return ret; + + ret = regmap_read_poll_timeout(regmap, reg, val, (val & 1) == 0, + STATS_CLR_INT_US, + STATS_CLR_INT_TIMEOUT_US); + if (ret) { + dev_err(&netdev->dev, "failed to clear tx stats\n"); + return ret; + } + + reg = npriv->ops_params->rx_clr_off; + + ret = regmap_write(regmap, reg, 1); + if (ret) + return ret; + + ret = regmap_write(regmap, reg, 0); + if (ret) + return ret; + + ret = regmap_read_poll_timeout(regmap, reg, val, (val & 1) == 0, + STATS_CLR_INT_US, + STATS_CLR_INT_TIMEOUT_US); + if (ret) { + dev_err(&netdev->dev, "failed to clear rx stats\n"); + return ret; + } + } + + return 0; +} + +static void ethtool_get_stats(struct net_device *netdev, + struct ethtool_stats *stats, u64 *data) +{ + struct n5010_hssi_netdata *npriv = netdev_priv(netdev); + unsigned int i, stats_num = npriv->ops_params->num_stats; + struct stat_info *stat = npriv->ops_params->stats; + + for (i = 0; i < stats_num; i++) + data[i] = read_mac_stat(npriv->regmap_mac, stat[i].addr); +} + +static int ethtool_module_info(struct net_device *netdev, + struct ethtool_modinfo *modinfo) +{ + return n5010_phy_module_info(netdev); +} + +static const struct ethtool_ops ethtool_ops = { + .get_strings = ethtool_get_strings, + .get_sset_count = ethtool_get_sset_count, + .get_ethtool_stats = ethtool_get_stats, + .get_link = ethtool_op_get_link, + .get_module_info = ethtool_module_info, + .reset = ethtool_reset, +}; + +static struct stat_info stats_100g[] = { + /* tx statistics */ + {STAT_INFO(0x800, "tx_fragments")}, + {STAT_INFO(0x802, "tx_jabbers")}, + {STAT_INFO(0x804, "tx_crcerr")}, + {STAT_INFO(0x806, "tx_crcerr_sizeok")}, + {STAT_INFO(0x808, "tx_mcast_data_err")}, + {STAT_INFO(0x80a, "tx_bcast_data_err")}, + {STAT_INFO(0x80c, "tx_ucast_data_err")}, + {STAT_INFO(0x80e, "tx_mcast_ctrl_err")}, + {STAT_INFO(0x810, "tx_bcast_ctrl_err")}, + {STAT_INFO(0x812, "tx_ucast_ctrl_err")}, + {STAT_INFO(0x814, "tx_pause_err")}, + {STAT_INFO(0x816, "tx_64b")}, + {STAT_INFO(0x818, "tx_65to127b")}, + {STAT_INFO(0x81a, "tx_128to255b")}, + {STAT_INFO(0x81c, "tx_256to511b")}, + {STAT_INFO(0x81e, "tx_512to1023b")}, + {STAT_INFO(0x820, "tx_1024to1518b")}, + {STAT_INFO(0x822, "tx_1519tomaxb")}, + {STAT_INFO(0x824, "tx_oversize")}, + {STAT_INFO(0x836, "tx_st")}, + {STAT_INFO(0x826, "tx_mcast_data_ok")}, + {STAT_INFO(0x828, "tx_bcast_data_ok")}, + {STAT_INFO(0x82a, "tx_ucast_data_ok")}, + {STAT_INFO(0x82c, "tx_mcast_ctrl_ok")}, + {STAT_INFO(0x82e, "tx_bcast_ctrl_ok")}, + {STAT_INFO(0x830, "tx_ucast_ctrl_ok")}, + {STAT_INFO(0x832, "tx_pause")}, + {STAT_INFO(0x860, "tx_payload_octets_ok")}, + {STAT_INFO(0x862, "tx_frame_octets_ok")}, + + /* rx statistics */ + {STAT_INFO(0x900, "rx_fragments")}, + {STAT_INFO(0x902, "rx_jabbers")}, + {STAT_INFO(0x904, "rx_crcerr")}, + {STAT_INFO(0x906, "rx_crcerr_sizeok")}, + {STAT_INFO(0x908, "rx_mcast_data_err")}, + {STAT_INFO(0x90a, "rx_bcast_data_err")}, + {STAT_INFO(0x90c, "rx_ucast_data_err")}, + {STAT_INFO(0x90e, "rx_mcast_ctrl_err")}, + {STAT_INFO(0x910, "rx_bcast_ctrl_err")}, + {STAT_INFO(0x912, "rx_ucast_ctrl_err")}, + {STAT_INFO(0x914, "rx_pause_err")}, + {STAT_INFO(0x916, "rx_64b")}, + {STAT_INFO(0x918, "rx_65to127b")}, + {STAT_INFO(0x91a, "rx_128to255b")}, + {STAT_INFO(0x91c, "rx_256to511b")}, + {STAT_INFO(0x91e, "rx_512to1023b")}, + {STAT_INFO(0x920, "rx_1024to1518b")}, + {STAT_INFO(0x922, "rx_1519tomaxb")}, + {STAT_INFO(0x924, "rx_oversize")}, + {STAT_INFO(0x936, "rx_st")}, + {STAT_INFO(0x926, "rx_mcast_data_ok")}, + {STAT_INFO(0x928, "rx_bcast_data_ok")}, + {STAT_INFO(0x92a, "rx_ucast_data_ok")}, + {STAT_INFO(0x92c, "rx_mcast_ctrl_ok")}, + {STAT_INFO(0x92e, "rx_bcast_ctrl_ok")}, + {STAT_INFO(0x930, "rx_ucast_ctrl_ok")}, + {STAT_INFO(0x932, "rx_pause")}, + {STAT_INFO(0x960, "rx_payload_octets_ok")}, + {STAT_INFO(0x962, "rx_frame_octets_ok")}, +}; + +static const struct n5010_hssi_ops_params n5010_100g_params = { + .stats = stats_100g, + .num_stats = ARRAY_SIZE(stats_100g), + .tx_clr_off = ILL_100G_TX_STATS_CLR, + .rx_clr_off = ILL_100G_RX_STATS_CLR, +}; + +static void n5010_hssi_init_netdev(struct net_device *netdev) +{ + netdev->ethtool_ops = ðtool_ops; + netdev->netdev_ops = &netdev_ops; + netdev->features = 0; + netdev->hard_header_len = 0; + netdev->priv_flags |= IFF_NO_QUEUE; + netdev->max_mtu = MAC_MAX_MTU; + netdev->needs_free_netdev = true; + + ether_setup(netdev); +} + +enum n5010_hssi_regmap { + regmap_mac, + regmap_fec, + regmap_phy, +}; + +#ifndef devm_regmap_init_indirect_register +struct regmap *devm_regmap_init_indirect_register(struct device *dev, + void __iomem *base, + struct regmap_config *cfg); +#endif + +static struct regmap *n5010_hssi_create_regmap(struct n5010_hssi_drvdata *priv, + u64 port, + enum n5010_hssi_regmap type) +{ + void __iomem *base = priv->base + port * MB_PORT_SIZE; + struct device *dev = &priv->dfl_dev->dev; + struct regmap_config cfg = {0}; + char regmap_name[20]; + + switch (type) { + case regmap_mac: + sprintf(regmap_name, "n5010_hssi_mac%llu", port); + base += MB_MAC_OFFSET; + cfg.val_bits = 32; + cfg.max_register = 0xbbf; + break; + case regmap_fec: + sprintf(regmap_name, "n5010_hssi_fec%llu", port); + base += MB_FEC_OFFSET; + cfg.val_bits = 8; + cfg.max_register = 0x29c; + break; + case regmap_phy: + sprintf(regmap_name, "n5010_hssi_phy%llu", port); + base += MB_PHY_OFFSET; + cfg.val_bits = 8; + cfg.max_register = 0x40144; + break; + } + + cfg.name = regmap_name; + cfg.reg_bits = 32; + + return devm_regmap_init_indirect_register(dev, base, &cfg); +} + +static int n5010_hssi_create_netdev(struct n5010_hssi_drvdata *priv, + struct device *phy, u64 port) +{ + struct device *dev = &priv->dfl_dev->dev; + struct n5010_hssi_netdata *npriv; + struct net_device *netdev; + int err = -ENOMEM; + u32 flags; + + netdev = alloc_netdev(sizeof(struct n5010_hssi_netdata), + "n5010_hssi%d", NET_NAME_UNKNOWN, + n5010_hssi_init_netdev); + priv->netdev[port] = netdev; + + if (!netdev) + return -ENOMEM; + + npriv = netdev_priv(netdev); + + npriv->dfl_dev = priv->dfl_dev; + + npriv->regmap_mac = n5010_hssi_create_regmap(priv, port, regmap_mac); + if (!npriv->regmap_mac) + goto err_unreg_netdev; + + npriv->regmap_fec = n5010_hssi_create_regmap(priv, port, regmap_fec); + if (!npriv->regmap_fec) + goto err_unreg_netdev; + + npriv->regmap_phy = n5010_hssi_create_regmap(priv, port, regmap_phy); + if (!npriv->regmap_phy) + goto err_unreg_netdev; + + npriv->ops_params = &n5010_100g_params; + + SET_NETDEV_DEV(netdev, dev); + + flags = ETH_RESET_MGMT; + + npriv->link_status = FEC_RX_STATUS_LINK_NO; + + err = ethtool_reset(netdev, &flags); + if (err) { + dev_err(dev, "failed to reset MGMT %s: %d", netdev->name, err); + goto err_unreg_netdev; + } + + err = register_netdev(netdev); + if (err) { + dev_err(dev, "failed to register %s: %d", netdev->name, err); + goto err_unreg_netdev; + } + + err = n5010_phy_attach(phy, netdev, n5010_hssi_update_link, port); + if (err) + goto err_unreg_netdev; + + return 0; + +err_unreg_netdev: + unregister_netdev(netdev); + + return err; +} + +static int n5010_match_phy_dev(struct device *dev, void *data) +{ + return dev->driver && !strcmp(dev->driver->name, "n5010bmc-phy"); +} + +static int n5010_match_phy_master(struct device *dev, const void *data) +{ + struct dfl_device *dfl_dev = (void *)data; + struct device *base_dev = dfl_dev_get_base_dev(dfl_dev); + + /* look trace device tree until a direct dfl-device is found */ + do { + if (!dev->bus) + continue; + + if (!strcmp(dev->bus->name, "dfl")) + break; + + if (!dev->parent) + return 0; + } while ((dev = dev->parent)); + + if (!dev) + return 0; + + /* compare the base (pci) device of the spi controller with the base + * (pci) device of the n5010-hssi device + */ + return dfl_dev_get_base_dev(to_dfl_dev(dev)) == base_dev; +} + +static int n5010_hssi_probe(struct dfl_device *dfl_dev) +{ + struct device *phy_master, *phy_dev; + struct device *dev = &dfl_dev->dev; + struct n5010_hssi_drvdata *priv; + u64 val, port_cnt, port; + void __iomem *base; + u64 priv_size; + int ret = 0; + + /* find the spi controller from this pci device */ + phy_master = bus_find_device(&spi_bus_type, NULL, dfl_dev, + n5010_match_phy_master); + if (!phy_master) { + dev_info(dev, "phy master not found; deferring probe\n"); + return -EPROBE_DEFER; + } + + /* find the spi slave matching the n5010-phy driver */ + phy_dev = device_find_child(phy_master, dfl_dev, + n5010_match_phy_dev); + if (!phy_dev) { + dev_info(dev, "phy slave not found; deferring probe\n"); + ret = -EPROBE_DEFER; + goto err_phy_master; + } + + base = devm_ioremap_resource(dev, &dfl_dev->mmio_res); + if (IS_ERR(base)) { + ret = PTR_ERR(base); + goto err_phy_dev; + } + + val = readq(base + CAPABILITY_OFFSET); + port_cnt = FIELD_GET(CAP_PORT_CNT, val); + priv_size = sizeof(*priv) + port_cnt * sizeof(void *); + + priv = devm_kzalloc(dev, priv_size, GFP_KERNEL); + if (!priv) { + ret = -ENOMEM; + goto err_phy_dev; + } + + dev_set_drvdata(dev, priv); + + priv->dfl_dev = dfl_dev; + priv->port_cnt = port_cnt; + priv->base = base; + + for (port = 0; port < priv->port_cnt; port++) { + ret = n5010_hssi_create_netdev(priv, phy_dev, port); + if (ret) + goto err_phy_dev; + } + +err_phy_dev: + put_device(phy_dev); +err_phy_master: + put_device(phy_master); + + return ret; +} + +static void n5010_hssi_remove(struct dfl_device *dfl_dev) +{ + struct n5010_hssi_drvdata *priv = dev_get_drvdata(&dfl_dev->dev); + u64 port; + + for (port = 0; port < priv->port_cnt; port++) { + n5010_phy_detach(priv->netdev[port]); + unregister_netdev(priv->netdev[port]); + } +} + +#define FME_FEATURE_ID_LL_100G_MAC_N5010 0x1f /* Silicom Lightning Creek */ + +static const struct dfl_device_id n5010_hssi_mac_ids[] = { + { FME_ID, FME_FEATURE_ID_LL_100G_MAC_N5010 }, + { } +}; + +static struct dfl_driver n5010_hssi_driver = { + .drv = { + .name = "n5010_hssi", + }, + .id_table = n5010_hssi_mac_ids, + .probe = n5010_hssi_probe, + .remove = n5010_hssi_remove, +}; + +module_dfl_driver(n5010_hssi_driver); +MODULE_DEVICE_TABLE(dfl, n5010_hssi_mac_ids); +MODULE_DESCRIPTION("Network Device Driver for Silicom Lightning Creek"); +MODULE_AUTHOR("Esa Leskinen "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/ethernet/silicom/n5010-phy.c b/drivers/net/ethernet/silicom/n5010-phy.c new file mode 100644 index 000000000000..084b615c3580 --- /dev/null +++ b/drivers/net/ethernet/silicom/n5010-phy.c @@ -0,0 +1,235 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Intel Max10 BMC Lightning Creek phy Driver + * + * Copyright (C) 2020 Silicom Denmark A/S. All rights reserved. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "n5010-phy.h" + +#define N5010_PHY_CSR_0 0x40c +#define N5010_PHY_CSR_1 0x410 + +#define N5010_PHY_ABSENT_0 BIT(7) +#define N5010_PHY_ABSENT_1 BIT(23) + +#define N5010_PHY_LED_0 GENMASK(5, 3) +#define N5010_PHY_LED_1 GENMASK(21, 19) + +struct n5010_phy { + struct intel_m10bmc *m10bmc; +}; + +struct n5010_port { + u64 num; + bool sfp_in; + struct n5010_phy *priv; + struct phy_device *phy; + bool (*get_link)(struct net_device *netdev); +}; + +static struct fixed_phy_status n5010_phy_status = { + .link = 0, + .speed = 1000, + .duplex = 1, +}; + +static int n5010_phy_sfp_status(struct n5010_port *port) +{ + unsigned int offset, bit, val; + int ret; + + switch (port->num) { + case 0: + offset = N5010_PHY_CSR_1; + bit = N5010_PHY_ABSENT_0; + break; + case 1: + offset = N5010_PHY_CSR_1; + bit = N5010_PHY_ABSENT_1; + break; + case 2: + offset = N5010_PHY_CSR_0; + bit = N5010_PHY_ABSENT_0; + break; + case 3: + offset = N5010_PHY_CSR_0; + bit = N5010_PHY_ABSENT_1; + break; + default: + return -EINVAL; + } + + ret = m10bmc_sys_read(port->priv->m10bmc, offset, &val); + if (ret) + return ret; + + port->sfp_in = !(val & bit); + + return 0; +} + +static int n5010_phy_set_led(struct n5010_port *port, bool link) +{ + unsigned int offset, mask, val; + + switch (port->num) { + case 0: + offset = N5010_PHY_CSR_1; + mask = N5010_PHY_LED_0; + break; + case 1: + offset = N5010_PHY_CSR_1; + mask = N5010_PHY_LED_1; + break; + case 2: + offset = N5010_PHY_CSR_0; + mask = N5010_PHY_LED_0; + break; + case 3: + offset = N5010_PHY_CSR_0; + mask = N5010_PHY_LED_1; + break; + default: + return -EINVAL; + } + + val = link ? mask : 0; + + return m10bmc_sys_update_bits(port->priv->m10bmc, offset, mask, val); +} + +static void n5010_phy_adjust_link(struct net_device *netdev) +{ + struct n5010_port *port = netdev->phydev->priv; + bool link = netdev->phydev->link; + int err; + + netdev_info(netdev, "link: %i\n", link); + + err = n5010_phy_set_led(port, link); + if (err) + netdev_info(netdev, "failed to set led: %i\n", err); +} + +static int n5010_phy_update_link(struct net_device *netdev, + struct fixed_phy_status *status) +{ + struct n5010_port *port = netdev->phydev->priv; + bool sfp_in = port->sfp_in; + + n5010_phy_sfp_status(port); + status->link = port->get_link(netdev); + + if (sfp_in != port->sfp_in) + netdev_info(netdev, "sfp: %s\n", port->sfp_in ? "in" : "out"); + + return 0; +} + +int n5010_phy_module_info(struct net_device *netdev) +{ + struct n5010_port *port = netdev->phydev->priv; + + return port->sfp_in ? -ENODATA : -ENODEV; +} +EXPORT_SYMBOL(n5010_phy_module_info); + +int n5010_phy_attach(struct device *dev, struct net_device *netdev, + bool (*get_link)(struct net_device *), u64 port_num) +{ + struct n5010_phy *priv = dev_get_drvdata(dev); + struct phy_device *phy; + struct n5010_port *port; + int ret; + + phy = fixed_phy_register(PHY_POLL, &n5010_phy_status, NULL); + if (IS_ERR(phy)) + return PTR_ERR(phy); + + port = devm_kzalloc(&phy->mdio.dev, sizeof(*port), GFP_KERNEL); + if (!port) + return -ENOMEM; + + port->num = port_num; + port->priv = priv; + port->phy = phy; + port->get_link = get_link; + + phy->priv = port; + + ret = phy_connect_direct(netdev, phy, &n5010_phy_adjust_link, + PHY_INTERFACE_MODE_NA); + if (ret) + goto err_deregister; + + fixed_phy_set_link_update(phy, n5010_phy_update_link); + fixed_phy_change_carrier(netdev, false); + n5010_phy_sfp_status(port); + + netdev_info(netdev, "sfp: %s\n", port->sfp_in ? "in" : "out"); + + return 0; + +err_deregister: + fixed_phy_unregister(phy); + + return ret; +} +EXPORT_SYMBOL(n5010_phy_attach); + +int n5010_phy_detach(struct net_device *netdev) +{ + struct phy_device *phy = netdev->phydev; + + phy_detach(phy); + fixed_phy_unregister(phy); + phy_device_free(phy); + + return 0; +} +EXPORT_SYMBOL(n5010_phy_detach); + +static int n5010_phy_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct n5010_phy *priv; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + dev_set_drvdata(dev, priv); + priv->m10bmc = dev_get_drvdata(dev->parent); + + return 0; +} + +static const struct platform_device_id n5010_phy_ids[] = { + { + .name = "n5010bmc-phy", + }, + { } +}; + +static struct platform_driver n5010_phy_driver = { + .probe = n5010_phy_probe, + .driver = { + .name = "n5010bmc-phy", + }, + .id_table = n5010_phy_ids, +}; +module_platform_driver(n5010_phy_driver); + +MODULE_DEVICE_TABLE(platform, n5010_phy_ids); +MODULE_AUTHOR("Intel Corporation"); +MODULE_DESCRIPTION("Intel MAX10 BMC phy driver for n5010"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/silicom/n5010-phy.h b/drivers/net/ethernet/silicom/n5010-phy.h new file mode 100644 index 000000000000..9d466f88fb1a --- /dev/null +++ b/drivers/net/ethernet/silicom/n5010-phy.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Header File for DFL driver and device API + * + * Copyright (C) 2020 Silicom Denmark A/S. All rights reserved. + */ + +#ifndef __SILICOM_N5010_PHY_H +#define __SILICOM_N5010_PHY_H + +int n5010_phy_module_info(struct net_device *netdev); +int n5010_phy_attach(struct device *dev, struct net_device *netdev, + bool (*update)(struct net_device *netdev), u64 port_num); +int n5010_phy_detach(struct net_device *netdev); + +#endif diff --git a/include/linux/dfl.h b/include/linux/dfl.h index 1cd86b2e7cb1..4c86ae896ef1 100644 --- a/include/linux/dfl.h +++ b/include/linux/dfl.h @@ -135,4 +135,6 @@ static inline u8 dfl_feature_revision(void __iomem *base) return (u8)FIELD_GET(DFH_REVISION, readq(base + DFH)); } +struct device *dfl_dev_get_base_dev(struct dfl_device *dfl_dev); + #endif /* __LINUX_DFL_H */ diff --git a/include/linux/mfd/intel-m10-bmc.h b/include/linux/mfd/intel-m10-bmc.h index 33b13cd35e24..fbe70b8d6362 100644 --- a/include/linux/mfd/intel-m10-bmc.h +++ b/include/linux/mfd/intel-m10-bmc.h @@ -13,7 +13,8 @@ /* Supported MAX10 BMC types */ enum m10bmc_type { M10_N3000, - M10_D5005 + M10_D5005, + M10_N5010, }; #define M10BMC_LEGACY_SYS_BASE 0x300400 diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index d8156a5dbee8..aae07d512ca6 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2588,6 +2588,8 @@ #define PCI_VENDOR_ID_REDHAT 0x1b36 +#define PCI_VENDOR_ID_SILICOM_DENMARK 0x1c2c + #define PCI_VENDOR_ID_AMAZON_ANNAPURNA_LABS 0x1c36 #define PCI_VENDOR_ID_CIRCUITCO 0x1cc8