diff options
author | Ben Hutchings <bhutchings@solarflare.com> | 2009-11-29 10:15:41 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-11-29 20:23:57 -0500 |
commit | 8880f4ec21e668dcab3c6d387524a887e5bcbf73 (patch) | |
tree | d2f34eec2fba31f3b3141c2e580846e92c4e554c | |
parent | afd4aea03f597f29421dc5767e7d1f754730ec23 (diff) |
sfc: Add support for SFC9000 family (2)
This integrates support for the SFC9000 family of 10G Ethernet
controllers and LAN-on-motherboard chips, starting with the SFL9021
'Siena' and SFC9020 'Bethpage'.
Credit for this code is largely due to my colleagues at Solarflare:
Guido Barzini
Steve Hodgson
Kieran Mansley
Matthew Slattery
Neil Turton
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/sfc/Kconfig | 13 | ||||
-rw-r--r-- | drivers/net/sfc/Makefile | 7 | ||||
-rw-r--r-- | drivers/net/sfc/bitfield.h | 2 | ||||
-rw-r--r-- | drivers/net/sfc/efx.c | 26 | ||||
-rw-r--r-- | drivers/net/sfc/efx.h | 2 | ||||
-rw-r--r-- | drivers/net/sfc/enum.h | 2 | ||||
-rw-r--r-- | drivers/net/sfc/ethtool.c | 3 | ||||
-rw-r--r-- | drivers/net/sfc/mac.h | 3 | ||||
-rw-r--r-- | drivers/net/sfc/mtd.c | 267 | ||||
-rw-r--r-- | drivers/net/sfc/net_driver.h | 10 | ||||
-rw-r--r-- | drivers/net/sfc/nic.c | 63 | ||||
-rw-r--r-- | drivers/net/sfc/nic.h | 23 | ||||
-rw-r--r-- | drivers/net/sfc/phy.h | 17 | ||||
-rw-r--r-- | drivers/net/sfc/workarounds.h | 5 |
14 files changed, 414 insertions, 29 deletions
diff --git a/drivers/net/sfc/Kconfig b/drivers/net/sfc/Kconfig index 260aafaac235..a65c98638398 100644 --- a/drivers/net/sfc/Kconfig +++ b/drivers/net/sfc/Kconfig | |||
@@ -1,5 +1,5 @@ | |||
1 | config SFC | 1 | config SFC |
2 | tristate "Solarflare Solarstorm SFC4000 support" | 2 | tristate "Solarflare Solarstorm SFC4000/SFC9000-family support" |
3 | depends on PCI && INET | 3 | depends on PCI && INET |
4 | select MDIO | 4 | select MDIO |
5 | select CRC32 | 5 | select CRC32 |
@@ -7,15 +7,16 @@ config SFC | |||
7 | select I2C_ALGOBIT | 7 | select I2C_ALGOBIT |
8 | help | 8 | help |
9 | This driver supports 10-gigabit Ethernet cards based on | 9 | This driver supports 10-gigabit Ethernet cards based on |
10 | the Solarflare Communications Solarstorm SFC4000 controller. | 10 | the Solarflare Communications Solarstorm SFC4000 and |
11 | SFC9000-family controllers. | ||
11 | 12 | ||
12 | To compile this driver as a module, choose M here. The module | 13 | To compile this driver as a module, choose M here. The module |
13 | will be called sfc. | 14 | will be called sfc. |
14 | config SFC_MTD | 15 | config SFC_MTD |
15 | bool "Solarflare Solarstorm SFC4000 flash MTD support" | 16 | bool "Solarflare Solarstorm SFC4000/SFC9000-family MTD support" |
16 | depends on SFC && MTD && !(SFC=y && MTD=m) | 17 | depends on SFC && MTD && !(SFC=y && MTD=m) |
17 | default y | 18 | default y |
18 | help | 19 | help |
19 | This exposes the on-board flash memory as an MTD device (e.g. | 20 | This exposes the on-board flash memory as MTD devices (e.g. |
20 | /dev/mtd1). This makes it possible to upload new boot code | 21 | /dev/mtd1). This makes it possible to upload new firmware |
21 | to the NIC. | 22 | to the NIC. |
diff --git a/drivers/net/sfc/Makefile b/drivers/net/sfc/Makefile index 223106b93447..1047b19c60a5 100644 --- a/drivers/net/sfc/Makefile +++ b/drivers/net/sfc/Makefile | |||
@@ -1,6 +1,7 @@ | |||
1 | sfc-y += efx.o nic.o falcon.o tx.o rx.o falcon_gmac.o \ | 1 | sfc-y += efx.o nic.o falcon.o siena.o tx.o rx.o \ |
2 | falcon_xmac.o selftest.o ethtool.o qt202x_phy.o \ | 2 | falcon_gmac.o falcon_xmac.o mcdi_mac.o \ |
3 | mdio_10g.o tenxpress.o falcon_boards.o | 3 | selftest.o ethtool.o qt202x_phy.o mdio_10g.o \ |
4 | tenxpress.o falcon_boards.o mcdi.o mcdi_phy.o | ||
4 | sfc-$(CONFIG_SFC_MTD) += mtd.o | 5 | sfc-$(CONFIG_SFC_MTD) += mtd.o |
5 | 6 | ||
6 | obj-$(CONFIG_SFC) += sfc.o | 7 | obj-$(CONFIG_SFC) += sfc.o |
diff --git a/drivers/net/sfc/bitfield.h b/drivers/net/sfc/bitfield.h index 6ad909bba957..bb5de4fe9257 100644 --- a/drivers/net/sfc/bitfield.h +++ b/drivers/net/sfc/bitfield.h | |||
@@ -37,6 +37,8 @@ | |||
37 | #define EFX_DWORD_2_WIDTH 32 | 37 | #define EFX_DWORD_2_WIDTH 32 |
38 | #define EFX_DWORD_3_LBN 96 | 38 | #define EFX_DWORD_3_LBN 96 |
39 | #define EFX_DWORD_3_WIDTH 32 | 39 | #define EFX_DWORD_3_WIDTH 32 |
40 | #define EFX_QWORD_0_LBN 0 | ||
41 | #define EFX_QWORD_0_WIDTH 64 | ||
40 | 42 | ||
41 | /* Specified attribute (e.g. LBN) of the specified field */ | 43 | /* Specified attribute (e.g. LBN) of the specified field */ |
42 | #define EFX_VAL(field, attribute) field ## _ ## attribute | 44 | #define EFX_VAL(field, attribute) field ## _ ## attribute |
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 97a6ebdcaf2b..4b5c786f0e2c 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c | |||
@@ -25,6 +25,8 @@ | |||
25 | #include "mdio_10g.h" | 25 | #include "mdio_10g.h" |
26 | #include "nic.h" | 26 | #include "nic.h" |
27 | 27 | ||
28 | #include "mcdi.h" | ||
29 | |||
28 | /************************************************************************** | 30 | /************************************************************************** |
29 | * | 31 | * |
30 | * Type name strings | 32 | * Type name strings |
@@ -84,6 +86,7 @@ const char *efx_reset_type_names[] = { | |||
84 | [RESET_TYPE_RX_DESC_FETCH] = "RX_DESC_FETCH", | 86 | [RESET_TYPE_RX_DESC_FETCH] = "RX_DESC_FETCH", |
85 | [RESET_TYPE_TX_DESC_FETCH] = "TX_DESC_FETCH", | 87 | [RESET_TYPE_TX_DESC_FETCH] = "TX_DESC_FETCH", |
86 | [RESET_TYPE_TX_SKIP] = "TX_SKIP", | 88 | [RESET_TYPE_TX_SKIP] = "TX_SKIP", |
89 | [RESET_TYPE_MC_FAILURE] = "MC_FAILURE", | ||
87 | }; | 90 | }; |
88 | 91 | ||
89 | #define EFX_MAX_MTU (9 * 1024) | 92 | #define EFX_MAX_MTU (9 * 1024) |
@@ -1191,6 +1194,15 @@ static void efx_start_all(struct efx_nic *efx) | |||
1191 | 1194 | ||
1192 | efx_nic_enable_interrupts(efx); | 1195 | efx_nic_enable_interrupts(efx); |
1193 | 1196 | ||
1197 | /* Switch to event based MCDI completions after enabling interrupts. | ||
1198 | * If a reset has been scheduled, then we need to stay in polled mode. | ||
1199 | * Rather than serialising efx_mcdi_mode_event() [which sleeps] and | ||
1200 | * reset_pending [modified from an atomic context], we instead guarantee | ||
1201 | * that efx_mcdi_mode_poll() isn't reverted erroneously */ | ||
1202 | efx_mcdi_mode_event(efx); | ||
1203 | if (efx->reset_pending != RESET_TYPE_NONE) | ||
1204 | efx_mcdi_mode_poll(efx); | ||
1205 | |||
1194 | /* Start the hardware monitor if there is one. Otherwise (we're link | 1206 | /* Start the hardware monitor if there is one. Otherwise (we're link |
1195 | * event driven), we have to poll the PHY because after an event queue | 1207 | * event driven), we have to poll the PHY because after an event queue |
1196 | * flush, we could have a missed a link state change */ | 1208 | * flush, we could have a missed a link state change */ |
@@ -1242,6 +1254,9 @@ static void efx_stop_all(struct efx_nic *efx) | |||
1242 | 1254 | ||
1243 | efx->type->stop_stats(efx); | 1255 | efx->type->stop_stats(efx); |
1244 | 1256 | ||
1257 | /* Switch to MCDI polling on Siena before disabling interrupts */ | ||
1258 | efx_mcdi_mode_poll(efx); | ||
1259 | |||
1245 | /* Disable interrupts and wait for ISR to complete */ | 1260 | /* Disable interrupts and wait for ISR to complete */ |
1246 | efx_nic_disable_interrupts(efx); | 1261 | efx_nic_disable_interrupts(efx); |
1247 | if (efx->legacy_irq) | 1262 | if (efx->legacy_irq) |
@@ -1445,6 +1460,8 @@ static int efx_net_open(struct net_device *net_dev) | |||
1445 | return -EIO; | 1460 | return -EIO; |
1446 | if (efx->phy_mode & PHY_MODE_SPECIAL) | 1461 | if (efx->phy_mode & PHY_MODE_SPECIAL) |
1447 | return -EBUSY; | 1462 | return -EBUSY; |
1463 | if (efx_mcdi_poll_reboot(efx) && efx_reset(efx, RESET_TYPE_ALL)) | ||
1464 | return -EIO; | ||
1448 | 1465 | ||
1449 | /* Notify the kernel of the link state polled during driver load, | 1466 | /* Notify the kernel of the link state polled during driver load, |
1450 | * before the monitor starts running */ | 1467 | * before the monitor starts running */ |
@@ -1895,6 +1912,7 @@ void efx_schedule_reset(struct efx_nic *efx, enum reset_type type) | |||
1895 | case RESET_TYPE_TX_SKIP: | 1912 | case RESET_TYPE_TX_SKIP: |
1896 | method = RESET_TYPE_INVISIBLE; | 1913 | method = RESET_TYPE_INVISIBLE; |
1897 | break; | 1914 | break; |
1915 | case RESET_TYPE_MC_FAILURE: | ||
1898 | default: | 1916 | default: |
1899 | method = RESET_TYPE_ALL; | 1917 | method = RESET_TYPE_ALL; |
1900 | break; | 1918 | break; |
@@ -1908,6 +1926,10 @@ void efx_schedule_reset(struct efx_nic *efx, enum reset_type type) | |||
1908 | 1926 | ||
1909 | efx->reset_pending = method; | 1927 | efx->reset_pending = method; |
1910 | 1928 | ||
1929 | /* efx_process_channel() will no longer read events once a | ||
1930 | * reset is scheduled. So switch back to poll'd MCDI completions. */ | ||
1931 | efx_mcdi_mode_poll(efx); | ||
1932 | |||
1911 | queue_work(reset_workqueue, &efx->reset_work); | 1933 | queue_work(reset_workqueue, &efx->reset_work); |
1912 | } | 1934 | } |
1913 | 1935 | ||
@@ -1923,6 +1945,10 @@ static struct pci_device_id efx_pci_table[] __devinitdata = { | |||
1923 | .driver_data = (unsigned long) &falcon_a1_nic_type}, | 1945 | .driver_data = (unsigned long) &falcon_a1_nic_type}, |
1924 | {PCI_DEVICE(EFX_VENDID_SFC, FALCON_B_P_DEVID), | 1946 | {PCI_DEVICE(EFX_VENDID_SFC, FALCON_B_P_DEVID), |
1925 | .driver_data = (unsigned long) &falcon_b0_nic_type}, | 1947 | .driver_data = (unsigned long) &falcon_b0_nic_type}, |
1948 | {PCI_DEVICE(EFX_VENDID_SFC, BETHPAGE_A_P_DEVID), | ||
1949 | .driver_data = (unsigned long) &siena_a0_nic_type}, | ||
1950 | {PCI_DEVICE(EFX_VENDID_SFC, SIENA_A_P_DEVID), | ||
1951 | .driver_data = (unsigned long) &siena_a0_nic_type}, | ||
1926 | {0} /* end of list */ | 1952 | {0} /* end of list */ |
1927 | }; | 1953 | }; |
1928 | 1954 | ||
diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h index fa40c7b66d7b..b4470da23860 100644 --- a/drivers/net/sfc/efx.h +++ b/drivers/net/sfc/efx.h | |||
@@ -18,6 +18,8 @@ | |||
18 | #define FALCON_A_P_DEVID 0x0703 | 18 | #define FALCON_A_P_DEVID 0x0703 |
19 | #define FALCON_A_S_DEVID 0x6703 | 19 | #define FALCON_A_S_DEVID 0x6703 |
20 | #define FALCON_B_P_DEVID 0x0710 | 20 | #define FALCON_B_P_DEVID 0x0710 |
21 | #define BETHPAGE_A_P_DEVID 0x0803 | ||
22 | #define SIENA_A_P_DEVID 0x0813 | ||
21 | 23 | ||
22 | /* Solarstorm controllers use BAR 0 for I/O space and BAR 2(&3) for memory */ | 24 | /* Solarstorm controllers use BAR 0 for I/O space and BAR 2(&3) for memory */ |
23 | #define EFX_MEM_BAR 2 | 25 | #define EFX_MEM_BAR 2 |
diff --git a/drivers/net/sfc/enum.h b/drivers/net/sfc/enum.h index 7a9e79ab9313..b1f7a40ab15f 100644 --- a/drivers/net/sfc/enum.h +++ b/drivers/net/sfc/enum.h | |||
@@ -144,6 +144,7 @@ enum efx_loopback_mode { | |||
144 | * @RESET_TYPE_RX_DESC_FETCH: pcie error during rx descriptor fetch | 144 | * @RESET_TYPE_RX_DESC_FETCH: pcie error during rx descriptor fetch |
145 | * @RESET_TYPE_TX_DESC_FETCH: pcie error during tx descriptor fetch | 145 | * @RESET_TYPE_TX_DESC_FETCH: pcie error during tx descriptor fetch |
146 | * @RESET_TYPE_TX_SKIP: hardware completed empty tx descriptors | 146 | * @RESET_TYPE_TX_SKIP: hardware completed empty tx descriptors |
147 | * @RESET_TYPE_MC_FAILURE: MC reboot/assertion | ||
147 | */ | 148 | */ |
148 | enum reset_type { | 149 | enum reset_type { |
149 | RESET_TYPE_NONE = -1, | 150 | RESET_TYPE_NONE = -1, |
@@ -158,6 +159,7 @@ enum reset_type { | |||
158 | RESET_TYPE_RX_DESC_FETCH, | 159 | RESET_TYPE_RX_DESC_FETCH, |
159 | RESET_TYPE_TX_DESC_FETCH, | 160 | RESET_TYPE_TX_DESC_FETCH, |
160 | RESET_TYPE_TX_SKIP, | 161 | RESET_TYPE_TX_SKIP, |
162 | RESET_TYPE_MC_FAILURE, | ||
161 | RESET_TYPE_MAX, | 163 | RESET_TYPE_MAX, |
162 | }; | 164 | }; |
163 | 165 | ||
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index 012ee31db0c2..5492b6336602 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c | |||
@@ -236,6 +236,9 @@ static void efx_ethtool_get_drvinfo(struct net_device *net_dev, | |||
236 | 236 | ||
237 | strlcpy(info->driver, EFX_DRIVER_NAME, sizeof(info->driver)); | 237 | strlcpy(info->driver, EFX_DRIVER_NAME, sizeof(info->driver)); |
238 | strlcpy(info->version, EFX_DRIVER_VERSION, sizeof(info->version)); | 238 | strlcpy(info->version, EFX_DRIVER_VERSION, sizeof(info->version)); |
239 | if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0) | ||
240 | siena_print_fwver(efx, info->fw_version, | ||
241 | sizeof(info->fw_version)); | ||
239 | strlcpy(info->bus_info, pci_name(efx->pci_dev), sizeof(info->bus_info)); | 242 | strlcpy(info->bus_info, pci_name(efx->pci_dev), sizeof(info->bus_info)); |
240 | } | 243 | } |
241 | 244 | ||
diff --git a/drivers/net/sfc/mac.h b/drivers/net/sfc/mac.h index d2af50f1747b..c733863fa41e 100644 --- a/drivers/net/sfc/mac.h +++ b/drivers/net/sfc/mac.h | |||
@@ -15,6 +15,9 @@ | |||
15 | 15 | ||
16 | extern struct efx_mac_operations falcon_gmac_operations; | 16 | extern struct efx_mac_operations falcon_gmac_operations; |
17 | extern struct efx_mac_operations falcon_xmac_operations; | 17 | extern struct efx_mac_operations falcon_xmac_operations; |
18 | extern struct efx_mac_operations efx_mcdi_mac_operations; | ||
18 | extern void falcon_reconfigure_xmac_core(struct efx_nic *efx); | 19 | extern void falcon_reconfigure_xmac_core(struct efx_nic *efx); |
20 | extern int efx_mcdi_mac_stats(struct efx_nic *efx, dma_addr_t dma_addr, | ||
21 | u32 dma_len, int enable, int clear); | ||
19 | 22 | ||
20 | #endif | 23 | #endif |
diff --git a/drivers/net/sfc/mtd.c b/drivers/net/sfc/mtd.c index 65a22f193f92..ef561f8af4d1 100644 --- a/drivers/net/sfc/mtd.c +++ b/drivers/net/sfc/mtd.c | |||
@@ -8,6 +8,7 @@ | |||
8 | * by the Free Software Foundation, incorporated herein by reference. | 8 | * by the Free Software Foundation, incorporated herein by reference. |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/bitops.h> | ||
11 | #include <linux/module.h> | 12 | #include <linux/module.h> |
12 | #include <linux/mtd/mtd.h> | 13 | #include <linux/mtd/mtd.h> |
13 | #include <linux/delay.h> | 14 | #include <linux/delay.h> |
@@ -18,12 +19,22 @@ | |||
18 | #include "spi.h" | 19 | #include "spi.h" |
19 | #include "efx.h" | 20 | #include "efx.h" |
20 | #include "nic.h" | 21 | #include "nic.h" |
22 | #include "mcdi.h" | ||
23 | #include "mcdi_pcol.h" | ||
21 | 24 | ||
22 | #define EFX_SPI_VERIFY_BUF_LEN 16 | 25 | #define EFX_SPI_VERIFY_BUF_LEN 16 |
26 | #define EFX_MCDI_CHUNK_LEN 128 | ||
23 | 27 | ||
24 | struct efx_mtd_partition { | 28 | struct efx_mtd_partition { |
25 | struct mtd_info mtd; | 29 | struct mtd_info mtd; |
26 | size_t offset; | 30 | union { |
31 | struct { | ||
32 | bool updating; | ||
33 | u8 nvram_type; | ||
34 | u16 fw_subtype; | ||
35 | } mcdi; | ||
36 | size_t offset; | ||
37 | }; | ||
27 | const char *type_name; | 38 | const char *type_name; |
28 | char name[IFNAMSIZ + 20]; | 39 | char name[IFNAMSIZ + 20]; |
29 | }; | 40 | }; |
@@ -56,6 +67,7 @@ struct efx_mtd { | |||
56 | container_of(mtd, struct efx_mtd_partition, mtd) | 67 | container_of(mtd, struct efx_mtd_partition, mtd) |
57 | 68 | ||
58 | static int falcon_mtd_probe(struct efx_nic *efx); | 69 | static int falcon_mtd_probe(struct efx_nic *efx); |
70 | static int siena_mtd_probe(struct efx_nic *efx); | ||
59 | 71 | ||
60 | /* SPI utilities */ | 72 | /* SPI utilities */ |
61 | 73 | ||
@@ -223,9 +235,14 @@ static void efx_mtd_rename_device(struct efx_mtd *efx_mtd) | |||
223 | struct efx_mtd_partition *part; | 235 | struct efx_mtd_partition *part; |
224 | 236 | ||
225 | efx_for_each_partition(part, efx_mtd) | 237 | efx_for_each_partition(part, efx_mtd) |
226 | snprintf(part->name, sizeof(part->name), | 238 | if (efx_nic_rev(efx_mtd->efx) >= EFX_REV_SIENA_A0) |
227 | "%s %s", efx_mtd->efx->name, | 239 | snprintf(part->name, sizeof(part->name), |
228 | part->type_name); | 240 | "%s %s:%02x", efx_mtd->efx->name, |
241 | part->type_name, part->mcdi.fw_subtype); | ||
242 | else | ||
243 | snprintf(part->name, sizeof(part->name), | ||
244 | "%s %s", efx_mtd->efx->name, | ||
245 | part->type_name); | ||
229 | } | 246 | } |
230 | 247 | ||
231 | static int efx_mtd_probe_device(struct efx_nic *efx, struct efx_mtd *efx_mtd) | 248 | static int efx_mtd_probe_device(struct efx_nic *efx, struct efx_mtd *efx_mtd) |
@@ -285,7 +302,10 @@ void efx_mtd_rename(struct efx_nic *efx) | |||
285 | 302 | ||
286 | int efx_mtd_probe(struct efx_nic *efx) | 303 | int efx_mtd_probe(struct efx_nic *efx) |
287 | { | 304 | { |
288 | return falcon_mtd_probe(efx); | 305 | if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0) |
306 | return siena_mtd_probe(efx); | ||
307 | else | ||
308 | return falcon_mtd_probe(efx); | ||
289 | } | 309 | } |
290 | 310 | ||
291 | /* Implementation of MTD operations for Falcon */ | 311 | /* Implementation of MTD operations for Falcon */ |
@@ -393,3 +413,240 @@ static int falcon_mtd_probe(struct efx_nic *efx) | |||
393 | kfree(efx_mtd); | 413 | kfree(efx_mtd); |
394 | return rc; | 414 | return rc; |
395 | } | 415 | } |
416 | |||
417 | /* Implementation of MTD operations for Siena */ | ||
418 | |||
419 | static int siena_mtd_read(struct mtd_info *mtd, loff_t start, | ||
420 | size_t len, size_t *retlen, u8 *buffer) | ||
421 | { | ||
422 | struct efx_mtd_partition *part = to_efx_mtd_partition(mtd); | ||
423 | struct efx_mtd *efx_mtd = mtd->priv; | ||
424 | struct efx_nic *efx = efx_mtd->efx; | ||
425 | loff_t offset = start; | ||
426 | loff_t end = min_t(loff_t, start + len, mtd->size); | ||
427 | size_t chunk; | ||
428 | int rc = 0; | ||
429 | |||
430 | while (offset < end) { | ||
431 | chunk = min_t(size_t, end - offset, EFX_MCDI_CHUNK_LEN); | ||
432 | rc = efx_mcdi_nvram_read(efx, part->mcdi.nvram_type, offset, | ||
433 | buffer, chunk); | ||
434 | if (rc) | ||
435 | goto out; | ||
436 | offset += chunk; | ||
437 | buffer += chunk; | ||
438 | } | ||
439 | out: | ||
440 | *retlen = offset - start; | ||
441 | return rc; | ||
442 | } | ||
443 | |||
444 | static int siena_mtd_erase(struct mtd_info *mtd, loff_t start, size_t len) | ||
445 | { | ||
446 | struct efx_mtd_partition *part = to_efx_mtd_partition(mtd); | ||
447 | struct efx_mtd *efx_mtd = mtd->priv; | ||
448 | struct efx_nic *efx = efx_mtd->efx; | ||
449 | loff_t offset = start & ~((loff_t)(mtd->erasesize - 1)); | ||
450 | loff_t end = min_t(loff_t, start + len, mtd->size); | ||
451 | size_t chunk = part->mtd.erasesize; | ||
452 | int rc = 0; | ||
453 | |||
454 | if (!part->mcdi.updating) { | ||
455 | rc = efx_mcdi_nvram_update_start(efx, part->mcdi.nvram_type); | ||
456 | if (rc) | ||
457 | goto out; | ||
458 | part->mcdi.updating = 1; | ||
459 | } | ||
460 | |||
461 | /* The MCDI interface can in fact do multiple erase blocks at once; | ||
462 | * but erasing may be slow, so we make multiple calls here to avoid | ||
463 | * tripping the MCDI RPC timeout. */ | ||
464 | while (offset < end) { | ||
465 | rc = efx_mcdi_nvram_erase(efx, part->mcdi.nvram_type, offset, | ||
466 | chunk); | ||
467 | if (rc) | ||
468 | goto out; | ||
469 | offset += chunk; | ||
470 | } | ||
471 | out: | ||
472 | return rc; | ||
473 | } | ||
474 | |||
475 | static int siena_mtd_write(struct mtd_info *mtd, loff_t start, | ||
476 | size_t len, size_t *retlen, const u8 *buffer) | ||
477 | { | ||
478 | struct efx_mtd_partition *part = to_efx_mtd_partition(mtd); | ||
479 | struct efx_mtd *efx_mtd = mtd->priv; | ||
480 | struct efx_nic *efx = efx_mtd->efx; | ||
481 | loff_t offset = start; | ||
482 | loff_t end = min_t(loff_t, start + len, mtd->size); | ||
483 | size_t chunk; | ||
484 | int rc = 0; | ||
485 | |||
486 | if (!part->mcdi.updating) { | ||
487 | rc = efx_mcdi_nvram_update_start(efx, part->mcdi.nvram_type); | ||
488 | if (rc) | ||
489 | goto out; | ||
490 | part->mcdi.updating = 1; | ||
491 | } | ||
492 | |||
493 | while (offset < end) { | ||
494 | chunk = min_t(size_t, end - offset, EFX_MCDI_CHUNK_LEN); | ||
495 | rc = efx_mcdi_nvram_write(efx, part->mcdi.nvram_type, offset, | ||
496 | buffer, chunk); | ||
497 | if (rc) | ||
498 | goto out; | ||
499 | offset += chunk; | ||
500 | buffer += chunk; | ||
501 | } | ||
502 | out: | ||
503 | *retlen = offset - start; | ||
504 | return rc; | ||
505 | } | ||
506 | |||
507 | static int siena_mtd_sync(struct mtd_info *mtd) | ||
508 | { | ||
509 | struct efx_mtd_partition *part = to_efx_mtd_partition(mtd); | ||
510 | struct efx_mtd *efx_mtd = mtd->priv; | ||
511 | struct efx_nic *efx = efx_mtd->efx; | ||
512 | int rc = 0; | ||
513 | |||
514 | if (part->mcdi.updating) { | ||
515 | part->mcdi.updating = 0; | ||
516 | rc = efx_mcdi_nvram_update_finish(efx, part->mcdi.nvram_type); | ||
517 | } | ||
518 | |||
519 | return rc; | ||
520 | } | ||
521 | |||
522 | static struct efx_mtd_ops siena_mtd_ops = { | ||
523 | .read = siena_mtd_read, | ||
524 | .erase = siena_mtd_erase, | ||
525 | .write = siena_mtd_write, | ||
526 | .sync = siena_mtd_sync, | ||
527 | }; | ||
528 | |||
529 | struct siena_nvram_type_info { | ||
530 | int port; | ||
531 | const char *name; | ||
532 | }; | ||
533 | |||
534 | static struct siena_nvram_type_info siena_nvram_types[] = { | ||
535 | [MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO] = { 0, "sfc_dummy_phy" }, | ||
536 | [MC_CMD_NVRAM_TYPE_MC_FW] = { 0, "sfc_mcfw" }, | ||
537 | [MC_CMD_NVRAM_TYPE_MC_FW_BACKUP] = { 0, "sfc_mcfw_backup" }, | ||
538 | [MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT0] = { 0, "sfc_static_cfg" }, | ||
539 | [MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT1] = { 1, "sfc_static_cfg" }, | ||
540 | [MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0] = { 0, "sfc_dynamic_cfg" }, | ||
541 | [MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1] = { 1, "sfc_dynamic_cfg" }, | ||
542 | [MC_CMD_NVRAM_TYPE_EXP_ROM] = { 0, "sfc_exp_rom" }, | ||
543 | [MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT0] = { 0, "sfc_exp_rom_cfg" }, | ||
544 | [MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT1] = { 1, "sfc_exp_rom_cfg" }, | ||
545 | [MC_CMD_NVRAM_TYPE_PHY_PORT0] = { 0, "sfc_phy_fw" }, | ||
546 | [MC_CMD_NVRAM_TYPE_PHY_PORT1] = { 1, "sfc_phy_fw" }, | ||
547 | }; | ||
548 | |||
549 | static int siena_mtd_probe_partition(struct efx_nic *efx, | ||
550 | struct efx_mtd *efx_mtd, | ||
551 | unsigned int part_id, | ||
552 | unsigned int type) | ||
553 | { | ||
554 | struct efx_mtd_partition *part = &efx_mtd->part[part_id]; | ||
555 | struct siena_nvram_type_info *info; | ||
556 | size_t size, erase_size; | ||
557 | bool protected; | ||
558 | int rc; | ||
559 | |||
560 | if (type >= ARRAY_SIZE(siena_nvram_types)) | ||
561 | return -ENODEV; | ||
562 | |||
563 | info = &siena_nvram_types[type]; | ||
564 | |||
565 | if (info->port != efx_port_num(efx)) | ||
566 | return -ENODEV; | ||
567 | |||
568 | rc = efx_mcdi_nvram_info(efx, type, &size, &erase_size, &protected); | ||
569 | if (rc) | ||
570 | return rc; | ||
571 | if (protected) | ||
572 | return -ENODEV; /* hide it */ | ||
573 | |||
574 | part->mcdi.nvram_type = type; | ||
575 | part->type_name = info->name; | ||
576 | |||
577 | part->mtd.type = MTD_NORFLASH; | ||
578 | part->mtd.flags = MTD_CAP_NORFLASH; | ||
579 | part->mtd.size = size; | ||
580 | part->mtd.erasesize = erase_size; | ||
581 | |||
582 | return 0; | ||
583 | } | ||
584 | |||
585 | static int siena_mtd_get_fw_subtypes(struct efx_nic *efx, | ||
586 | struct efx_mtd *efx_mtd) | ||
587 | { | ||
588 | struct efx_mtd_partition *part; | ||
589 | uint16_t fw_subtype_list[MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_LEN / | ||
590 | sizeof(uint16_t)]; | ||
591 | int rc; | ||
592 | |||
593 | rc = efx_mcdi_get_board_cfg(efx, NULL, fw_subtype_list); | ||
594 | if (rc) | ||
595 | return rc; | ||
596 | |||
597 | efx_for_each_partition(part, efx_mtd) | ||
598 | part->mcdi.fw_subtype = fw_subtype_list[part->mcdi.nvram_type]; | ||
599 | |||
600 | return 0; | ||
601 | } | ||
602 | |||
603 | static int siena_mtd_probe(struct efx_nic *efx) | ||
604 | { | ||
605 | struct efx_mtd *efx_mtd; | ||
606 | int rc = -ENODEV; | ||
607 | u32 nvram_types; | ||
608 | unsigned int type; | ||
609 | |||
610 | ASSERT_RTNL(); | ||
611 | |||
612 | rc = efx_mcdi_nvram_types(efx, &nvram_types); | ||
613 | if (rc) | ||
614 | return rc; | ||
615 | |||
616 | efx_mtd = kzalloc(sizeof(*efx_mtd) + | ||
617 | hweight32(nvram_types) * sizeof(efx_mtd->part[0]), | ||
618 | GFP_KERNEL); | ||
619 | if (!efx_mtd) | ||
620 | return -ENOMEM; | ||
621 | |||
622 | efx_mtd->name = "Siena NVRAM manager"; | ||
623 | |||
624 | efx_mtd->ops = &siena_mtd_ops; | ||
625 | |||
626 | type = 0; | ||
627 | efx_mtd->n_parts = 0; | ||
628 | |||
629 | while (nvram_types != 0) { | ||
630 | if (nvram_types & 1) { | ||
631 | rc = siena_mtd_probe_partition(efx, efx_mtd, | ||
632 | efx_mtd->n_parts, type); | ||
633 | if (rc == 0) | ||
634 | efx_mtd->n_parts++; | ||
635 | else if (rc != -ENODEV) | ||
636 | goto fail; | ||
637 | } | ||
638 | type++; | ||
639 | nvram_types >>= 1; | ||
640 | } | ||
641 | |||
642 | rc = siena_mtd_get_fw_subtypes(efx, efx_mtd); | ||
643 | if (rc) | ||
644 | goto fail; | ||
645 | |||
646 | rc = efx_mtd_probe_device(efx, efx_mtd); | ||
647 | fail: | ||
648 | if (rc) | ||
649 | kfree(efx_mtd); | ||
650 | return rc; | ||
651 | } | ||
652 | |||
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 96d3f00df645..ec132038b26d 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h | |||
@@ -706,6 +706,7 @@ union efx_multicast_hash { | |||
706 | * @phy_op: PHY interface | 706 | * @phy_op: PHY interface |
707 | * @phy_data: PHY private data (including PHY-specific stats) | 707 | * @phy_data: PHY private data (including PHY-specific stats) |
708 | * @mdio: PHY MDIO interface | 708 | * @mdio: PHY MDIO interface |
709 | * @mdio_bus: PHY MDIO bus ID (only used by Siena) | ||
709 | * @phy_mode: PHY operating mode. Serialised by @mac_lock. | 710 | * @phy_mode: PHY operating mode. Serialised by @mac_lock. |
710 | * @xmac_poll_required: XMAC link state needs polling | 711 | * @xmac_poll_required: XMAC link state needs polling |
711 | * @link_advertising: Autonegotiation advertising flags | 712 | * @link_advertising: Autonegotiation advertising flags |
@@ -756,6 +757,7 @@ struct efx_nic { | |||
756 | 757 | ||
757 | struct efx_buffer irq_status; | 758 | struct efx_buffer irq_status; |
758 | volatile signed int last_irq_cpu; | 759 | volatile signed int last_irq_cpu; |
760 | unsigned long irq_zero_count; | ||
759 | 761 | ||
760 | struct efx_spi_device *spi_flash; | 762 | struct efx_spi_device *spi_flash; |
761 | struct efx_spi_device *spi_eeprom; | 763 | struct efx_spi_device *spi_eeprom; |
@@ -766,7 +768,7 @@ struct efx_nic { | |||
766 | 768 | ||
767 | unsigned n_rx_nodesc_drop_cnt; | 769 | unsigned n_rx_nodesc_drop_cnt; |
768 | 770 | ||
769 | struct falcon_nic_data *nic_data; | 771 | void *nic_data; |
770 | 772 | ||
771 | struct mutex mac_lock; | 773 | struct mutex mac_lock; |
772 | struct work_struct mac_work; | 774 | struct work_struct mac_work; |
@@ -792,6 +794,7 @@ struct efx_nic { | |||
792 | struct efx_phy_operations *phy_op; | 794 | struct efx_phy_operations *phy_op; |
793 | void *phy_data; | 795 | void *phy_data; |
794 | struct mdio_if_info mdio; | 796 | struct mdio_if_info mdio; |
797 | unsigned int mdio_bus; | ||
795 | enum efx_phy_mode phy_mode; | 798 | enum efx_phy_mode phy_mode; |
796 | 799 | ||
797 | bool xmac_poll_required; | 800 | bool xmac_poll_required; |
@@ -824,6 +827,11 @@ static inline const char *efx_dev_name(struct efx_nic *efx) | |||
824 | return efx_dev_registered(efx) ? efx->name : ""; | 827 | return efx_dev_registered(efx) ? efx->name : ""; |
825 | } | 828 | } |
826 | 829 | ||
830 | static inline unsigned int efx_port_num(struct efx_nic *efx) | ||
831 | { | ||
832 | return PCI_FUNC(efx->pci_dev->devfn); | ||
833 | } | ||
834 | |||
827 | /** | 835 | /** |
828 | * struct efx_nic_type - Efx device type definition | 836 | * struct efx_nic_type - Efx device type definition |
829 | * @probe: Probe the controller | 837 | * @probe: Probe the controller |
diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c index 55dbd7994b64..5ac4b1af8391 100644 --- a/drivers/net/sfc/nic.c +++ b/drivers/net/sfc/nic.c | |||
@@ -997,6 +997,9 @@ int efx_nic_process_eventq(struct efx_channel *channel, int rx_quota) | |||
997 | case FSE_AZ_EV_CODE_DRIVER_EV: | 997 | case FSE_AZ_EV_CODE_DRIVER_EV: |
998 | efx_handle_driver_event(channel, &event); | 998 | efx_handle_driver_event(channel, &event); |
999 | break; | 999 | break; |
1000 | case FSE_CZ_EV_CODE_MCDI_EV: | ||
1001 | efx_mcdi_process_event(channel, &event); | ||
1002 | break; | ||
1000 | default: | 1003 | default: |
1001 | EFX_ERR(channel->efx, "channel %d unknown event type %d" | 1004 | EFX_ERR(channel->efx, "channel %d unknown event type %d" |
1002 | " (data " EFX_QWORD_FMT ")\n", channel->channel, | 1005 | " (data " EFX_QWORD_FMT ")\n", channel->channel, |
@@ -1025,13 +1028,21 @@ int efx_nic_probe_eventq(struct efx_channel *channel) | |||
1025 | 1028 | ||
1026 | void efx_nic_init_eventq(struct efx_channel *channel) | 1029 | void efx_nic_init_eventq(struct efx_channel *channel) |
1027 | { | 1030 | { |
1028 | efx_oword_t evq_ptr; | 1031 | efx_oword_t reg; |
1029 | struct efx_nic *efx = channel->efx; | 1032 | struct efx_nic *efx = channel->efx; |
1030 | 1033 | ||
1031 | EFX_LOG(efx, "channel %d event queue in special buffers %d-%d\n", | 1034 | EFX_LOG(efx, "channel %d event queue in special buffers %d-%d\n", |
1032 | channel->channel, channel->eventq.index, | 1035 | channel->channel, channel->eventq.index, |
1033 | channel->eventq.index + channel->eventq.entries - 1); | 1036 | channel->eventq.index + channel->eventq.entries - 1); |
1034 | 1037 | ||
1038 | if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0) { | ||
1039 | EFX_POPULATE_OWORD_3(reg, | ||
1040 | FRF_CZ_TIMER_Q_EN, 1, | ||
1041 | FRF_CZ_HOST_NOTIFY_MODE, 0, | ||
1042 | FRF_CZ_TIMER_MODE, FFE_CZ_TIMER_MODE_DIS); | ||
1043 | efx_writeo_table(efx, ®, FR_BZ_TIMER_TBL, channel->channel); | ||
1044 | } | ||
1045 | |||
1035 | /* Pin event queue buffer */ | 1046 | /* Pin event queue buffer */ |
1036 | efx_init_special_buffer(efx, &channel->eventq); | 1047 | efx_init_special_buffer(efx, &channel->eventq); |
1037 | 1048 | ||
@@ -1039,11 +1050,11 @@ void efx_nic_init_eventq(struct efx_channel *channel) | |||
1039 | memset(channel->eventq.addr, 0xff, channel->eventq.len); | 1050 | memset(channel->eventq.addr, 0xff, channel->eventq.len); |
1040 | 1051 | ||
1041 | /* Push event queue to card */ | 1052 | /* Push event queue to card */ |
1042 | EFX_POPULATE_OWORD_3(evq_ptr, | 1053 | EFX_POPULATE_OWORD_3(reg, |
1043 | FRF_AZ_EVQ_EN, 1, | 1054 | FRF_AZ_EVQ_EN, 1, |
1044 | FRF_AZ_EVQ_SIZE, __ffs(channel->eventq.entries), | 1055 | FRF_AZ_EVQ_SIZE, __ffs(channel->eventq.entries), |
1045 | FRF_AZ_EVQ_BUF_BASE_ID, channel->eventq.index); | 1056 | FRF_AZ_EVQ_BUF_BASE_ID, channel->eventq.index); |
1046 | efx_writeo_table(efx, &evq_ptr, efx->type->evq_ptr_tbl_base, | 1057 | efx_writeo_table(efx, ®, efx->type->evq_ptr_tbl_base, |
1047 | channel->channel); | 1058 | channel->channel); |
1048 | 1059 | ||
1049 | efx->type->push_irq_moderation(channel); | 1060 | efx->type->push_irq_moderation(channel); |
@@ -1051,13 +1062,15 @@ void efx_nic_init_eventq(struct efx_channel *channel) | |||
1051 | 1062 | ||
1052 | void efx_nic_fini_eventq(struct efx_channel *channel) | 1063 | void efx_nic_fini_eventq(struct efx_channel *channel) |
1053 | { | 1064 | { |
1054 | efx_oword_t eventq_ptr; | 1065 | efx_oword_t reg; |
1055 | struct efx_nic *efx = channel->efx; | 1066 | struct efx_nic *efx = channel->efx; |
1056 | 1067 | ||
1057 | /* Remove event queue from card */ | 1068 | /* Remove event queue from card */ |
1058 | EFX_ZERO_OWORD(eventq_ptr); | 1069 | EFX_ZERO_OWORD(reg); |
1059 | efx_writeo_table(efx, &eventq_ptr, efx->type->evq_ptr_tbl_base, | 1070 | efx_writeo_table(efx, ®, efx->type->evq_ptr_tbl_base, |
1060 | channel->channel); | 1071 | channel->channel); |
1072 | if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0) | ||
1073 | efx_writeo_table(efx, ®, FR_BZ_TIMER_TBL, channel->channel); | ||
1061 | 1074 | ||
1062 | /* Unpin event queue */ | 1075 | /* Unpin event queue */ |
1063 | efx_fini_special_buffer(efx, &channel->eventq); | 1076 | efx_fini_special_buffer(efx, &channel->eventq); |
@@ -1220,8 +1233,15 @@ static inline void efx_nic_interrupts(struct efx_nic *efx, | |||
1220 | bool enabled, bool force) | 1233 | bool enabled, bool force) |
1221 | { | 1234 | { |
1222 | efx_oword_t int_en_reg_ker; | 1235 | efx_oword_t int_en_reg_ker; |
1236 | unsigned int level = 0; | ||
1237 | |||
1238 | if (EFX_WORKAROUND_17213(efx) && !EFX_INT_MODE_USE_MSI(efx)) | ||
1239 | /* Set the level always even if we're generating a test | ||
1240 | * interrupt, because our legacy interrupt handler is safe */ | ||
1241 | level = 0x1f; | ||
1223 | 1242 | ||
1224 | EFX_POPULATE_OWORD_2(int_en_reg_ker, | 1243 | EFX_POPULATE_OWORD_3(int_en_reg_ker, |
1244 | FRF_AZ_KER_INT_LEVE_SEL, level, | ||
1225 | FRF_AZ_KER_INT_KER, force, | 1245 | FRF_AZ_KER_INT_KER, force, |
1226 | FRF_AZ_DRV_INT_EN_KER, enabled); | 1246 | FRF_AZ_DRV_INT_EN_KER, enabled); |
1227 | efx_writeo(efx, &int_en_reg_ker, FR_AZ_INT_EN_KER); | 1247 | efx_writeo(efx, &int_en_reg_ker, FR_AZ_INT_EN_KER); |
@@ -1334,15 +1354,30 @@ static irqreturn_t efx_legacy_interrupt(int irq, void *dev_id) | |||
1334 | if (unlikely(syserr)) | 1354 | if (unlikely(syserr)) |
1335 | return efx_nic_fatal_interrupt(efx); | 1355 | return efx_nic_fatal_interrupt(efx); |
1336 | 1356 | ||
1337 | /* Schedule processing of any interrupting queues */ | 1357 | if (queues != 0) { |
1338 | efx_for_each_channel(channel, efx) { | 1358 | if (EFX_WORKAROUND_15783(efx)) |
1339 | if ((queues & 1) || | 1359 | efx->irq_zero_count = 0; |
1340 | efx_event_present( | 1360 | |
1341 | efx_event(channel, channel->eventq_read_ptr))) { | 1361 | /* Schedule processing of any interrupting queues */ |
1362 | efx_for_each_channel(channel, efx) { | ||
1363 | if (queues & 1) | ||
1364 | efx_schedule_channel(channel); | ||
1365 | queues >>= 1; | ||
1366 | } | ||
1367 | result = IRQ_HANDLED; | ||
1368 | |||
1369 | } else if (EFX_WORKAROUND_15783(efx) && | ||
1370 | efx->irq_zero_count++ == 0) { | ||
1371 | efx_qword_t *event; | ||
1372 | |||
1373 | /* Ensure we rearm all event queues */ | ||
1374 | efx_for_each_channel(channel, efx) { | ||
1375 | event = efx_event(channel, channel->eventq_read_ptr); | ||
1376 | if (efx_event_present(event)) | ||
1342 | efx_schedule_channel(channel); | 1377 | efx_schedule_channel(channel); |
1343 | result = IRQ_HANDLED; | ||
1344 | } | 1378 | } |
1345 | queues >>= 1; | 1379 | |
1380 | result = IRQ_HANDLED; | ||
1346 | } | 1381 | } |
1347 | 1382 | ||
1348 | if (result == IRQ_HANDLED) { | 1383 | if (result == IRQ_HANDLED) { |
diff --git a/drivers/net/sfc/nic.h b/drivers/net/sfc/nic.h index e7eb30488c15..57c510d8c34d 100644 --- a/drivers/net/sfc/nic.h +++ b/drivers/net/sfc/nic.h | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/i2c-algo-bit.h> | 14 | #include <linux/i2c-algo-bit.h> |
15 | #include "net_driver.h" | 15 | #include "net_driver.h" |
16 | #include "efx.h" | 16 | #include "efx.h" |
17 | #include "mcdi.h" | ||
17 | 18 | ||
18 | /* | 19 | /* |
19 | * Falcon hardware control | 20 | * Falcon hardware control |
@@ -23,6 +24,7 @@ enum { | |||
23 | EFX_REV_FALCON_A0 = 0, | 24 | EFX_REV_FALCON_A0 = 0, |
24 | EFX_REV_FALCON_A1 = 1, | 25 | EFX_REV_FALCON_A1 = 1, |
25 | EFX_REV_FALCON_B0 = 2, | 26 | EFX_REV_FALCON_B0 = 2, |
27 | EFX_REV_SIENA_A0 = 3, | ||
26 | }; | 28 | }; |
27 | 29 | ||
28 | static inline int efx_nic_rev(struct efx_nic *efx) | 30 | static inline int efx_nic_rev(struct efx_nic *efx) |
@@ -32,6 +34,10 @@ static inline int efx_nic_rev(struct efx_nic *efx) | |||
32 | 34 | ||
33 | extern u32 efx_nic_fpga_ver(struct efx_nic *efx); | 35 | extern u32 efx_nic_fpga_ver(struct efx_nic *efx); |
34 | 36 | ||
37 | static inline bool efx_nic_has_mc(struct efx_nic *efx) | ||
38 | { | ||
39 | return efx_nic_rev(efx) >= EFX_REV_SIENA_A0; | ||
40 | } | ||
35 | /* NIC has two interlinked PCI functions for the same port. */ | 41 | /* NIC has two interlinked PCI functions for the same port. */ |
36 | static inline bool efx_nic_is_dual_func(struct efx_nic *efx) | 42 | static inline bool efx_nic_is_dual_func(struct efx_nic *efx) |
37 | { | 43 | { |
@@ -123,8 +129,25 @@ static inline struct falcon_board *falcon_board(struct efx_nic *efx) | |||
123 | return &data->board; | 129 | return &data->board; |
124 | } | 130 | } |
125 | 131 | ||
132 | /** | ||
133 | * struct siena_nic_data - Siena NIC state | ||
134 | * @fw_version: Management controller firmware version | ||
135 | * @fw_build: Firmware build number | ||
136 | * @mcdi: Management-Controller-to-Driver Interface | ||
137 | * @wol_filter_id: Wake-on-LAN packet filter id | ||
138 | */ | ||
139 | struct siena_nic_data { | ||
140 | u64 fw_version; | ||
141 | u32 fw_build; | ||
142 | struct efx_mcdi_iface mcdi; | ||
143 | int wol_filter_id; | ||
144 | }; | ||
145 | |||
146 | extern void siena_print_fwver(struct efx_nic *efx, char *buf, size_t len); | ||
147 | |||
126 | extern struct efx_nic_type falcon_a1_nic_type; | 148 | extern struct efx_nic_type falcon_a1_nic_type; |
127 | extern struct efx_nic_type falcon_b0_nic_type; | 149 | extern struct efx_nic_type falcon_b0_nic_type; |
150 | extern struct efx_nic_type siena_a0_nic_type; | ||
128 | 151 | ||
129 | /************************************************************************** | 152 | /************************************************************************** |
130 | * | 153 | * |
diff --git a/drivers/net/sfc/phy.h b/drivers/net/sfc/phy.h index 2ad1cec2c720..64dff2d59522 100644 --- a/drivers/net/sfc/phy.h +++ b/drivers/net/sfc/phy.h | |||
@@ -41,4 +41,21 @@ extern struct efx_phy_operations falcon_qt202x_phy_ops; | |||
41 | 41 | ||
42 | extern void falcon_qt202x_set_led(struct efx_nic *p, int led, int state); | 42 | extern void falcon_qt202x_set_led(struct efx_nic *p, int led, int state); |
43 | 43 | ||
44 | /**************************************************************************** | ||
45 | * Siena managed PHYs | ||
46 | */ | ||
47 | extern struct efx_phy_operations efx_mcdi_phy_ops; | ||
48 | |||
49 | extern int efx_mcdi_mdio_read(struct efx_nic *efx, unsigned int bus, | ||
50 | unsigned int prtad, unsigned int devad, | ||
51 | u16 addr, u16 *value_out, u32 *status_out); | ||
52 | extern int efx_mcdi_mdio_write(struct efx_nic *efx, unsigned int bus, | ||
53 | unsigned int prtad, unsigned int devad, | ||
54 | u16 addr, u16 value, u32 *status_out); | ||
55 | extern void efx_mcdi_phy_decode_link(struct efx_nic *efx, | ||
56 | struct efx_link_state *link_state, | ||
57 | u32 speed, u32 flags, u32 fcntl); | ||
58 | extern int efx_mcdi_phy_reconfigure(struct efx_nic *efx); | ||
59 | extern void efx_mcdi_phy_check_fcntl(struct efx_nic *efx, u32 lpa); | ||
60 | |||
44 | #endif | 61 | #endif |
diff --git a/drivers/net/sfc/workarounds.h b/drivers/net/sfc/workarounds.h index 021d0d2d97f3..ecee8f57d7f3 100644 --- a/drivers/net/sfc/workarounds.h +++ b/drivers/net/sfc/workarounds.h | |||
@@ -18,6 +18,7 @@ | |||
18 | #define EFX_WORKAROUND_ALWAYS(efx) 1 | 18 | #define EFX_WORKAROUND_ALWAYS(efx) 1 |
19 | #define EFX_WORKAROUND_FALCON_A(efx) (efx_nic_rev(efx) <= EFX_REV_FALCON_A1) | 19 | #define EFX_WORKAROUND_FALCON_A(efx) (efx_nic_rev(efx) <= EFX_REV_FALCON_A1) |
20 | #define EFX_WORKAROUND_FALCON_AB(efx) (efx_nic_rev(efx) <= EFX_REV_FALCON_B0) | 20 | #define EFX_WORKAROUND_FALCON_AB(efx) (efx_nic_rev(efx) <= EFX_REV_FALCON_B0) |
21 | #define EFX_WORKAROUND_SIENA(efx) (efx_nic_rev(efx) == EFX_REV_SIENA_A0) | ||
21 | #define EFX_WORKAROUND_10G(efx) EFX_IS10G(efx) | 22 | #define EFX_WORKAROUND_10G(efx) EFX_IS10G(efx) |
22 | #define EFX_WORKAROUND_SFT9001(efx) ((efx)->phy_type == PHY_TYPE_SFT9001A || \ | 23 | #define EFX_WORKAROUND_SFT9001(efx) ((efx)->phy_type == PHY_TYPE_SFT9001A || \ |
23 | (efx)->phy_type == PHY_TYPE_SFT9001B) | 24 | (efx)->phy_type == PHY_TYPE_SFT9001B) |
@@ -35,6 +36,10 @@ | |||
35 | #define EFX_WORKAROUND_11482 EFX_WORKAROUND_FALCON_AB | 36 | #define EFX_WORKAROUND_11482 EFX_WORKAROUND_FALCON_AB |
36 | /* Truncated IPv4 packets can confuse the TX packet parser */ | 37 | /* Truncated IPv4 packets can confuse the TX packet parser */ |
37 | #define EFX_WORKAROUND_15592 EFX_WORKAROUND_FALCON_AB | 38 | #define EFX_WORKAROUND_15592 EFX_WORKAROUND_FALCON_AB |
39 | /* Legacy ISR read can return zero once */ | ||
40 | #define EFX_WORKAROUND_15783 EFX_WORKAROUND_SIENA | ||
41 | /* Legacy interrupt storm when interrupt fifo fills */ | ||
42 | #define EFX_WORKAROUND_17213 EFX_WORKAROUND_SIENA | ||
38 | 43 | ||
39 | /* Spurious parity errors in TSORT buffers */ | 44 | /* Spurious parity errors in TSORT buffers */ |
40 | #define EFX_WORKAROUND_5129 EFX_WORKAROUND_FALCON_A | 45 | #define EFX_WORKAROUND_5129 EFX_WORKAROUND_FALCON_A |