| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/08/05 22:47 | flow | patch-triage |
0mArgs:null Results: {
"EnableConfigs": [
"E1000E"
],
"FocusSymbols": [
"e1000_alloc_rx_buffers",
"e1000_clean_rx_irq"
],
"Reasoning": "The patch modifies the RX path of the e1000e driver (e1000_alloc_rx_buffers and e1000_clean_rx_irq), which is fully emulated in QEMU and reachable. It also modifies i40e, ice, and igc drivers, but those are not natively emulated in standard QEMU. We focus on the e1000e changes.",
"WorthFuzzing": true
} |
| 1/1 | 2026/08/05 22:47 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit b6f0af5c9437f4164b02c6118aa0d784455dab12\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Wed Aug 5 22:47:25 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/Documentation/networking/device_drivers/ethernet/intel/ice.rst b/Documentation/networking/device_drivers/ethernet/intel/ice.rst\nindex 0bca293cf9cb7..82b3ccc7027ea 100644\n--- a/Documentation/networking/device_drivers/ethernet/intel/ice.rst\n+++ b/Documentation/networking/device_drivers/ethernet/intel/ice.rst\n@@ -941,6 +941,86 @@ To see input signal on those PTP pins, you need to configure DPLL properly.\n Output signal is only visible on DPLL and to send it to the board SMA/U.FL pins,\n DPLL output pins have to be manually configured.\n \n+Unmanaged DPLL Support\n+----------------------\n+Hardware variants of E830 may support an unmanaged DPLL:\n+\n+- Intel(R) Ethernet Network Adapter E830-XXVDA8F for OCP 3.0,\n+\n+- Intel(R) Ethernet Network Adapter E830-XXVDA4F.\n+\n+In the case of the unmanaged DPLL, the configuration is hardcoded within the\n+hardware and firmware, meaning users cannot modify settings. However,\n+users can check the DPLL lock status and obtain configuration information\n+through the Linux DPLL subsystem.\n+\n+When present, the DPLL device locks to an external signal provided through the\n+PCIe/OCP pin. The expected input signal is 1PPS (1 Pulse Per Second) embedded\n+on a 10MHz reference clock.\n+The DPLL produces output:\n+\n+- for MAC (Media Access Control) \u0026 PHY (Physical Layer) clocks,\n+\n+- 1PPS for synchronization of onboard PHC (Precision Hardware Clock) timer.\n+\n+Example output of querying the Linux DPLL subsystem can be found below.\n+\n+.. code-block:: console\n+ :caption: Dumping the DPLL pins\n+\n+ $ \u003cynl\u003e --spec Documentation/netlink/specs/dpll.yaml --dump pin-get\n+ [{'board-label': '1588-TIME_SYNC',\n+ 'capabilities': set(),\n+ 'clock-id': 282574471561216,\n+ 'esync-frequency': 1,\n+ 'esync-frequency-supported': [{'frequency-max': 1, 'frequency-min': 1}],\n+ 'esync-pulse': 25,\n+ 'frequency': 10000000,\n+ 'id': 13,\n+ 'module-name': 'ice',\n+ 'parent-device': [{'direction': 'input',\n+ 'parent-id': 6,\n+ 'state': 'connected'}],\n+ 'phase-adjust-max': 0,\n+ 'phase-adjust-min': 0,\n+ 'type': 'ext'},\n+ {'board-label': 'MAC-PHY-CLK',\n+ 'capabilities': set(),\n+ 'clock-id': 282574471561216,\n+ 'frequency': 156250000,\n+ 'id': 14,\n+ 'module-name': 'ice',\n+ 'parent-device': [{'direction': 'output',\n+ 'parent-id': 6,\n+ 'state': 'connected'}],\n+ 'phase-adjust-max': 0,\n+ 'phase-adjust-min': 0,\n+ 'type': 'synce-eth-port'},\n+ {'board-label': '1588-TIME_REF',\n+ 'capabilities': set(),\n+ 'clock-id': 282574471561216,\n+ 'frequency': 1,\n+ 'id': 15,\n+ 'module-name': 'ice',\n+ 'parent-device': [{'direction': 'output',\n+ 'parent-id': 6,\n+ 'state': 'connected'}],\n+ 'phase-adjust-max': 0,\n+ 'phase-adjust-min': 0,\n+ 'type': 'int-oscillator'}]\n+\n+.. code-block:: console\n+ :caption: Dumping the DPLL devices\n+\n+ $ \u003cynl\u003e --spec Documentation/netlink/specs/dpll.yaml --dump device-get\n+ [{'clock-id': 282574471561216,\n+ 'id': 6,\n+ 'lock-status': 'locked',\n+ 'mode': 'manual',\n+ 'mode-supported': ['manual'],\n+ 'module-name': 'ice',\n+ 'type': 'pps'}]\n+\n GNSS module\n -----------\n Requires kernel compiled with CONFIG_GNSS=y or CONFIG_GNSS=m.\ndiff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c\nindex 844f31ab37ad4..b08bcbdb19d97 100644\n--- a/drivers/net/ethernet/intel/e1000e/netdev.c\n+++ b/drivers/net/ethernet/intel/e1000e/netdev.c\n@@ -675,6 +675,8 @@ static void e1000_alloc_rx_buffers(struct e1000_ring *rx_ring,\n \t\tskb = buffer_info-\u003eskb;\n \t\tif (skb) {\n \t\t\tskb_trim(skb, 0);\n+\t\t\tif (likely(buffer_info-\u003edma))\n+\t\t\t\tgoto write_desc;\n \t\t\tgoto map_skb;\n \t\t}\n \n@@ -692,10 +694,12 @@ static void e1000_alloc_rx_buffers(struct e1000_ring *rx_ring,\n \t\t\t\t\t\t DMA_FROM_DEVICE);\n \t\tif (dma_mapping_error(\u0026pdev-\u003edev, buffer_info-\u003edma)) {\n \t\t\tdev_err(\u0026pdev-\u003edev, \"Rx DMA map failed\\n\");\n+\t\t\tbuffer_info-\u003edma = 0;\n \t\t\tadapter-\u003erx_dma_failed++;\n \t\t\tbreak;\n \t\t}\n \n+write_desc:\n \t\trx_desc = E1000_RX_DESC_EXT(*rx_ring, i);\n \t\trx_desc-\u003eread.buffer_addr = cpu_to_le64(buffer_info-\u003edma);\n \n@@ -953,7 +957,6 @@ static bool e1000_clean_rx_irq(struct e1000_ring *rx_ring, int *work_done,\n \t\tdma_rmb();\t/* read descriptor and rx_buffer_info after status DD */\n \n \t\tskb = buffer_info-\u003eskb;\n-\t\tbuffer_info-\u003eskb = NULL;\n \n \t\tprefetch(skb-\u003edata - NET_IP_ALIGN);\n \n@@ -967,9 +970,6 @@ static bool e1000_clean_rx_irq(struct e1000_ring *rx_ring, int *work_done,\n \n \t\tcleaned = true;\n \t\tcleaned_count++;\n-\t\tdma_unmap_single(\u0026pdev-\u003edev, buffer_info-\u003edma,\n-\t\t\t\t adapter-\u003erx_buffer_len, DMA_FROM_DEVICE);\n-\t\tbuffer_info-\u003edma = 0;\n \n \t\tlength = le16_to_cpu(rx_desc-\u003ewb.upper.length);\n \n@@ -985,8 +985,6 @@ static bool e1000_clean_rx_irq(struct e1000_ring *rx_ring, int *work_done,\n \t\tif (adapter-\u003eflags2 \u0026 FLAG2_IS_DISCARDING) {\n \t\t\t/* All receives must fit into a single buffer */\n \t\t\te_dbg(\"Receive packet consumed multiple buffers\\n\");\n-\t\t\t/* recycle */\n-\t\t\tbuffer_info-\u003eskb = skb;\n \t\t\tif (staterr \u0026 E1000_RXD_STAT_EOP)\n \t\t\t\tadapter-\u003eflags2 \u0026= ~FLAG2_IS_DISCARDING;\n \t\t\tgoto next_desc;\n@@ -994,8 +992,6 @@ static bool e1000_clean_rx_irq(struct e1000_ring *rx_ring, int *work_done,\n \n \t\tif (unlikely((staterr \u0026 E1000_RXDEXT_ERR_FRAME_ERR_MASK) \u0026\u0026\n \t\t\t !(netdev-\u003efeatures \u0026 NETIF_F_RXALL))) {\n-\t\t\t/* recycle */\n-\t\t\tbuffer_info-\u003eskb = skb;\n \t\t\tgoto next_desc;\n \t\t}\n \n@@ -1022,19 +1018,33 @@ static bool e1000_clean_rx_irq(struct e1000_ring *rx_ring, int *work_done,\n \t\t\tstruct sk_buff *new_skb =\n \t\t\t\tnapi_alloc_skb(\u0026adapter-\u003enapi, length);\n \t\t\tif (new_skb) {\n+\t\t\t\tdma_sync_single_for_cpu(\u0026pdev-\u003edev,\n+\t\t\t\t\t\t\tbuffer_info-\u003edma,\n+\t\t\t\t\t\t\tadapter-\u003erx_buffer_len,\n+\t\t\t\t\t\t\tDMA_FROM_DEVICE);\n \t\t\t\tskb_copy_to_linear_data_offset(new_skb,\n \t\t\t\t\t\t\t -NET_IP_ALIGN,\n \t\t\t\t\t\t\t (skb-\u003edata -\n \t\t\t\t\t\t\t\tNET_IP_ALIGN),\n \t\t\t\t\t\t\t (length +\n \t\t\t\t\t\t\t\tNET_IP_ALIGN));\n-\t\t\t\t/* save the skb in buffer_info as good */\n-\t\t\t\tbuffer_info-\u003eskb = skb;\n+\t\t\t\tdma_sync_single_for_device(\u0026pdev-\u003edev,\n+\t\t\t\t\t\t\t buffer_info-\u003edma,\n+\t\t\t\t\t\t\t adapter-\u003erx_buffer_len,\n+\t\t\t\t\t\t\t DMA_FROM_DEVICE);\n \t\t\t\tskb = new_skb;\n+\t\t\t\tgoto copybreak_done;\n \t\t\t}\n \t\t\t/* else just continue with the old one */\n \t\t}\n-\t\t/* end copybreak code */\n+\n+\t\tbuffer_info-\u003eskb = NULL;\n+\t\tdma_unmap_single(\u0026pdev-\u003edev, buffer_info-\u003edma,\n+\t\t\t\t adapter-\u003erx_buffer_len,\n+\t\t\t\t DMA_FROM_DEVICE);\n+\t\tbuffer_info-\u003edma = 0;\n+\n+copybreak_done:\n \t\tskb_put(skb, length);\n \n \t\t/* Receive Checksum Offload */\ndiff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c\nindex 0cd0e5597c909..abbc71e815ae3 100644\n--- a/drivers/net/ethernet/intel/i40e/i40e_main.c\n+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c\n@@ -4,6 +4,7 @@\n #include \u003cgenerated/utsrelease.h\u003e\n #include \u003clinux/crash_dump.h\u003e\n #include \u003clinux/net/intel/libie/pctype.h\u003e\n+#include \u003clinux/net/intel/libie/rx.h\u003e\n #include \u003clinux/if_bridge.h\u003e\n #include \u003clinux/if_macvlan.h\u003e\n #include \u003clinux/module.h\u003e\n@@ -2411,10 +2412,12 @@ void i40e_aqc_add_filters(struct i40e_vsi *vsi, const char *vsi_name,\n \n \tif (fcnt != num_add) {\n \t\tif (vsi-\u003etype == I40E_VSI_MAIN) {\n-\t\t\tset_bit(__I40E_VSI_OVERFLOW_PROMISC, vsi-\u003estate);\n-\t\t\tdev_warn(\u0026vsi-\u003eback-\u003epdev-\u003edev,\n-\t\t\t\t \"Error %s adding RX filters on %s, promiscuous mode forced on\\n\",\n-\t\t\t\t libie_aq_str(aq_status), vsi_name);\n+\t\t\tif (!test_and_set_bit(__I40E_VSI_OVERFLOW_PROMISC,\n+\t\t\t\t\t vsi-\u003estate)) {\n+\t\t\t\tdev_warn(\u0026vsi-\u003eback-\u003epdev-\u003edev,\n+\t\t\t\t\t \"Error %s adding RX filters on %s, promiscuous mode forced on\\n\",\n+\t\t\t\t\t libie_aq_str(aq_status), vsi_name);\n+\t\t\t}\n \t\t} else if (vsi-\u003etype == I40E_VSI_SRIOV ||\n \t\t\t vsi-\u003etype == I40E_VSI_VMDQ1 ||\n \t\t\t vsi-\u003etype == I40E_VSI_VMDQ2) {\n@@ -2464,10 +2467,11 @@ i40e_aqc_broadcast_filter(struct i40e_vsi *vsi, const char *vsi_name,\n \t}\n \n \tif (aq_ret) {\n-\t\tset_bit(__I40E_VSI_OVERFLOW_PROMISC, vsi-\u003estate);\n-\t\tdev_warn(\u0026vsi-\u003eback-\u003epdev-\u003edev,\n-\t\t\t \"Error %s, forcing overflow promiscuous on %s\\n\",\n-\t\t\t libie_aq_str(hw-\u003eaq.asq_last_status), vsi_name);\n+\t\tif (!test_and_set_bit(__I40E_VSI_OVERFLOW_PROMISC, vsi-\u003estate)) {\n+\t\t\tdev_warn(\u0026vsi-\u003eback-\u003epdev-\u003edev,\n+\t\t\t\t \"Error %s, forcing overflow promiscuous on %s\\n\",\n+\t\t\t\t libie_aq_str(hw-\u003eaq.asq_last_status), vsi_name);\n+\t\t}\n \t}\n \n \treturn aq_ret;\n@@ -3622,7 +3626,7 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)\n \t}\n \n skip:\n-\txdp_init_buff(\u0026ring-\u003exdp, xdp_frame_sz, \u0026ring-\u003exdp_rxq);\n+\txdp_init_buff(\u0026ring-\u003exdp_ctx.xdp, xdp_frame_sz, \u0026ring-\u003exdp_rxq);\n \n \trx_ctx.dbuff = DIV_ROUND_UP(ring-\u003erx_buf_len,\n \t\t\t\t BIT_ULL(I40E_RXQ_CTX_DBUFF_SHIFT));\n@@ -13582,6 +13586,53 @@ static int i40e_xdp(struct net_device *dev,\n \t}\n }\n \n+static int i40e_xdp_rx_hash(const struct xdp_md *_ctx, u32 *hash,\n+\t\t\t enum xdp_rss_hash_type *rss_type)\n+{\n+\tconst struct i40e_xdp_buff *ctx = (const void *)_ctx;\n+\tconst union i40e_rx_desc *desc = ctx-\u003edesc;\n+\tstruct libeth_rx_pt rx_ptype;\n+\tu8 raw_rx_ptype;\n+\tu64 status;\n+\n+\tstatus = le64_to_cpu(desc-\u003ewb.qword1.status_error_len);\n+\traw_rx_ptype = FIELD_GET(I40E_RXD_QW1_PTYPE_MASK, status);\n+\trx_ptype = libie_rx_pt_parse(raw_rx_ptype);\n+\n+\tif (!libeth_rx_pt_has_hash(ctx-\u003exdp.rxq-\u003edev, rx_ptype) ||\n+\t FIELD_GET(I40E_RX_DESC_STATUS_FLTSTAT_MASK, status) !=\n+\t\t I40E_RX_DESC_FLTSTAT_RSS_HASH)\n+\t\treturn -ENODATA;\n+\n+\t*hash = le32_to_cpu(desc-\u003ewb.qword0.hi_dword.rss);\n+\t*rss_type = rx_ptype.hash_type;\n+\n+\treturn 0;\n+}\n+\n+static int i40e_xdp_rx_vlan_tag(const struct xdp_md *_ctx, __be16 *vlan_proto,\n+\t\t\t\tu16 *vlan_tci)\n+{\n+\tconst struct i40e_xdp_buff *ctx = (const void *)_ctx;\n+\tconst union i40e_rx_desc *desc = ctx-\u003edesc;\n+\tu64 status;\n+\n+\tstatus = le64_to_cpu(desc-\u003ewb.qword1.status_error_len);\n+\n+\tif (!(status \u0026 BIT(I40E_RX_DESC_STATUS_L2TAG1P_SHIFT)))\n+\t\treturn -ENODATA;\n+\n+\t*vlan_proto = cpu_to_be16(ETH_P_8021Q);\n+\t*vlan_tci = le16_to_cpu(desc-\u003ewb.qword0.lo_dword.l2tag1);\n+\n+\treturn 0;\n+}\n+\n+static const struct xdp_metadata_ops i40e_xdp_metadata_ops = {\n+\t.xmo_rx_hash\t\t= i40e_xdp_rx_hash,\n+\t.xmo_rx_vlan_tag\t= i40e_xdp_rx_vlan_tag,\n+};\n+\n static const struct net_device_ops i40e_netdev_ops = {\n \t.ndo_open\t\t= i40e_open,\n \t.ndo_stop\t\t= i40e_close,\n@@ -13784,6 +13835,7 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)\n \ti40e_vsi_config_netdev_tc(vsi, vsi-\u003etc_config.enabled_tc);\n \n \tnetdev-\u003enetdev_ops = \u0026i40e_netdev_ops;\n+\tnetdev-\u003exdp_metadata_ops = \u0026i40e_xdp_metadata_ops;\n \tnetdev-\u003ewatchdog_timeo = 5 * HZ;\n \ti40e_set_ethtool_ops(netdev);\n \ndiff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c\nindex ef5e657816f00..7f68adb5109b0 100644\n--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c\n+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c\n@@ -2438,10 +2438,11 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget,\n \t\t\t unsigned int *rx_cleaned)\n {\n \tunsigned int total_rx_bytes = 0, total_rx_packets = 0;\n+\tstruct i40e_xdp_buff *xdp_ctx = \u0026rx_ring-\u003exdp_ctx;\n \tu16 cleaned_count = I40E_DESC_UNUSED(rx_ring);\n \tu16 clean_threshold = rx_ring-\u003ecount / 2;\n \tunsigned int offset = rx_ring-\u003erx_offset;\n-\tstruct xdp_buff *xdp = \u0026rx_ring-\u003exdp;\n+\tstruct xdp_buff *xdp = \u0026xdp_ctx-\u003exdp;\n \tunsigned int xdp_xmit = 0;\n \tstruct bpf_prog *xdp_prog;\n \tbool failure = false;\n@@ -2530,6 +2531,8 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget,\n \t\tif (neop)\n \t\t\tcontinue;\n \n+\t\txdp_ctx-\u003edesc = rx_desc;\n+\n \t\txdp_res = i40e_run_xdp(rx_ring, xdp, xdp_prog);\n \n \t\tif (xdp_res) {\ndiff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.h b/drivers/net/ethernet/intel/i40e/i40e_txrx.h\nindex 1e5fd63d47f47..bb741ff3e5f2c 100644\n--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.h\n+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.h\n@@ -283,6 +283,11 @@ struct i40e_rx_buffer {\n \t__u32 page_count;\n };\n \n+struct i40e_xdp_buff {\n+\tstruct xdp_buff xdp;\n+\tconst union i40e_rx_desc *desc;\n+};\n+\n struct i40e_queue_stats {\n \tu64 packets;\n \tu64 bytes;\n@@ -345,7 +350,7 @@ struct i40e_ring {\n \t * and to resume packet building for this ring in the next call to\n \t * i40e_clean_rx_ring_irq().\n \t */\n-\tstruct xdp_buff xdp;\n+\tstruct i40e_xdp_buff xdp_ctx;\n \n \t/* Next descriptor to be processed; next_to_clean is updated only on\n \t * processing EOP descriptor\ndiff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h\nindex ed8bbdb586da9..16a65c6e51537 100644\n--- a/drivers/net/ethernet/intel/i40e/i40e_type.h\n+++ b/drivers/net/ethernet/intel/i40e/i40e_type.h\n@@ -4,6 +4,7 @@\n #ifndef _I40E_TYPE_H_\n #define _I40E_TYPE_H_\n \n+#include \u003clinux/bits.h\u003e\n #include \u003cuapi/linux/if_ether.h\u003e\n #include \"i40e_adminq.h\"\n #include \"i40e_hmc.h\"\n@@ -699,6 +700,10 @@ enum i40e_rx_desc_status_bits {\n \tI40E_RX_DESC_STATUS_LAST /* this entry must be last!!! */\n };\n \n+#define I40E_RX_DESC_STATUS_FLTSTAT_MASK \\\n+\tGENMASK_ULL(I40E_RX_DESC_STATUS_FLTSTAT_SHIFT + 1, \\\n+\t\t I40E_RX_DESC_STATUS_FLTSTAT_SHIFT)\n+\n #define I40E_RXD_QW1_STATUS_SHIFT\t0\n #define I40E_RXD_QW1_STATUS_MASK\t((BIT(I40E_RX_DESC_STATUS_LAST) - 1) \\\n \t\t\t\t\t \u003c\u003c I40E_RXD_QW1_STATUS_SHIFT)\ndiff --git a/drivers/net/ethernet/intel/i40e/i40e_xsk.c b/drivers/net/ethernet/intel/i40e/i40e_xsk.c\nindex 9f47388eaba53..51a05ce4c7ce8 100644\n--- a/drivers/net/ethernet/intel/i40e/i40e_xsk.c\n+++ b/drivers/net/ethernet/intel/i40e/i40e_xsk.c\n@@ -246,6 +246,8 @@ bool i40e_alloc_rx_buffers_zc(struct i40e_ring *rx_ring, u16 count)\n \tu32 nb_buffs, i;\n \tdma_addr_t dma;\n \n+\tXSK_CHECK_PRIV_TYPE(struct i40e_xdp_buff);\n+\n \trx_desc = I40E_RX_DESC(rx_ring, ntu);\n \txdp = i40e_rx_bi(rx_ring, ntu);\n \n@@ -396,6 +398,14 @@ static void i40e_handle_xdp_result_zc(struct i40e_ring *rx_ring,\n \tWARN_ON_ONCE(1);\n }\n \n+static struct i40e_xdp_buff *xsk_buff_to_i40e_ctx(struct xdp_buff *xdp)\n+{\n+\t/* xdp_buff pointer used by ZC code path is allocated as xdp_buff_xsk.\n+\t * i40e_xdp_buff private fields overlap with xdp_buff_xsk-\u003ecb.\n+\t */\n+\treturn (struct i40e_xdp_buff *)xdp;\n+}\n+\n /**\n * i40e_clean_rx_irq_zc - Consumes Rx packets from the hardware ring\n * @rx_ring: Rx ring\n@@ -472,6 +482,8 @@ int i40e_clean_rx_irq_zc(struct i40e_ring *rx_ring, int budget)\n \t\tif (i40e_is_non_eop(rx_ring, rx_desc))\n \t\t\tcontinue;\n \n+\t\txsk_buff_to_i40e_ctx(first)-\u003edesc = rx_desc;\n+\n \t\txdp_res = i40e_run_xdp_zc(rx_ring, first, xdp_prog);\n \t\ti40e_handle_xdp_result_zc(rx_ring, first, rx_desc, \u0026rx_packets,\n \t\t\t\t\t \u0026rx_bytes, xdp_res, \u0026failure);\ndiff --git a/drivers/net/ethernet/intel/ice/devlink/health.c b/drivers/net/ethernet/intel/ice/devlink/health.c\nindex 8e9a8a8178d48..a83eb9f104c83 100644\n--- a/drivers/net/ethernet/intel/ice/devlink/health.c\n+++ b/drivers/net/ethernet/intel/ice/devlink/health.c\n@@ -101,6 +101,8 @@ static const struct ice_health_status ice_health_status_lookup[] = {\n \t\t\"Supplied MIB file is invalid. DCB reverted to default configuration.\",\n \t\t\"Disable FW-LLDP and check DCBx system configuration.\",\n \t\t{ice_port_number_label, \"MIB ID\"}},\n+\t{ICE_AQC_HEALTH_STATUS_INFO_LOSS_OF_LOCK, \"Local DPLL lock status\",\n+\t\tNULL,},\n };\n \n static int ice_health_status_lookup_compare(const void *a, const void *b)\n@@ -242,6 +244,10 @@ void ice_process_health_status_event(struct ice_pf *pf, struct ice_rq_event_info\n \t\t\t\tpf-\u003ehealth_reporters.fw_status = *health_info;\n \t\t\t\tdevlink_health_report(pf-\u003ehealth_reporters.fw,\n \t\t\t\t\t\t \"FW syndrome reported\", NULL);\n+\t\t\t\tif (status_code == ICE_AQC_HEALTH_STATUS_INFO_LOSS_OF_LOCK \u0026\u0026\n+\t\t\t\t test_bit(ICE_FLAG_DPLL, pf-\u003eflags) \u0026\u0026\n+\t\t\t\t pf-\u003edplls.unmanaged)\n+\t\t\t\t\tice_dpll_lock_state_set_unmanaged(pf, health_info, true);\n \t\t\t\tbreak;\n \t\t\tcase ICE_AQC_HEALTH_STATUS_PF:\n \t\t\tcase ICE_AQC_HEALTH_STATUS_PORT:\ndiff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h\nindex 42878abac9eb1..848ac58342979 100644\n--- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h\n+++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h\n@@ -1500,6 +1500,7 @@ struct ice_aqc_get_link_topo {\n #define ICE_AQC_GET_LINK_TOPO_NODE_NR_PCA9575\t\t0x21\n #define ICE_AQC_GET_LINK_TOPO_NODE_NR_ZL30632_80032\t0x24\n #define ICE_AQC_GET_LINK_TOPO_NODE_NR_SI5383_5384\t0x25\n+#define ICE_AQC_GET_LINK_TOPO_NODE_NR_ZL80640\t\t0x27\n #define ICE_AQC_GET_LINK_TOPO_NODE_NR_E822_PHY\t\t0x30\n #define ICE_AQC_GET_LINK_TOPO_NODE_NR_C827\t\t0x31\n #define ICE_AQC_GET_LINK_TOPO_NODE_NR_GEN_CLK_MUX\t0x47\n@@ -2483,11 +2484,14 @@ enum ice_aqc_health_status {\n \tICE_AQC_HEALTH_STATUS_ERR_BMC_RESET\t\t\t= 0x50B,\n \tICE_AQC_HEALTH_STATUS_ERR_LAST_MNG_FAIL\t\t\t= 0x50C,\n \tICE_AQC_HEALTH_STATUS_ERR_RESOURCE_ALLOC_FAIL\t\t= 0x50D,\n+\tICE_AQC_HEALTH_STATUS_INFO_LOSS_OF_LOCK\t\t\t= 0x601,\n \tICE_AQC_HEALTH_STATUS_ERR_FW_LOOP\t\t\t= 0x1000,\n \tICE_AQC_HEALTH_STATUS_ERR_FW_PFR_FAIL\t\t\t= 0x1001,\n \tICE_AQC_HEALTH_STATUS_ERR_LAST_FAIL_AQ\t\t\t= 0x1002,\n };\n \n+#define ICE_AQC_HEALTH_STATUS_CODE_NUM\t\t\t\t64\n+\n /* Get Health Status (indirect 0xFF22) */\n struct ice_aqc_get_health_status {\n \t__le16 health_status_count;\n@@ -2514,6 +2518,13 @@ struct ice_aqc_health_status_elem {\n \t__le32 internal_data2;\n };\n \n+/* Get Health Status response buffer entry, (0xFF21)\n+ * repeated per reported health status\n+ */\n+struct ice_aqc_health_status_supp_elem {\n+\t__le16 health_status_code;\n+};\n+\n /* Admin Queue command opcodes */\n enum ice_adminq_opc {\n \t/* AQ commands */\n@@ -2677,6 +2688,7 @@ enum ice_adminq_opc {\n \n \t/* System Diagnostic commands */\n \tice_aqc_opc_set_health_status_cfg\t\t= 0xFF20,\n+\tice_aqc_opc_get_supported_health_status_codes\t= 0xFF21,\n \tice_aqc_opc_get_health_status\t\t\t= 0xFF22,\n \n \t/* FW Logging Commands */\ndiff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c\nindex ef1ce106f81b5..2c72ed18695c5 100644\n--- a/drivers/net/ethernet/intel/ice/ice_common.c\n+++ b/drivers/net/ethernet/intel/ice/ice_common.c\n@@ -3048,6 +3048,29 @@ bool ice_is_cgu_in_netlist(struct ice_hw *hw)\n \treturn false;\n }\n \n+/**\n+ * ice_is_unmanaged_cgu_in_netlist - check for unmanaged CGU presence\n+ * @hw: pointer to the hw struct\n+ *\n+ * Check if the unmanaged Clock Generation Unit (CGU) device is present in the netlist.\n+ * Save the CGU part number in the hw structure for later use.\n+ * Return:\n+ * * true - unmanaged cgu is present\n+ * * false - unmanaged cgu is not present\n+ */\n+bool ice_is_unmanaged_cgu_in_netlist(struct ice_hw *hw)\n+{\n+\tif (!ice_find_netlist_node(hw, ICE_AQC_LINK_TOPO_NODE_TYPE_CLK_CTRL,\n+\t\t\t\t ICE_AQC_LINK_TOPO_NODE_CTX_GLOBAL,\n+\t\t\t\t ICE_AQC_GET_LINK_TOPO_NODE_NR_ZL80640,\n+\t\t\t\t NULL)) {\n+\t\thw-\u003ecgu_part_number = ICE_AQC_GET_LINK_TOPO_NODE_NR_ZL80640;\n+\t\treturn true;\n+\t}\n+\n+\treturn false;\n+}\n+\n /**\n * ice_is_gps_in_netlist\n * @hw: pointer to the hw struct\n@@ -6312,6 +6335,119 @@ bool ice_is_fw_health_report_supported(struct ice_hw *hw)\n \t\t\t\t ICE_FW_API_HEALTH_REPORT_PATCH);\n }\n \n+/**\n+ * ice_aq_get_health_status_supported - get supported health status codes\n+ * @hw: pointer to the HW struct\n+ * @buff: pointer to buffer where health status elements will be stored\n+ * @num: number of health status elements buffer can hold\n+ *\n+ * Return:\n+ * * 0 - success,\n+ * * negative - AQ error code.\n+ */\n+static int\n+ice_aq_get_health_status_supported(struct ice_hw *hw,\n+\t\t\t\t struct ice_aqc_health_status_supp_elem *buff,\n+\t\t\t\t int num)\n+{\n+\tu16 code = ice_aqc_opc_get_supported_health_status_codes;\n+\tstruct libie_aq_desc desc;\n+\n+\tice_fill_dflt_direct_cmd_desc(\u0026desc, code);\n+\n+\treturn ice_aq_send_cmd(hw, \u0026desc, buff, num * sizeof(*buff), NULL);\n+}\n+\n+/**\n+ * ice_aq_get_health_status - get current health status array from the firmware\n+ * @hw: pointer to the HW struct\n+ * @buff: pointer to buffer where health status elements will be stored\n+ * @num: number of health status elements buffer can hold\n+ *\n+ * Return:\n+ * * 0 - success,\n+ * * negative - AQ error code.\n+ */\n+int ice_aq_get_health_status(struct ice_hw *hw,\n+\t\t\t struct ice_aqc_health_status_elem *buff, int num)\n+{\n+\tstruct libie_aq_desc desc;\n+\n+\tice_fill_dflt_direct_cmd_desc(\u0026desc,\n+\t\t\t\t ice_aqc_opc_get_health_status);\n+\n+\treturn ice_aq_send_cmd(hw, \u0026desc, buff, num * sizeof(*buff), NULL);\n+}\n+\n+/**\n+ * ice_is_health_status_code_supported - check if health status code is supported\n+ * @hw: pointer to the hardware structure\n+ * @code: health status code to check\n+ * @supported: pointer to boolean result\n+ *\n+ * Return: 0 on success, negative error code otherwise\n+ */\n+int ice_is_health_status_code_supported(struct ice_hw *hw, u16 code,\n+\t\t\t\t\tbool *supported)\n+{\n+\tconst int BUFF_SIZE = ICE_AQC_HEALTH_STATUS_CODE_NUM;\n+\tstruct ice_aqc_health_status_supp_elem *buff;\n+\tint ret;\n+\n+\t*supported = false;\n+\tbuff = kzalloc_objs(*buff, BUFF_SIZE);\n+\tif (!buff)\n+\t\treturn -ENOMEM;\n+\tret = ice_aq_get_health_status_supported(hw, buff, BUFF_SIZE);\n+\tif (ret)\n+\t\tgoto free_buff;\n+\tfor (int i = 0; i \u003c BUFF_SIZE \u0026\u0026 buff[i].health_status_code; i++)\n+\t\tif (le16_to_cpu(buff[i].health_status_code) == code) {\n+\t\t\t*supported = true;\n+\t\t\tbreak;\n+\t\t}\n+\n+free_buff:\n+\tkfree(buff);\n+\treturn ret;\n+}\n+\n+/**\n+ * ice_get_last_health_status_code - get last health status for given code\n+ * @hw: pointer to the hardware structure\n+ * @out: pointer to the health status struct to be filled\n+ * @code: health status code to check\n+ *\n+ * Return: 0 on success, negative error code otherwise\n+ */\n+int ice_get_last_health_status_code(struct ice_hw *hw,\n+\t\t\t\t struct ice_aqc_health_status_elem *out,\n+\t\t\t\t u16 code)\n+{\n+\tconst int BUFF_SIZE = ICE_AQC_HEALTH_STATUS_CODE_NUM;\n+\tstruct ice_aqc_health_status_elem *buff;\n+\tint ret, last_status = -1;\n+\n+\tbuff = kzalloc_objs(*buff, BUFF_SIZE);\n+\tif (!buff)\n+\t\treturn -ENOMEM;\n+\tret = ice_aq_get_health_status(hw, buff, BUFF_SIZE);\n+\tif (ret)\n+\t\tgoto free_buff;\n+\tfor (int i = 0; i \u003c BUFF_SIZE \u0026\u0026 buff[i].health_status_code; i++)\n+\t\tif (le16_to_cpu(buff[i].health_status_code) == code)\n+\t\t\tlast_status = i;\n+\n+\tif (last_status \u003e= 0)\n+\t\tmemcpy(out, \u0026buff[last_status], sizeof(*out));\n+\telse\n+\t\tmemset(out, 0, sizeof(*out));\n+\n+free_buff:\n+\tkfree(buff);\n+\treturn ret;\n+}\n+\n /**\n * ice_aq_set_health_status_cfg - Configure FW health events\n * @hw: pointer to the HW struct\ndiff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h\nindex 9f53442121955..51036188cd396 100644\n--- a/drivers/net/ethernet/intel/ice/ice_common.h\n+++ b/drivers/net/ethernet/intel/ice/ice_common.h\n@@ -162,6 +162,7 @@ ice_aq_get_phy_caps(struct ice_port_info *pi, bool qual_mods, u8 report_mode,\n bool ice_is_phy_rclk_in_netlist(struct ice_hw *hw);\n bool ice_is_clock_mux_in_netlist(struct ice_hw *hw);\n bool ice_is_cgu_in_netlist(struct ice_hw *hw);\n+bool ice_is_unmanaged_cgu_in_netlist(struct ice_hw *hw);\n bool ice_is_gps_in_netlist(struct ice_hw *hw);\n int\n ice_aq_get_netlist_node(struct ice_hw *hw, struct ice_aqc_get_link_topo *cmd,\n@@ -188,6 +189,13 @@ ice_get_link_default_override(struct ice_link_default_override_tlv *ldo,\n \t\t\t struct ice_port_info *pi);\n bool ice_is_phy_caps_an_enabled(struct ice_aqc_get_phy_caps_data *caps);\n bool ice_is_fw_health_report_supported(struct ice_hw *hw);\n+int ice_aq_get_health_status(struct ice_hw *hw,\n+\t\t\t struct ice_aqc_health_status_elem *buff, int num);\n+int ice_is_health_status_code_supported(struct ice_hw *hw, u16 code,\n+\t\t\t\t\tbool *supported);\n+int ice_get_last_health_status_code(struct ice_hw *hw,\n+\t\t\t\t struct ice_aqc_health_status_elem *out,\n+\t\t\t\t u16 code);\n int ice_aq_set_health_status_cfg(struct ice_hw *hw, u8 event_source);\n int ice_aq_get_phy_equalization(struct ice_hw *hw, u16 data_in, u16 op_code,\n \t\t\t\tu8 serdes_num, int *output);\ndiff --git a/drivers/net/ethernet/intel/ice/ice_dcb_nl.c b/drivers/net/ethernet/intel/ice/ice_dcb_nl.c\nindex a10c1c8d86977..bb5cc0a2ba69b 100644\n--- a/drivers/net/ethernet/intel/ice/ice_dcb_nl.c\n+++ b/drivers/net/ethernet/intel/ice/ice_dcb_nl.c\n@@ -872,7 +872,7 @@ static int ice_dcbnl_delapp(struct net_device *netdev, struct dcb_app *app)\n \tint ret = 0;\n \n \tif (pf-\u003edcbx_cap \u0026 DCB_CAP_DCBX_LLD_MANAGED) {\n-\t\tnetdev_err(netdev, \"can't delete DSCP netlink app when FW DCB agent is active\\n\");\n+\t\tnetdev_dbg(netdev, \"can't delete DSCP netlink app when FW DCB agent is active\\n\");\n \t\treturn -EINVAL;\n \t}\n \ndiff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c\nindex 85a74cd6ea1f3..1ca137f67dd48 100644\n--- a/drivers/net/ethernet/intel/ice/ice_dpll.c\n+++ b/drivers/net/ethernet/intel/ice/ice_dpll.c\n@@ -19,6 +19,8 @@\n #define ICE_DPLL_SW_PIN_INPUT_BASE_SFP\t\t4\n #define ICE_DPLL_SW_PIN_INPUT_BASE_QSFP\t\t6\n #define ICE_DPLL_SW_PIN_OUTPUT_BASE\t\t0\n+#define ICE_DPLL_HEALTH_STATUS_LOCKED\t\t1\n+#define ICE_DPLL_HEALTH_STATUS_UNLOCKED\t\t0\n \n #define E825_RCLK_PARENT_0_PIN_IDX\t\t0\n #define E825_RCLK_PARENT_1_PIN_IDX\t\t1\n@@ -89,6 +91,10 @@ static const struct dpll_pin_frequency ice_esync_range[] = {\n \tDPLL_PIN_FREQUENCY_RANGE(0, DPLL_PIN_FREQUENCY_1_HZ),\n };\n \n+static const struct dpll_pin_frequency ice_esync_range_unmanaged[] = {\n+\tDPLL_PIN_FREQUENCY_1PPS,\n+};\n+\n /**\n * ice_dpll_is_sw_pin - check if given pin shall be controlled by SW\n * @pf: private board structure\n@@ -1098,9 +1104,11 @@ ice_dpll_pin_state_get(const struct dpll_pin *pin, void *pin_priv,\n \t\treturn -EBUSY;\n \n \tmutex_lock(\u0026pf-\u003edplls.lock);\n-\tret = ice_dpll_pin_state_update(pf, p, pin_type, extack);\n-\tif (ret)\n-\t\tgoto unlock;\n+\tif (!pf-\u003edplls.unmanaged) {\n+\t\tret = ice_dpll_pin_state_update(pf, p, pin_type, extack);\n+\t\tif (ret)\n+\t\t\tgoto unlock;\n+\t}\n \tif (pin_type == ICE_DPLL_PIN_TYPE_INPUT ||\n \t pin_type == ICE_DPLL_PIN_TYPE_OUTPUT)\n \t\t*state = p-\u003estate[d-\u003edpll_idx];\n@@ -2243,9 +2251,14 @@ ice_dpll_input_esync_get(const struct dpll_pin *pin, void *pin_priv,\n \t\tmutex_unlock(\u0026pf-\u003edplls.lock);\n \t\treturn -EOPNOTSUPP;\n \t}\n-\tesync-\u003erange = ice_esync_range;\n-\tesync-\u003erange_num = ARRAY_SIZE(ice_esync_range);\n-\tif (p-\u003eflags[0] \u0026 ICE_AQC_GET_CGU_IN_CFG_FLG2_ESYNC_EN) {\n+\tif (pf-\u003edplls.unmanaged) {\n+\t\tesync-\u003erange = ice_esync_range_unmanaged;\n+\t\tesync-\u003erange_num = ARRAY_SIZE(ice_esync_range_unmanaged);\n+\t} else {\n+\t\tesync-\u003erange = ice_esync_range;\n+\t\tesync-\u003erange_num = ARRAY_SIZE(ice_esync_range);\n+\t}\n+\tif (p-\u003eflags[0] \u0026 ICE_DPLL_IN_ESYNC_ENABLED) {\n \t\tesync-\u003efreq = DPLL_PIN_FREQUENCY_1_HZ;\n \t\tesync-\u003epulse = ICE_DPLL_PIN_ESYNC_PULSE_HIGH_PERCENT;\n \t} else {\n@@ -2876,6 +2889,19 @@ static const struct dpll_pin_ops ice_dpll_output_ops = {\n \t.esync_get = ice_dpll_output_esync_get,\n };\n \n+static const struct dpll_pin_ops ice_dpll_input_unmanaged_ops = {\n+\t.frequency_get = ice_dpll_input_frequency_get,\n+\t.direction_get = ice_dpll_input_direction,\n+\t.state_on_dpll_get = ice_dpll_input_state_get,\n+\t.esync_get = ice_dpll_input_esync_get,\n+};\n+\n+static const struct dpll_pin_ops ice_dpll_output_unmanaged_ops = {\n+\t.frequency_get = ice_dpll_output_frequency_get,\n+\t.direction_get = ice_dpll_output_direction,\n+\t.state_on_dpll_get = ice_dpll_output_state_get,\n+};\n+\n static const struct dpll_device_ops ice_dpll_ops = {\n \t.lock_status_get = ice_dpll_lock_status_get,\n \t.mode_get = ice_dpll_mode_get,\n@@ -3439,8 +3465,10 @@ ice_dpll_deinit_direct_pins(struct ice_pf *pf, bool cgu,\n \t\t\t struct dpll_device *second)\n {\n \tif (cgu) {\n-\t\tice_dpll_unregister_pins(first, pins, ops, count);\n-\t\tice_dpll_unregister_pins(second, pins, ops, count);\n+\t\tif (first)\n+\t\t\tice_dpll_unregister_pins(first, pins, ops, count);\n+\t\tif (second)\n+\t\t\tice_dpll_unregister_pins(second, pins, ops, count);\n \t}\n \tice_dpll_release_pins(pins, count);\n }\n@@ -3472,12 +3500,15 @@ ice_dpll_init_direct_pins(struct ice_pf *pf, bool cgu,\n \tint ret;\n \n \tret = ice_dpll_get_pins(pf, pins, start_idx, count, pf-\u003edplls.clock_id);\n-\tif (ret)\n+\tif (!cgu || ret)\n \t\treturn ret;\n-\tif (cgu) {\n+\n+\tif (first) {\n \t\tret = ice_dpll_register_pins(first, pins, ops, count);\n \t\tif (ret)\n \t\t\tgoto release_pins;\n+\t}\n+\tif (second) {\n \t\tret = ice_dpll_register_pins(second, pins, ops, count);\n \t\tif (ret)\n \t\t\tgoto unregister_first;\n@@ -3486,7 +3517,8 @@ ice_dpll_init_direct_pins(struct ice_pf *pf, bool cgu,\n \treturn 0;\n \n unregister_first:\n-\tice_dpll_unregister_pins(first, pins, ops, count);\n+\tif (first)\n+\t\tice_dpll_unregister_pins(first, pins, ops, count);\n release_pins:\n \tice_dpll_release_pins(pins, count);\n \treturn ret;\n@@ -3824,6 +3856,18 @@ static void ice_dpll_deinit_pins(struct ice_pf *pf, bool cgu)\n \tstruct ice_dpll *de = \u0026d-\u003eeec;\n \tstruct ice_dpll *dp = \u0026d-\u003epps;\n \n+\tif (d-\u003eunmanaged) {\n+\t\tice_dpll_unregister_pins(dp-\u003edpll, inputs,\n+\t\t\t\t\t \u0026ice_dpll_input_unmanaged_ops,\n+\t\t\t\t\t num_inputs);\n+\t\tice_dpll_unregister_pins(dp-\u003edpll, outputs,\n+\t\t\t\t\t \u0026ice_dpll_output_unmanaged_ops,\n+\t\t\t\t\t num_outputs);\n+\t\tice_dpll_release_pins(inputs, num_inputs);\n+\t\tice_dpll_release_pins(outputs, num_outputs);\n+\t\treturn;\n+\t}\n+\n \tice_dpll_deinit_rclk_pin(pf);\n \tif (pf-\u003ehw.mac_type == ICE_MAC_GENERIC_3K_E825) {\n \t\tice_dpll_deinit_txclk_pins(pf);\n@@ -4082,23 +4126,29 @@ static int ice_dpll_init_pins(struct ice_pf *pf, bool cgu)\n \tconst struct dpll_pin_ops *input_ops;\n \tint ret, count;\n \n-\tinput_ops = \u0026ice_dpll_input_ops;\n-\toutput_ops = \u0026ice_dpll_output_ops;\n+\tif (!pf-\u003edplls.unmanaged) {\n+\t\tinput_ops = \u0026ice_dpll_input_ops;\n+\t\toutput_ops = \u0026ice_dpll_output_ops;\n+\t} else {\n+\t\tinput_ops = \u0026ice_dpll_input_unmanaged_ops;\n+\t\toutput_ops = \u0026ice_dpll_output_unmanaged_ops;\n+\t}\n \n \tret = ice_dpll_init_direct_pins(pf, cgu, pf-\u003edplls.inputs, 0,\n \t\t\t\t\tpf-\u003edplls.num_inputs, input_ops,\n-\t\t\t\t\tpf-\u003edplls.eec.dpll,\n-\t\t\t\t\tpf-\u003edplls.pps.dpll);\n+\t\t\t\t\tpf-\u003edplls.eec.dpll, pf-\u003edplls.pps.dpll);\n \tif (ret)\n \t\treturn ret;\n \tcount = pf-\u003edplls.num_inputs;\n-\tif (cgu) {\n+\tif (cgu || pf-\u003edplls.unmanaged) {\n \t\tret = ice_dpll_init_direct_pins(pf, cgu, pf-\u003edplls.outputs,\n \t\t\t\t\t\tcount, pf-\u003edplls.num_outputs,\n \t\t\t\t\t\toutput_ops, pf-\u003edplls.eec.dpll,\n \t\t\t\t\t\tpf-\u003edplls.pps.dpll);\n \t\tif (ret)\n \t\t\tgoto deinit_inputs;\n+\t\tif (pf-\u003edplls.unmanaged)\n+\t\t\treturn 0;\n \t\tcount += pf-\u003edplls.num_outputs;\n \t\tif (!pf-\u003edplls.generic) {\n \t\t\tret = ice_dpll_init_direct_pins(pf, cgu, pf-\u003edplls.sma,\n@@ -4206,12 +4256,13 @@ ice_dpll_init_dpll(struct ice_pf *pf, struct ice_dpll *d, bool cgu,\n \t\treturn ret;\n \t}\n \td-\u003epf = pf;\n-\tif (cgu || pf-\u003ehw.mac_type == ICE_MAC_GENERIC_3K_E825) {\n+\tif (cgu || pf-\u003edplls.unmanaged ||\n+\t pf-\u003ehw.mac_type == ICE_MAC_GENERIC_3K_E825) {\n \t\tconst struct dpll_device_ops *ops = \u0026ice_dpll_ops;\n \n \t\tif (type == DPLL_TYPE_PPS \u0026\u0026 ice_dpll_is_pps_phase_monitor(pf))\n \t\t\tops = \u0026ice_dpll_pom_ops;\n-\t\tif (cgu)\n+\t\tif (cgu \u0026\u0026 !pf-\u003edplls.unmanaged)\n \t\t\tice_dpll_update_state(pf, d, true);\n \t\tret = dpll_device_register(d-\u003edpll, type, ops, d);\n \t\tif (ret) {\n@@ -4239,6 +4290,33 @@ static void ice_dpll_deinit_worker(struct ice_pf *pf)\n \tkthread_destroy_worker(d-\u003ekworker);\n }\n \n+/**\n+ * ice_dpll_pin_freq_info - find pin frequency from supported ones\n+ * @hw: pointer to the hardware structure\n+ * @pin_idx: pin index\n+ * @input: if input pin\n+ *\n+ * This function searches through the array of supported frequencies for a\n+ * DPLL pin and returns single frequency pin is capable, if pin support only\n+ * one frequency. Shall be used only for dpll with driver hardcoded frequency.\n+ *\n+ * Return:\n+ * * 0 - failure, pin uses multiple frequencies,\n+ * * frequency - success.\n+ */\n+static u64 ice_dpll_pin_freq_info(struct ice_hw *hw, u8 pin_idx, bool input)\n+{\n+\tstruct dpll_pin_frequency *freqs;\n+\tu8 freq_num;\n+\n+\t/* Get supported frequencies for this pin */\n+\tfreqs = ice_cgu_get_pin_freq_supp(hw, pin_idx, input, \u0026freq_num);\n+\tif (!freqs || freq_num != 1 || freqs[0].min != freqs[0].max)\n+\t\treturn 0;\n+\n+\treturn freqs[0].min;\n+}\n+\n /**\n * ice_dpll_init_worker - Initialize DPLLs periodic worker\n * @pf: board private structure\n@@ -4398,6 +4476,19 @@ ice_dpll_init_info_direct_pins(struct ice_pf *pf,\n \t\tpins[i].prop.board_label = ice_cgu_get_pin_name(hw, i, input);\n \t\tpins[i].prop.type = ice_cgu_get_pin_type(hw, i, input);\n \t\tif (input) {\n+\t\t\tif (pf-\u003edplls.unmanaged) {\n+\t\t\t\tpins[i].freq = ice_dpll_pin_freq_info(hw, i,\n+\t\t\t\t\t\t\t\t input);\n+\t\t\t\tpins[i].state[0] = DPLL_PIN_STATE_CONNECTED;\n+\t\t\t\tpins[i].status =\n+\t\t\t\t\tICE_AQC_GET_CGU_IN_CFG_STATUS_ESYNC_CAP;\n+\t\t\t\tpins[i].flags[0] = ICE_DPLL_IN_ESYNC_ENABLED;\n+\t\t\t\t/* skip priority, capabilities, phase range,\n+\t\t\t\t * pin state AQ query and freq_supported -\n+\t\t\t\t * not available for unmanaged DPLL\n+\t\t\t\t */\n+\t\t\t\tcontinue;\n+\t\t\t}\n \t\t\tret = ice_aq_get_cgu_ref_prio(hw, de-\u003edpll_idx, i,\n \t\t\t\t\t\t \u0026de-\u003einput_prio[i]);\n \t\t\tif (ret)\n@@ -4411,6 +4502,16 @@ ice_dpll_init_info_direct_pins(struct ice_pf *pf,\n \t\t\tif (ice_dpll_is_sw_pin(pf, i, true))\n \t\t\t\tpins[i].hidden = true;\n \t\t} else {\n+\t\t\tif (pf-\u003edplls.unmanaged) {\n+\t\t\t\tpins[i].freq = ice_dpll_pin_freq_info(hw, i,\n+\t\t\t\t\t\t\t\t input);\n+\t\t\t\tpins[i].state[0] = DPLL_PIN_STATE_CONNECTED;\n+\t\t\t\t/* skip output state caps, phase range,\n+\t\t\t\t * pin state AQ query and freq_supported -\n+\t\t\t\t * not available for unmanaged DPLL\n+\t\t\t\t */\n+\t\t\t\tcontinue;\n+\t\t\t}\n \t\t\tret = ice_cgu_get_output_pin_state_caps(hw, i, \u0026caps);\n \t\t\tif (ret)\n \t\t\t\treturn ret;\n@@ -4428,10 +4529,13 @@ ice_dpll_init_info_direct_pins(struct ice_pf *pf,\n \t\tpins[i].prop.freq_supported_num = freq_supp_num;\n \t\tpins[i].pf = pf;\n \t}\n-\tif (input)\n+\tif (input \u0026\u0026 !pf-\u003edplls.unmanaged) {\n \t\tret = ice_dpll_init_ref_sync_inputs(pf);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\t}\n \n-\treturn ret;\n+\treturn 0;\n }\n \n /**\n@@ -4712,6 +4816,82 @@ static int ice_dpll_init_info_e825c(struct ice_pf *pf)\n \treturn ret;\n }\n \n+/**\n+ * ice_dpll_lock_state_init_unmanaged - initialize lock state for unmanaged dpll\n+ * @pf: board private structure\n+ *\n+ * Initialize the lock state for unmanaged DPLL by checking health status.\n+ * For unmanaged DPLL, we rely on hardware autonomous operation.\n+ *\n+ * Return:\n+ * * 0 - success\n+ * * negative - init failure reason\n+ */\n+static int ice_dpll_lock_state_init_unmanaged(struct ice_pf *pf)\n+{\n+\tu16 code = ICE_AQC_HEALTH_STATUS_INFO_LOSS_OF_LOCK;\n+\tstruct ice_aqc_health_status_elem buff;\n+\tint ret;\n+\n+\tret = ice_get_last_health_status_code(\u0026pf-\u003ehw, \u0026buff, code);\n+\tif (ret)\n+\t\treturn ret;\n+\tice_dpll_lock_state_set_unmanaged(pf, \u0026buff, false);\n+\n+\treturn ret;\n+}\n+\n+/**\n+ * ice_dpll_init_info_unmanaged - init dpll information for unmanaged dpll\n+ * @pf: board private structure\n+ *\n+ * Acquire (from HW) and set basic dpll information (on pf-\u003edplls struct).\n+ * For unmanaged dpll mode.\n+ *\n+ * Return:\n+ * * 0 - success\n+ * * negative - init failure reason\n+ */\n+static int ice_dpll_init_info_unmanaged(struct ice_pf *pf)\n+{\n+\tstruct ice_dplls *d = \u0026pf-\u003edplls;\n+\tint ret;\n+\n+\td-\u003eclock_id = ice_generate_clock_id(pf);\n+\td-\u003enum_inputs = ice_cgu_get_pin_num(\u0026pf-\u003ehw, true);\n+\td-\u003enum_outputs = ice_cgu_get_pin_num(\u0026pf-\u003ehw, false);\n+\tret = ice_dpll_lock_state_init_unmanaged(pf);\n+\tif (ret)\n+\t\treturn ret;\n+\td-\u003einputs = kzalloc_objs(*d-\u003einputs, d-\u003enum_inputs);\n+\tif (!d-\u003einputs)\n+\t\treturn -ENOMEM;\n+\n+\tret = ice_dpll_init_pins_info(pf, ICE_DPLL_PIN_TYPE_INPUT);\n+\tif (ret)\n+\t\tgoto deinit_info;\n+\n+\td-\u003eoutputs = kzalloc_objs(*d-\u003eoutputs, d-\u003enum_outputs);\n+\tif (!d-\u003eoutputs) {\n+\t\tret = -ENOMEM;\n+\t\tgoto deinit_info;\n+\t}\n+\n+\tret = ice_dpll_init_pins_info(pf, ICE_DPLL_PIN_TYPE_OUTPUT);\n+\tif (ret)\n+\t\tgoto deinit_info;\n+\n+\td-\u003epps.mode = DPLL_MODE_MANUAL;\n+\tdev_dbg(ice_pf_to_dev(pf), \"%s - success, inputs:%u, outputs:%u\\n\",\n+\t\t__func__, d-\u003enum_inputs, d-\u003enum_outputs);\n+\treturn 0;\n+deinit_info:\n+\tdev_err(ice_pf_to_dev(pf), \"%s - fail: d-\u003einputs:%p, d-\u003eoutputs:%p\\n\",\n+\t\t__func__, d-\u003einputs, d-\u003eoutputs);\n+\tice_dpll_deinit_info(pf);\n+\treturn ret;\n+}\n+\n /**\n * ice_dpll_init_info - prepare pf's dpll information structure\n * @pf: board private structure\n@@ -4815,6 +4995,42 @@ static int ice_dpll_init_info(struct ice_pf *pf, bool cgu)\n \treturn ret;\n }\n \n+/**\n+ * ice_dpll_lock_state_set_unmanaged - determine lock state from health status\n+ * @pf: board private structure\n+ * @buff: health status buffer\n+ * @notify: if true, notify dpll device\n+ *\n+ * Set unmanaged dpll lock state based on health status code and internal data.\n+ * Context: Acquires and releases pf-\u003edplls.lock (must release before notify\n+ * if called).\n+ */\n+void ice_dpll_lock_state_set_unmanaged(struct ice_pf *pf,\n+\t\t\t\t const struct ice_aqc_health_status_elem *buff,\n+\t\t\t\t bool notify)\n+{\n+\tu32 internal_data = le32_to_cpu(buff-\u003einternal_data1);\n+\tstruct ice_dpll *d = \u0026pf-\u003edplls.pps;\n+\n+\tif (!ice_pf_src_tmr_owned(pf))\n+\t\treturn;\n+\n+\tmutex_lock(\u0026pf-\u003edplls.lock);\n+\tif (buff-\u003ehealth_status_code == 0 ||\n+\t internal_data == ICE_DPLL_HEALTH_STATUS_LOCKED)\n+\t\td-\u003edpll_state = DPLL_LOCK_STATUS_LOCKED;\n+\telse\n+\t\td-\u003edpll_state = DPLL_LOCK_STATUS_UNLOCKED;\n+\n+\tif (d-\u003eprev_dpll_state == d-\u003edpll_state)\n+\t\tnotify = false;\n+\telse\n+\t\td-\u003eprev_dpll_state = d-\u003edpll_state;\n+\tmutex_unlock(\u0026pf-\u003edplls.lock);\n+\tif (notify \u0026\u0026 d-\u003edpll)\n+\t\tdpll_device_change_ntf(d-\u003edpll);\n+}\n+\n /**\n * ice_dpll_deinit - Disable the driver/HW support for dpll subsystem\n * the dpll device.\n@@ -4854,9 +5070,10 @@ void ice_dpll_deinit(struct ice_pf *pf)\n \tif (pf-\u003ehw.mac_type == ICE_MAC_GENERIC_3K_E825)\n \t\tcancel_work_sync(\u0026pf-\u003edplls.txclk_work);\n \n-\tice_dpll_deinit_pins(pf, cgu);\n+\tice_dpll_deinit_pins(pf, cgu || pf-\u003edplls.unmanaged);\n \tif (!IS_ERR_OR_NULL(pf-\u003edplls.pps.dpll))\n-\t\tice_dpll_deinit_dpll(pf, \u0026pf-\u003edplls.pps, cgu);\n+\t\tice_dpll_deinit_dpll(pf, \u0026pf-\u003edplls.pps,\n+\t\t\t\t cgu || pf-\u003edplls.unmanaged);\n \tif (!IS_ERR_OR_NULL(pf-\u003edplls.eec.dpll))\n \t\tice_dpll_deinit_dpll(pf, \u0026pf-\u003edplls.eec, cgu);\n \tif (!IS_ERR_OR_NULL(pf-\u003edplls.txc.dpll))\n@@ -4866,6 +5083,45 @@ void ice_dpll_deinit(struct ice_pf *pf)\n \tmutex_destroy(\u0026pf-\u003edplls.lock);\n }\n \n+/**\n+ * ice_dpll_init_unmanaged - initialize support for unmanaged dpll subsystem\n+ * @pf: board private structure\n+ *\n+ * Set up the device dplls for unmanaged mode, register them and pins connected\n+ * within Linux dpll subsystem. Allow userspace to obtain state of DPLL.\n+ *\n+ * Context: Initializes pf-\u003edplls.lock mutex.\n+ */\n+static void ice_dpll_init_unmanaged(struct ice_pf *pf)\n+{\n+\tstruct ice_dplls *d = \u0026pf-\u003edplls;\n+\tint err;\n+\n+\tif (!ice_pf_src_tmr_owned(pf))\n+\t\treturn;\n+\tmutex_init(\u0026d-\u003elock);\n+\terr = ice_dpll_init_info_unmanaged(pf);\n+\tif (err)\n+\t\tgoto err_exit;\n+\terr = ice_dpll_init_dpll(pf, \u0026pf-\u003edplls.pps, true, DPLL_TYPE_PPS);\n+\tif (err)\n+\t\tgoto deinit_info;\n+\terr = ice_dpll_init_pins(pf, true);\n+\tif (err)\n+\t\tgoto deinit_pps;\n+\tset_bit(ICE_FLAG_DPLL, pf-\u003eflags);\n+\n+\treturn;\n+\n+deinit_pps:\n+\tice_dpll_deinit_dpll(pf, \u0026pf-\u003edplls.pps, true);\n+deinit_info:\n+\tice_dpll_deinit_info(pf);\n+err_exit:\n+\tmutex_destroy(\u0026d-\u003elock);\n+\tdev_warn(ice_pf_to_dev(pf), \"DPLLs init failure err:%d\\n\", err);\n+}\n+\n /**\n * ice_dpll_init_e825 - initialize support for dpll subsystem\n * @pf: board private structure\n@@ -4975,8 +5231,23 @@ static void ice_dpll_init_e810(struct ice_pf *pf)\n \tdev_warn(ice_pf_to_dev(pf), \"DPLLs init failure err:%d\\n\", err);\n }\n \n+/**\n+ * ice_dpll_init - initialize support for dpll subsystem\n+ * @pf: board private structure\n+ *\n+ * Set up the device dplls, register them and pins connected within Linux dpll\n+ * subsystem. Allow userspace to obtain state of DPLL and handling of DPLL\n+ * configuration requests.\n+ *\n+ * Context: Initializes pf-\u003edplls.lock mutex.\n+ */\n void ice_dpll_init(struct ice_pf *pf)\n {\n+\tif (pf-\u003edplls.unmanaged) {\n+\t\tice_dpll_init_unmanaged(pf);\n+\t\treturn;\n+\t}\n+\n \tswitch (pf-\u003ehw.mac_type) {\n \tcase ICE_MAC_GENERIC_3K_E825:\n \t\tice_dpll_init_e825(pf);\ndiff --git a/drivers/net/ethernet/intel/ice/ice_dpll.h b/drivers/net/ethernet/intel/ice/ice_dpll.h\nindex 103ba3e490682..c59d746a85671 100644\n--- a/drivers/net/ethernet/intel/ice/ice_dpll.h\n+++ b/drivers/net/ethernet/intel/ice/ice_dpll.h\n@@ -26,6 +26,8 @@\n #define ICE_CGU_R11_SYNCE_S_BYP_CLK\tGENMASK(6, 1)\n \n #define ICE_CGU_BYPASS_MUX_OFFSET_E825C\t3\n+#define ICE_DPLL_UNMANAGED_PIN_NUM\t4\n+#define ICE_DPLL_IN_ESYNC_ENABLED\tICE_AQC_GET_CGU_IN_CFG_FLG2_ESYNC_EN\n \n /**\n * enum ice_dpll_pin_sw - enumerate ice software pin indices:\n@@ -193,6 +195,7 @@ struct ice_dplls {\n \ts32 output_phase_adj_max;\n \tu32 periodic_counter;\n \tbool generic;\n+\tbool unmanaged;\n \tstruct work_struct txclk_work;\n \tbool txclk_switch_requested;\n \tstruct rw_semaphore txclk_notify_rwsem;\n@@ -201,9 +204,16 @@ struct ice_dplls {\n #if IS_ENABLED(CONFIG_PTP_1588_CLOCK)\n void ice_dpll_init(struct ice_pf *pf);\n void ice_dpll_deinit(struct ice_pf *pf);\n+void ice_dpll_lock_state_set_unmanaged(struct ice_pf *pf,\n+\t\t\t\t const struct ice_aqc_health_status_elem *buff,\n+\t\t\t\t bool notify);\n #else\n static inline void ice_dpll_init(struct ice_pf *pf) { }\n static inline void ice_dpll_deinit(struct ice_pf *pf) { }\n+static inline void\n+ice_dpll_lock_state_set_unmanaged(struct ice_pf *pf,\n+\t\t\t\t const struct ice_aqc_health_status_elem *buff,\n+\t\t\t\t bool notify) { }\n #endif\n \n #endif\ndiff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c\nindex 8cdc4fda89e97..fc9d4e0fa7558 100644\n--- a/drivers/net/ethernet/intel/ice/ice_lib.c\n+++ b/drivers/net/ethernet/intel/ice/ice_lib.c\n@@ -1415,6 +1415,10 @@ static int ice_vsi_alloc_rings(struct ice_vsi *vsi)\n \t\t\tset_bit(ICE_TX_RING_FLAGS_VLAN_L2TAG2, ring-\u003eflags);\n \t\telse\n \t\t\tset_bit(ICE_TX_RING_FLAGS_VLAN_L2TAG1, ring-\u003eflags);\n+\n+\t\tif (ice_is_feature_supported(pf, ICE_F_GCS))\n+\t\t\tset_bit(ICE_TX_RING_FLAGS_GCS, ring-\u003eflags);\n+\n \t\tWRITE_ONCE(vsi-\u003etx_rings[i], ring);\n \t}\n \ndiff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c\nindex d88835482d3aa..fefbc51c71900 100644\n--- a/drivers/net/ethernet/intel/ice/ice_main.c\n+++ b/drivers/net/ethernet/intel/ice/ice_main.c\n@@ -3428,7 +3428,7 @@ static int ice_req_irq_msix_misc(struct ice_pf *pf)\n \t\t ((pf-\u003ell_ts_irq.index + pf_intr_start_offset) \u0026\n \t\t PFINT_SB_CTL_MSIX_INDX_M) | PFINT_SB_CTL_CAUSE_ENA_M);\n \twr32(hw, GLINT_ITR(ICE_RX_ITR, pf-\u003eoicr_irq.index),\n-\t ITR_REG_ALIGN(ICE_ITR_8K) \u003e\u003e ICE_ITR_GRAN_S);\n+\t ITR_REG_ALIGN(ICE_ITR_20K) \u003e\u003e ICE_ITR_GRAN_S);\n \n \tice_flush(hw);\n \tice_irq_dynamic_ena(hw, NULL, NULL);\n@@ -3491,9 +3491,8 @@ void ice_set_netdev_features(struct net_device *netdev)\n \t\t\tNETIF_F_RXHASH;\n \n \tcsumo_features = NETIF_F_RXCSUM\t |\n-\t\t\t NETIF_F_IP_CSUM |\n \t\t\t NETIF_F_SCTP_CRC |\n-\t\t\t NETIF_F_IPV6_CSUM;\n+\t\t\t NETIF_F_HW_CSUM;\n \n \tvlano_features = NETIF_F_HW_VLAN_CTAG_FILTER |\n \t\t\t NETIF_F_HW_VLAN_CTAG_TX |\n@@ -3555,12 +3554,6 @@ void ice_set_netdev_features(struct net_device *netdev)\n \t/* Allow core to manage IRQs affinity */\n \tnetif_set_affinity_auto(netdev);\n \n-\t/* Mutual exclusivity for TSO and GCS is enforced by the set features\n-\t * ndo callback.\n-\t */\n-\tif (ice_is_feature_supported(pf, ICE_F_GCS))\n-\t\tnetdev-\u003ehw_features |= NETIF_F_HW_CSUM;\n-\n \tnetif_set_tso_max_size(netdev, ICE_MAX_TSO_SIZE);\n }\n \n@@ -4720,7 +4713,9 @@ void ice_deinit_dev(struct ice_pf *pf)\n \n static void ice_init_features(struct ice_pf *pf)\n {\n+\tu16 code = ICE_AQC_HEALTH_STATUS_INFO_LOSS_OF_LOCK;\n \tstruct device *dev = ice_pf_to_dev(pf);\n+\tint err;\n \n \tif (ice_is_safe_mode(pf))\n \t\treturn;\n@@ -4732,8 +4727,15 @@ static void ice_init_features(struct ice_pf *pf)\n \tif (ice_is_feature_supported(pf, ICE_F_GNSS))\n \t\tice_gnss_init(pf);\n \n+\t/* Initialize unmanaged DPLL detection */\n+\terr = ice_is_health_status_code_supported(\u0026pf-\u003ehw, code,\n+\t\t\t\t\t\t \u0026pf-\u003edplls.unmanaged);\n+\tif (err || !ice_is_unmanaged_cgu_in_netlist(\u0026pf-\u003ehw))\n+\t\tpf-\u003edplls.unmanaged = false;\n+\n \tif (ice_is_feature_supported(pf, ICE_F_CGU) ||\n-\t ice_is_feature_supported(pf, ICE_F_PHY_RCLK))\n+\t ice_is_feature_supported(pf, ICE_F_PHY_RCLK) ||\n+\t pf-\u003edplls.unmanaged)\n \t\tice_dpll_init(pf);\n \n \t/* Note: Flow director init failure is non-fatal to load */\n@@ -6510,18 +6512,6 @@ ice_set_features(struct net_device *netdev, netdev_features_t features)\n \tif (changed \u0026 NETIF_F_LOOPBACK)\n \t\tret = ice_set_loopback(vsi, !!(features \u0026 NETIF_F_LOOPBACK));\n \n-\t/* Due to E830 hardware limitations, TSO (NETIF_F_ALL_TSO) with GCS\n-\t * (NETIF_F_HW_CSUM) is not supported.\n-\t */\n-\tif (ice_is_feature_supported(pf, ICE_F_GCS) \u0026\u0026\n-\t ((features \u0026 NETIF_F_HW_CSUM) \u0026\u0026 (features \u0026 NETIF_F_ALL_TSO))) {\n-\t\tif (netdev-\u003efeatures \u0026 NETIF_F_HW_CSUM)\n-\t\t\tdev_err(ice_pf_to_dev(pf), \"To enable TSO, you must first disable HW checksum.\\n\");\n-\t\telse\n-\t\t\tdev_err(ice_pf_to_dev(pf), \"To enable HW checksum, you must first disable TSO.\\n\");\n-\t\treturn -EIO;\n-\t}\n-\n \treturn ret;\n }\n \ndiff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c\nindex eaec36ab6ae3f..e8392ec4f1348 100644\n--- a/drivers/net/ethernet/intel/ice/ice_ptp.c\n+++ b/drivers/net/ethernet/intel/ice/ice_ptp.c\n@@ -2327,6 +2327,8 @@ u64 ice_ptp_get_rx_hwts(const union ice_32b_rx_flex_desc *rx_desc,\n \tts_high = le32_to_cpu(rx_desc-\u003ewb.flex_ts.ts_high);\n \tts_ns = ice_ptp_extend_32b_ts(cached_time, ts_high);\n \n+\tice_trace(rx_hwtstamp, cached_time, ts_high, ts_ns);\n+\n \treturn ts_ns;\n }\n \ndiff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c\nindex 8e5f97835954c..f905104f95d88 100644\n--- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c\n+++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c\n@@ -20,6 +20,10 @@ static struct dpll_pin_frequency ice_cgu_pin_freq_10_mhz[] = {\n \tDPLL_PIN_FREQUENCY_10MHZ,\n };\n \n+static struct dpll_pin_frequency ice_cgu_pin_freq_156_25mhz[] = {\n+\tDPLL_PIN_FREQUENCY_RANGE(156250000, 156250000),\n+};\n+\n static const struct ice_cgu_pin_desc ice_e810t_sfp_cgu_inputs[] = {\n \t{ \"CVL-SDP22\",\t ZL_REF0P, DPLL_PIN_TYPE_INT_OSCILLATOR,\n \t\tARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common },\n@@ -131,6 +135,18 @@ static const struct ice_cgu_pin_desc ice_e823_zl_cgu_outputs[] = {\n \t{ \"NONE\",\t ZL_OUT5, 0, 0 },\n };\n \n+static const struct ice_cgu_pin_desc ice_e830_unmanaged_inputs[] = {\n+\t{ \"1588-TIME_SYNC\", 0, DPLL_PIN_TYPE_EXT,\n+\t ARRAY_SIZE(ice_cgu_pin_freq_10_mhz), ice_cgu_pin_freq_10_mhz },\n+};\n+\n+static const struct ice_cgu_pin_desc ice_e830_unmanaged_outputs[] = {\n+\t{ \"MAC-PHY-CLK\", 0, DPLL_PIN_TYPE_SYNCE_ETH_PORT,\n+\t ARRAY_SIZE(ice_cgu_pin_freq_156_25mhz), ice_cgu_pin_freq_156_25mhz },\n+\t{ \"1588-TIME_REF\", 1, DPLL_PIN_TYPE_INT_OSCILLATOR,\n+\t ARRAY_SIZE(ice_cgu_pin_freq_1_hz), ice_cgu_pin_freq_1_hz},\n+};\n+\n /* Low level functions for interacting with and managing the device clock used\n * for the Precision Time Protocol.\n *\n@@ -5979,6 +5995,24 @@ ice_cgu_get_pin_desc(struct ice_hw *hw, bool input, int *size)\n \tcase ICE_DEV_ID_E823C_SGMII:\n \t\tt = ice_cgu_get_pin_desc_e823(hw, input, size);\n \t\tbreak;\n+\tcase ICE_DEV_ID_E830CC_BACKPLANE:\n+\tcase ICE_DEV_ID_E830CC_QSFP56:\n+\tcase ICE_DEV_ID_E830CC_SFP:\n+\tcase ICE_DEV_ID_E830CC_SFP_DD:\n+\tcase ICE_DEV_ID_E830C_BACKPLANE:\n+\tcase ICE_DEV_ID_E830C_QSFP:\n+\tcase ICE_DEV_ID_E830C_SFP:\n+\tcase ICE_DEV_ID_E830_XXV_BACKPLANE:\n+\tcase ICE_DEV_ID_E830_XXV_QSFP:\n+\tcase ICE_DEV_ID_E830_XXV_SFP:\n+\t\tif (input) {\n+\t\t\tt = ice_e830_unmanaged_inputs;\n+\t\t\t*size = ARRAY_SIZE(ice_e830_unmanaged_inputs);\n+\t\t} else {\n+\t\t\tt = ice_e830_unmanaged_outputs;\n+\t\t\t*size = ARRAY_SIZE(ice_e830_unmanaged_outputs);\n+\t\t}\n+\t\tbreak;\n \tdefault:\n \t\tbreak;\n \t}\n@@ -6005,6 +6039,18 @@ int ice_cgu_get_num_pins(struct ice_hw *hw, bool input)\n \treturn 0;\n }\n \n+/**\n+ * ice_cgu_get_pin_num - get pin description array size\n+ * @hw: pointer to the hw struct\n+ * @input: if request is done against input or output pins\n+ *\n+ * Return: size of pin description array for given hw.\n+ */\n+int ice_cgu_get_pin_num(struct ice_hw *hw, bool input)\n+{\n+\treturn ice_cgu_get_num_pins(hw, input);\n+}\n+\n /**\n * ice_cgu_get_pin_type - get pin's type\n * @hw: pointer to the hw struct\ndiff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h\nindex 16b1988e993d2..fa1e908cebac6 100644\n--- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h\n+++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h\n@@ -364,6 +364,7 @@ int ice_read_sma_ctrl(struct ice_hw *hw, u8 *data);\n int ice_write_sma_ctrl(struct ice_hw *hw, u8 data);\n int ice_ptp_read_sdp_ac(struct ice_hw *hw, __le16 *entries, uint *num_entries);\n int ice_cgu_get_num_pins(struct ice_hw *hw, bool input);\n+int ice_cgu_get_pin_num(struct ice_hw *hw, bool input);\n enum dpll_pin_type ice_cgu_get_pin_type(struct ice_hw *hw, u8 pin, bool input);\n struct dpll_pin_frequency *\n ice_cgu_get_pin_freq_supp(struct ice_hw *hw, u8 pin, bool input, u8 *num);\ndiff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c\nindex 6a5875bd9c6b1..4daee252e2a63 100644\n--- a/drivers/net/ethernet/intel/ice/ice_switch.c\n+++ b/drivers/net/ethernet/intel/ice/ice_switch.c\n@@ -2612,7 +2612,6 @@ ice_fill_sw_rule(struct ice_hw *hw, struct ice_fltr_info *f_info,\n \tu16 vlan_id = ICE_MAX_VLAN_ID + 1;\n \tu16 vlan_tpid = ETH_P_8021Q;\n \tvoid *daddr = NULL;\n-\tu16 eth_hdr_sz;\n \tu8 *eth_hdr;\n \tu32 act = 0;\n \t__be16 *off;\n@@ -2625,11 +2624,10 @@ ice_fill_sw_rule(struct ice_hw *hw, struct ice_fltr_info *f_info,\n \t\treturn;\n \t}\n \n-\teth_hdr_sz = sizeof(dummy_eth_header);\n \teth_hdr = s_rule-\u003ehdr_data;\n \n \t/* initialize the ether header with a dummy header */\n-\tmemcpy(eth_hdr, dummy_eth_header, eth_hdr_sz);\n+\tice_fill_eth_hdr(eth_hdr);\n \tice_fill_sw_info(hw, f_info);\n \n \tswitch (f_info-\u003efltr_act) {\n@@ -2730,7 +2728,7 @@ ice_fill_sw_rule(struct ice_hw *hw, struct ice_fltr_info *f_info,\n \n \t/* Create the switch rule with the final dummy Ethernet header */\n \tif (opc != ice_aqc_opc_update_sw_rules)\n-\t\ts_rule-\u003ehdr_len = cpu_to_le16(eth_hdr_sz);\n+\t\ts_rule-\u003ehdr_len = cpu_to_le16(DUMMY_ETH_HDR_LEN);\n }\n \n /**\ndiff --git a/drivers/net/ethernet/intel/ice/ice_tc_lib.c b/drivers/net/ethernet/intel/ice/ice_tc_lib.c\nindex d20357c041273..4560e55c8f9c9 100644\n--- a/drivers/net/ethernet/intel/ice/ice_tc_lib.c\n+++ b/drivers/net/ethernet/intel/ice/ice_tc_lib.c\n@@ -174,6 +174,7 @@ static u16 ice_check_supported_vlan_tpid(u16 vlan_tpid)\n \tcase ETH_P_8021Q:\n \tcase ETH_P_8021AD:\n \tcase ETH_P_QINQ1:\n+\tcase ETH_P_8021AH:\n \t\treturn vlan_tpid;\n \tdefault:\n \t\treturn 0;\ndiff --git a/drivers/net/ethernet/intel/ice/ice_trace.h b/drivers/net/ethernet/intel/ice/ice_trace.h\nindex 4f35ef8d6b299..3cb8c6ea03cf6 100644\n--- a/drivers/net/ethernet/intel/ice/ice_trace.h\n+++ b/drivers/net/ethernet/intel/ice/ice_trace.h\n@@ -241,6 +241,24 @@ DEFINE_TX_TSTAMP_OP_EVENT(ice_tx_tstamp_fw_req);\n DEFINE_TX_TSTAMP_OP_EVENT(ice_tx_tstamp_fw_done);\n DEFINE_TX_TSTAMP_OP_EVENT(ice_tx_tstamp_complete);\n \n+/* Trace event for Rx timestamp */\n+TRACE_EVENT(ice_rx_hwtstamp,\n+\t TP_PROTO(u64 cached_time, u32 ts_high, u64 ts_ns),\n+\n+\t TP_ARGS(cached_time, ts_high, ts_ns),\n+\n+\t TP_STRUCT__entry(__field(u64, cached_time)\n+\t\t\t __field(u32, ts_high)\n+\t\t\t __field(u64, ts_ns)),\n+\n+\t TP_fast_assign(__entry-\u003ecached_time = cached_time;\n+\t\t\t __entry-\u003ets_high = ts_high;\n+\t\t\t __entry-\u003ets_ns = ts_ns;),\n+\n+\t TP_printk(\"cached_time=%llu ts_high=%u ts_ns=%llu\",\n+\t\t __entry-\u003ecached_time, __entry-\u003ets_high, __entry-\u003ets_ns)\n+);\n+\n DECLARE_EVENT_CLASS(ice_esw_br_fdb_template,\n \t\t TP_PROTO(struct ice_esw_br_fdb_entry *fdb),\n \t\t TP_ARGS(fdb),\ndiff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c\nindex 31303ab5be175..477c86d8c53bc 100644\n--- a/drivers/net/ethernet/intel/ice/ice_txrx.c\n+++ b/drivers/net/ethernet/intel/ice/ice_txrx.c\n@@ -1739,7 +1739,7 @@ int ice_tx_csum(struct ice_tx_buf *first, struct ice_tx_offload_params *off)\n \tl3_len = l4.hdr - ip.hdr;\n \toffset |= (l3_len / 4) \u003c\u003c ICE_TX_DESC_LEN_IPLEN_S;\n \n-\tif ((tx_ring-\u003enetdev-\u003efeatures \u0026 NETIF_F_HW_CSUM) \u0026\u0026\n+\tif (test_bit(ICE_TX_RING_FLAGS_GCS, tx_ring-\u003eflags) \u0026\u0026\n \t !(first-\u003etx_flags \u0026 ICE_TX_FLAGS_TSO) \u0026\u0026\n \t !skb_csum_is_sctp(skb)) {\n \t\t/* Set GCS */\ndiff --git a/drivers/net/ethernet/intel/ice/ice_txrx.h b/drivers/net/ethernet/intel/ice/ice_txrx.h\nindex 5e517f2193798..15dbd51009125 100644\n--- a/drivers/net/ethernet/intel/ice/ice_txrx.h\n+++ b/drivers/net/ethernet/intel/ice/ice_txrx.h\n@@ -217,6 +217,7 @@ enum ice_tx_ring_flags {\n \tICE_TX_RING_FLAGS_VLAN_L2TAG1,\n \tICE_TX_RING_FLAGS_VLAN_L2TAG2,\n \tICE_TX_RING_FLAGS_TXTIME,\n+\tICE_TX_RING_FLAGS_GCS,\n \tICE_TX_RING_FLAGS_NBITS,\n };\n \ndiff --git a/drivers/net/ethernet/intel/ice/ice_vsi_vlan_lib.c b/drivers/net/ethernet/intel/ice/ice_vsi_vlan_lib.c\nindex 54984966851d5..b67272e2f603c 100644\n--- a/drivers/net/ethernet/intel/ice/ice_vsi_vlan_lib.c\n+++ b/drivers/net/ethernet/intel/ice/ice_vsi_vlan_lib.c\n@@ -24,7 +24,8 @@ static void print_invalid_tpid(struct ice_vsi *vsi, u16 tpid)\n static bool validate_vlan(struct ice_vsi *vsi, struct ice_vlan *vlan)\n {\n \tif (vlan-\u003etpid != ETH_P_8021Q \u0026\u0026 vlan-\u003etpid != ETH_P_8021AD \u0026\u0026\n-\t vlan-\u003etpid != ETH_P_QINQ1 \u0026\u0026 (vlan-\u003etpid || vlan-\u003evid)) {\n+\t vlan-\u003etpid != ETH_P_QINQ1 \u0026\u0026 vlan-\u003etpid != ETH_P_8021AH \u0026\u0026\n+\t (vlan-\u003etpid || vlan-\u003evid)) {\n \t\tprint_invalid_tpid(vsi, vlan-\u003etpid);\n \t\treturn false;\n \t}\ndiff --git a/drivers/net/ethernet/intel/ice/virt/virtchnl.c b/drivers/net/ethernet/intel/ice/virt/virtchnl.c\nindex ca8018e3dd428..06d2f9be93ae4 100644\n--- a/drivers/net/ethernet/intel/ice/virt/virtchnl.c\n+++ b/drivers/net/ethernet/intel/ice/virt/virtchnl.c\n@@ -1702,6 +1702,9 @@ static bool ice_vc_validate_vlan_tpid(u16 filtering_caps, u16 tpid)\n \tcase ETH_P_QINQ1:\n \t\tvlan_ethertype = VIRTCHNL_VLAN_ETHERTYPE_9100;\n \t\tbreak;\n+\tcase ETH_P_8021AH:\n+\t\tvlan_ethertype = VIRTCHNL_VLAN_ETHERTYPE_88E7;\n+\t\tbreak;\n \t}\n \n \tif (!(filtering_caps \u0026 vlan_ethertype))\n@@ -2136,6 +2139,9 @@ static int ice_vc_get_tpid(u32 ethertype_setting, u16 *tpid)\n \tcase VIRTCHNL_VLAN_ETHERTYPE_9100:\n \t\t*tpid = ETH_P_QINQ1;\n \t\tbreak;\n+\tcase VIRTCHNL_VLAN_ETHERTYPE_88E7:\n+\t\t*tpid = ETH_P_8021AH;\n+\t\tbreak;\n \tdefault:\n \t\t*tpid = 0;\n \t\treturn -EINVAL;\ndiff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c\nindex 21d2fe38a41a6..424c12c0394a3 100644\n--- a/drivers/net/ethernet/intel/igc/igc_main.c\n+++ b/drivers/net/ethernet/intel/igc/igc_main.c\n@@ -11,6 +11,8 @@\n #include \u003cnet/pkt_sched.h\u003e\n #include \u003clinux/bpf_trace.h\u003e\n #include \u003cnet/xdp_sock_drv.h\u003e\n+#include \u003clinux/acpi.h\u003e\n+#include \u003clinux/hex.h\u003e\n #include \u003clinux/pci.h\u003e\n #include \u003clinux/mdio.h\u003e\n \n@@ -7105,6 +7107,57 @@ static enum hrtimer_restart igc_qbv_scheduling_timer(struct hrtimer *timer)\n \treturn HRTIMER_NORESTART;\n }\n \n+static bool igc_get_acpi_mac_passthru(u8 *mac)\n+{\n+\tstatic const struct {\n+\t\tconst char *name;\n+\t\tacpi_object_type type;\n+\t\tu32 length;\n+\t} sources[] = {\n+\t\t{ \"\\\\_SB.AMAC\", ACPI_TYPE_BUFFER, 23 },\n+\t\t{ \"\\\\MACA\", ACPI_TYPE_STRING, 22 },\n+\t};\n+\tstruct acpi_buffer buffer;\n+\tunion acpi_object *obj;\n+\tbool mac_found = false;\n+\tacpi_status status;\n+\tu8 buf[ETH_ALEN];\n+\tint i;\n+\n+\tif (!IS_ENABLED(CONFIG_ACPI))\n+\t\treturn false;\n+\n+\tfor (i = 0; i \u003c ARRAY_SIZE(sources) \u0026\u0026 !mac_found; i++) {\n+\t\tbuffer.length = ACPI_ALLOCATE_BUFFER;\n+\t\tbuffer.pointer = NULL;\n+\n+\t\tstatus = acpi_evaluate_object(NULL, (char *)sources[i].name,\n+\t\t\t\t\t NULL, \u0026buffer);\n+\t\tif (ACPI_FAILURE(status))\n+\t\t\tcontinue;\n+\n+\t\tobj = buffer.pointer;\n+\t\tif (!obj || obj-\u003etype != sources[i].type ||\n+\t\t obj-\u003estring.length != sources[i].length)\n+\t\t\tgoto free_obj;\n+\n+\t\tif (strncmp(obj-\u003estring.pointer, \"_AUXMAC_#\", 9) ||\n+\t\t obj-\u003estring.pointer[21] != '#')\n+\t\t\tgoto free_obj;\n+\n+\t\tif (hex2bin(buf, obj-\u003estring.pointer + 9, ETH_ALEN) ||\n+\t\t !is_valid_ether_addr(buf))\n+\t\t\tgoto free_obj;\n+\n+\t\tether_addr_copy(mac, buf);\n+\t\tmac_found = true;\n+free_obj:\n+\t\tkfree(obj);\n+\t}\n+\n+\treturn mac_found;\n+}\n+\n /**\n * igc_probe - Device Initialization Routine\n * @pdev: PCI device information struct\n@@ -7268,9 +7321,16 @@ static int igc_probe(struct pci_dev *pdev,\n \t}\n \n \tif (eth_platform_get_mac_address(\u0026pdev-\u003edev, hw-\u003emac.addr)) {\n-\t\t/* copy the MAC address out of the NVM */\n-\t\tif (hw-\u003emac.ops.read_mac_addr(hw))\n+\t\t/* Look for a system-provided MAC in the ACPI table before\n+\t\t * falling back to reading the address from the NVM.\n+\t\t */\n+\t\tif (igc_get_acpi_mac_passthru(hw-\u003emac.addr)) {\n+\t\t\tnetdev-\u003eaddr_assign_type = NET_ADDR_STOLEN;\n+\t\t\tdev_info(\u0026pdev-\u003edev, \"Using ACPI pass-through MAC addr %pM\\n\",\n+\t\t\t\t hw-\u003emac.addr);\n+\t\t} else if (hw-\u003emac.ops.read_mac_addr(hw)) {\n \t\t\tdev_err(\u0026pdev-\u003edev, \"NVM Read Error\\n\");\n+\t\t}\n \t}\n \n \teth_hw_addr_set(netdev, hw-\u003emac.addr);\ndiff --git a/include/linux/avf/virtchnl.h b/include/linux/avf/virtchnl.h\nindex 11bdab5522fd5..511c8827c640f 100644\n--- a/include/linux/avf/virtchnl.h\n+++ b/include/linux/avf/virtchnl.h\n@@ -636,6 +636,7 @@ enum virtchnl_vlan_support {\n \tVIRTCHNL_VLAN_ETHERTYPE_8100 =\t\tBIT(0),\n \tVIRTCHNL_VLAN_ETHERTYPE_88A8 =\t\tBIT(1),\n \tVIRTCHNL_VLAN_ETHERTYPE_9100 =\t\tBIT(2),\n+\tVIRTCHNL_VLAN_ETHERTYPE_88E7 =\t\tBIT(3),\n \tVIRTCHNL_VLAN_TAG_LOCATION_L2TAG1 =\tBIT(8),\n \tVIRTCHNL_VLAN_TAG_LOCATION_L2TAG2 =\tBIT(9),\n \tVIRTCHNL_VLAN_TAG_LOCATION_L2TAG2_2 =\tBIT(10),\n"
} |
| 2/1 | 2026/08/05 22:47 | agent | patch-evaluator |
0mModel:best-expensive Args: null Results: {
"EnableConfigs": [
"E1000E"
],
"FocusSymbols": [
"e1000_alloc_rx_buffers",
"e1000_clean_rx_irq"
],
"Reasoning": "The patch modifies the RX path of the e1000e driver (e1000_alloc_rx_buffers and e1000_clean_rx_irq), which is fully emulated in QEMU and reachable. It also modifies i40e, ice, and igc drivers, but those are not natively emulated in standard QEMU. We focus on the e1000e changes.",
"WorthFuzzing": true
}Instruction: You are an expert Linux kernel maintainer. Your job is to review a provided patch series and determine if it makes functional changes to the kernel that should be fuzzed. IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in your workspace. Do NOT rely on your internal knowledge of the kernel. You must actively use your code access tools to examine the actual source code and confirm any assumptions. Return WorthFuzzing=false if the patch only contains: - Modifications to Documentation/, Kconfig files, or code comments. - Purely decorative changes, such as logging (e.g., pr_err, printk) or tracepoints. - Changes to numeric constants or macros that do not functionally alter execution flow. - Code paths that are impossible to reach in virtualized environments like GCE or QEMU, even when utilizing software-emulated hardware (e.g., usb gadget, mac80211_hwsim). - Code in vendor-specific PCIe switch, SmartNIC, or GPU drivers (e.g., mlxsw, pds_core, qed, ionic, amdgpu) that require physical PCIe hardware cards not emulated in standard QEMU. - Driver .remove, .shutdown, or pci_unregister_driver teardown callbacks (e.g., igb_remove) that are executed only during PCI hot-unplug or sysfs driver unbind operations. If it modifies reachable core kernel logic, drivers, or architectures, use your code search tools to verify the code can be executed, then return WorthFuzzing=true. When returning WorthFuzzing=true, you MUST ALSO: 1. Extract any specific kernel functions that should be heavily fuzzed into FocusSymbols. Avoid listing generic hot-path functions to prevent skewed test distributions. Prefer non-static, non-inlined API entrypoint functions over internal static helper functions (which are inlined by the compiler and do not have distinct symbol addresses). 2. Identify any specific CONFIG_ options required to properly test this new/modified feature. Go and look into the Kconfig files and check for ifdefs around the code, do not make assumptions. Also check "depends on" lines in Kconfig to include any non-standard parent subsystem configs needed for Kbuild to compile the code statically into vmlinux. List them in the EnableConfigs output array, and DO NOT add a 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4"). Prefer calling several tools at the same time to save round-trips. Use set-results tool to provide results of the analysis. It must be called exactly once before the final reply. Ignore results of this tool. Prompt: For your convenience, here is the diff of the changes:
commit b6f0af5c9437f4164b02c6118aa0d784455dab12
Author: syz-cluster <triage@syzkaller.com>
Date: Wed Aug 5 22:47:25 2026 +0000
syz-cluster: applied patch under review
diff --git a/Documentation/networking/device_drivers/ethernet/intel/ice.rst b/Documentation/networking/device_drivers/ethernet/intel/ice.rst
index 0bca293cf9cb7..82b3ccc7027ea 100644
--- a/Documentation/networking/device_drivers/ethernet/intel/ice.rst
+++ b/Documentation/networking/device_drivers/ethernet/intel/ice.rst
@@ -941,6 +941,86 @@ To see input signal on those PTP pins, you need to configure DPLL properly.
Output signal is only visible on DPLL and to send it to the board SMA/U.FL pins,
DPLL output pins have to be manually configured.
+Unmanaged DPLL Support
+----------------------
+Hardware variants of E830 may support an unmanaged DPLL:
+
+- Intel(R) Ethernet Network Adapter E830-XXVDA8F for OCP 3.0,
+
+- Intel(R) Ethernet Network Adapter E830-XXVDA4F.
+
+In the case of the unmanaged DPLL, the configuration is hardcoded within the
+hardware and firmware, meaning users cannot modify settings. However,
+users can check the DPLL lock status and obtain configuration information
+through the Linux DPLL subsystem.
+
+When present, the DPLL device locks to an external signal provided through the
+PCIe/OCP pin. The expected input signal is 1PPS (1 Pulse Per Second) embedded
+on a 10MHz reference clock.
+The DPLL produces output:
+
+- for MAC (Media Access Control) & PHY (Physical Layer) clocks,
+
+- 1PPS for synchronization of onboard PHC (Precision Hardware Clock) timer.
+
+Example output of querying the Linux DPLL subsystem can be found below.
+
+.. code-block:: console
+ :caption: Dumping the DPLL pins
+
+ $ <ynl> --spec Documentation/netlink/specs/dpll.yaml --dump pin-get
+ [{'board-label': '1588-TIME_SYNC',
+ 'capabilities': set(),
+ 'clock-id': 282574471561216,
+ 'esync-frequency': 1,
+ 'esync-frequency-supported': [{'frequency-max': 1, 'frequency-min': 1}],
+ 'esync-pulse': 25,
+ 'frequency': 10000000,
+ 'id': 13,
+ 'module-name': 'ice',
+ 'parent-device': [{'direction': 'input',
+ 'parent-id': 6,
+ 'state': 'connected'}],
+ 'phase-adjust-max': 0,
+ 'phase-adjust-min': 0,
+ 'type': 'ext'},
+ {'board-label': 'MAC-PHY-CLK',
+ 'capabilities': set(),
+ 'clock-id': 282574471561216,
+ 'frequency': 156250000,
+ 'id': 14,
+ 'module-name': 'ice',
+ 'parent-device': [{'direction': 'output',
+ 'parent-id': 6,
+ 'state': 'connected'}],
+ 'phase-adjust-max': 0,
+ 'phase-adjust-min': 0,
+ 'type': 'synce-eth-port'},
+ {'board-label': '1588-TIME_REF',
+ 'capabilities': set(),
+ 'clock-id': 282574471561216,
+ 'frequency': 1,
+ 'id': 15,
+ 'module-name': 'ice',
+ 'parent-device': [{'direction': 'output',
+ 'parent-id': 6,
+ 'state': 'connected'}],
+ 'phase-adjust-max': 0,
+ 'phase-adjust-min': 0,
+ 'type': 'int-oscillator'}]
+
+.. code-block:: console
+ :caption: Dumping the DPLL devices
+
+ $ <ynl> --spec Documentation/netlink/specs/dpll.yaml --dump device-get
+ [{'clock-id': 282574471561216,
+ 'id': 6,
+ 'lock-status': 'locked',
+ 'mode': 'manual',
+ 'mode-supported': ['manual'],
+ 'module-name': 'ice',
+ 'type': 'pps'}]
+
GNSS module
-----------
Requires kernel compiled with CONFIG_GNSS=y or CONFIG_GNSS=m.
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index 844f31ab37ad4..b08bcbdb19d97 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -675,6 +675,8 @@ static void e1000_alloc_rx_buffers(struct e1000_ring *rx_ring,
skb = buffer_info->skb;
if (skb) {
skb_trim(skb, 0);
+ if (likely(buffer_info->dma))
+ goto write_desc;
goto map_skb;
}
@@ -692,10 +694,12 @@ static void e1000_alloc_rx_buffers(struct e1000_ring *rx_ring,
DMA_FROM_DEVICE);
if (dma_mapping_error(&pdev->dev, buffer_info->dma)) {
dev_err(&pdev->dev, "Rx DMA map failed\n");
+ buffer_info->dma = 0;
adapter->rx_dma_failed++;
break;
}
+write_desc:
rx_desc = E1000_RX_DESC_EXT(*rx_ring, i);
rx_desc->read.buffer_addr = cpu_to_le64(buffer_info->dma);
@@ -953,7 +957,6 @@ static bool e1000_clean_rx_irq(struct e1000_ring *rx_ring, int *work_done,
dma_rmb(); /* read descriptor and rx_buffer_info after status DD */
skb = buffer_info->skb;
- buffer_info->skb = NULL;
prefetch(skb->data - NET_IP_ALIGN);
@@ -967,9 +970,6 @@ static bool e1000_clean_rx_irq(struct e1000_ring *rx_ring, int *work_done,
cleaned = true;
cleaned_count++;
- dma_unmap_single(&pdev->dev, buffer_info->dma,
- adapter->rx_buffer_len, DMA_FROM_DEVICE);
- buffer_info->dma = 0;
length = le16_to_cpu(rx_desc->wb.upper.length);
@@ -985,8 +985,6 @@ static bool e1000_clean_rx_irq(struct e1000_ring *rx_ring, int *work_done,
if (adapter->flags2 & FLAG2_IS_DISCARDING) {
/* All receives must fit into a single buffer */
e_dbg("Receive packet consumed multiple buffers\n");
- /* recycle */
- buffer_info->skb = skb;
if (staterr & E1000_RXD_STAT_EOP)
adapter->flags2 &= ~FLAG2_IS_DISCARDING;
goto next_desc;
@@ -994,8 +992,6 @@ static bool e1000_clean_rx_irq(struct e1000_ring *rx_ring, int *work_done,
if (unlikely((staterr & E1000_RXDEXT_ERR_FRAME_ERR_MASK) &&
!(netdev->features & NETIF_F_RXALL))) {
- /* recycle */
- buffer_info->skb = skb;
goto next_desc;
}
@@ -1022,19 +1018,33 @@ static bool e1000_clean_rx_irq(struct e1000_ring *rx_ring, int *work_done,
struct sk_buff *new_skb =
napi_alloc_skb(&adapter->napi, length);
if (new_skb) {
+ dma_sync_single_for_cpu(&pdev->dev,
+ buffer_info->dma,
+ adapter->rx_buffer_len,
+ DMA_FROM_DEVICE);
skb_copy_to_linear_data_offset(new_skb,
-NET_IP_ALIGN,
(skb->data -
NET_IP_ALIGN),
(length +
NET_IP_ALIGN));
- /* save the skb in buffer_info as good */
- buffer_info->skb = skb;
+ dma_sync_single_for_device(&pdev->dev,
+ buffer_info->dma,
+ adapter->rx_buffer_len,
+ DMA_FROM_DEVICE);
skb = new_skb;
+ goto copybreak_done;
}
/* else just continue with the old one */
}
- /* end copybreak code */
+
+ buffer_info->skb = NULL;
+ dma_unmap_single(&pdev->dev, buffer_info->dma,
+ adapter->rx_buffer_len,
+ DMA_FROM_DEVICE);
+ buffer_info->dma = 0;
+
+copybreak_done:
skb_put(skb, length);
/* Receive Checksum Offload */
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index 0cd0e5597c909..abbc71e815ae3 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -4,6 +4,7 @@
#include <generated/utsrelease.h>
#include <linux/crash_dump.h>
#include <linux/net/intel/libie/pctype.h>
+#include <linux/net/intel/libie/rx.h>
#include <linux/if_bridge.h>
#include <linux/if_macvlan.h>
#include <linux/module.h>
@@ -2411,10 +2412,12 @@ void i40e_aqc_add_filters(struct i40e_vsi *vsi, const char *vsi_name,
if (fcnt != num_add) {
if (vsi->type == I40E_VSI_MAIN) {
- set_bit(__I40E_VSI_OVERFLOW_PROMISC, vsi->state);
- dev_warn(&vsi->back->pdev->dev,
- "Error %s adding RX filters on %s, promiscuous mode forced on\n",
- libie_aq_str(aq_status), vsi_name);
+ if (!test_and_set_bit(__I40E_VSI_OVERFLOW_PROMISC,
+ vsi->state)) {
+ dev_warn(&vsi->back->pdev->dev,
+ "Error %s adding RX filters on %s, promiscuous mode forced on\n",
+ libie_aq_str(aq_status), vsi_name);
+ }
} else if (vsi->type == I40E_VSI_SRIOV ||
vsi->type == I40E_VSI_VMDQ1 ||
vsi->type == I40E_VSI_VMDQ2) {
@@ -2464,10 +2467,11 @@ i40e_aqc_broadcast_filter(struct i40e_vsi *vsi, const char *vsi_name,
}
if (aq_ret) {
- set_bit(__I40E_VSI_OVERFLOW_PROMISC, vsi->state);
- dev_warn(&vsi->back->pdev->dev,
- "Error %s, forcing overflow promiscuous on %s\n",
- libie_aq_str(hw->aq.asq_last_status), vsi_name);
+ if (!test_and_set_bit(__I40E_VSI_OVERFLOW_PROMISC, vsi->state)) {
+ dev_warn(&vsi->back->pdev->dev,
+ "Error %s, forcing overflow promiscuous on %s\n",
+ libie_aq_str(hw->aq.asq_last_status), vsi_name);
+ }
}
return aq_ret;
@@ -3622,7 +3626,7 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
}
skip:
- xdp_init_buff(&ring->xdp, xdp_frame_sz, &ring->xdp_rxq);
+ xdp_init_buff(&ring->xdp_ctx.xdp, xdp_frame_sz, &ring->xdp_rxq);
rx_ctx.dbuff = DIV_ROUND_UP(ring->rx_buf_len,
BIT_ULL(I40E_RXQ_CTX_DBUFF_SHIFT));
@@ -13582,6 +13586,53 @@ static int i40e_xdp(struct net_device *dev,
}
}
+static int i40e_xdp_rx_hash(const struct xdp_md *_ctx, u32 *hash,
+ enum xdp_rss_hash_type *rss_type)
+{
+ const struct i40e_xdp_buff *ctx = (const void *)_ctx;
+ const union i40e_rx_desc *desc = ctx->desc;
+ struct libeth_rx_pt rx_ptype;
+ u8 raw_rx_ptype;
+ u64 status;
+
+ status = le64_to_cpu(desc->wb.qword1.status_error_len);
+ raw_rx_ptype = FIELD_GET(I40E_RXD_QW1_PTYPE_MASK, status);
+ rx_ptype = libie_rx_pt_parse(raw_rx_ptype);
+
+ if (!libeth_rx_pt_has_hash(ctx->xdp.rxq->dev, rx_ptype) ||
+ FIELD_GET(I40E_RX_DESC_STATUS_FLTSTAT_MASK, status) !=
+ I40E_RX_DESC_FLTSTAT_RSS_HASH)
+ return -ENODATA;
+
+ *hash = le32_to_cpu(desc->wb.qword0.hi_dword.rss);
+ *rss_type = rx_ptype.hash_type;
+
+ return 0;
+}
+
+static int i40e_xdp_rx_vlan_tag(const struct xdp_md *_ctx, __be16 *vlan_proto,
+ u16 *vlan_tci)
+{
+ const struct i40e_xdp_buff *ctx = (const void *)_ctx;
+ const union i40e_rx_desc *desc = ctx->desc;
+ u64 status;
+
+ status = le64_to_cpu(desc->wb.qword1.status_error_len);
+
+ if (!(status & BIT(I40E_RX_DESC_STATUS_L2TAG1P_SHIFT)))
+ return -ENODATA;
+
+ *vlan_proto = cpu_to_be16(ETH_P_8021Q);
+ *vlan_tci = le16_to_cpu(desc->wb.qword0.lo_dword.l2tag1);
+
+ return 0;
+}
+
+static const struct xdp_metadata_ops i40e_xdp_metadata_ops = {
+ .xmo_rx_hash = i40e_xdp_rx_hash,
+ .xmo_rx_vlan_tag = i40e_xdp_rx_vlan_tag,
+};
+
static const struct net_device_ops i40e_netdev_ops = {
.ndo_open = i40e_open,
.ndo_stop = i40e_close,
@@ -13784,6 +13835,7 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)
i40e_vsi_config_netdev_tc(vsi, vsi->tc_config.enabled_tc);
netdev->netdev_ops = &i40e_netdev_ops;
+ netdev->xdp_metadata_ops = &i40e_xdp_metadata_ops;
netdev->watchdog_timeo = 5 * HZ;
i40e_set_ethtool_ops(netdev);
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
index ef5e657816f00..7f68adb5109b0 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
@@ -2438,10 +2438,11 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget,
unsigned int *rx_cleaned)
{
unsigned int total_rx_bytes = 0, total_rx_packets = 0;
+ struct i40e_xdp_buff *xdp_ctx = &rx_ring->xdp_ctx;
u16 cleaned_count = I40E_DESC_UNUSED(rx_ring);
u16 clean_threshold = rx_ring->count / 2;
unsigned int offset = rx_ring->rx_offset;
- struct xdp_buff *xdp = &rx_ring->xdp;
+ struct xdp_buff *xdp = &xdp_ctx->xdp;
unsigned int xdp_xmit = 0;
struct bpf_prog *xdp_prog;
bool failure = false;
@@ -2530,6 +2531,8 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget,
if (neop)
continue;
+ xdp_ctx->desc = rx_desc;
+
xdp_res = i40e_run_xdp(rx_ring, xdp, xdp_prog);
if (xdp_res) {
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.h b/drivers/net/ethernet/intel/i40e/i40e_txrx.h
index 1e5fd63d47f47..bb741ff3e5f2c 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.h
@@ -283,6 +283,11 @@ struct i40e_rx_buffer {
__u32 page_count;
};
+struct i40e_xdp_buff {
+ struct xdp_buff xdp;
+ const union i40e_rx_desc *desc;
+};
+
struct i40e_queue_stats {
u64 packets;
u64 bytes;
@@ -345,7 +350,7 @@ struct i40e_ring {
* and to resume packet building for this ring in the next call to
* i40e_clean_rx_ring_irq().
*/
- struct xdp_buff xdp;
+ struct i40e_xdp_buff xdp_ctx;
/* Next descriptor to be processed; next_to_clean is updated only on
* processing EOP descriptor
diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h
index ed8bbdb586da9..16a65c6e51537 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_type.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_type.h
@@ -4,6 +4,7 @@
#ifndef _I40E_TYPE_H_
#define _I40E_TYPE_H_
+#include <linux/bits.h>
#include <uapi/linux/if_ether.h>
#include "i40e_adminq.h"
#include "i40e_hmc.h"
@@ -699,6 +700,10 @@ enum i40e_rx_desc_status_bits {
I40E_RX_DESC_STATUS_LAST /* this entry must be last!!! */
};
+#define I40E_RX_DESC_STATUS_FLTSTAT_MASK \
+ GENMASK_ULL(I40E_RX_DESC_STATUS_FLTSTAT_SHIFT + 1, \
+ I40E_RX_DESC_STATUS_FLTSTAT_SHIFT)
+
#define I40E_RXD_QW1_STATUS_SHIFT 0
#define I40E_RXD_QW1_STATUS_MASK ((BIT(I40E_RX_DESC_STATUS_LAST) - 1) \
<< I40E_RXD_QW1_STATUS_SHIFT)
diff --git a/drivers/net/ethernet/intel/i40e/i40e_xsk.c b/drivers/net/ethernet/intel/i40e/i40e_xsk.c
index 9f47388eaba53..51a05ce4c7ce8 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_xsk.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_xsk.c
@@ -246,6 +246,8 @@ bool i40e_alloc_rx_buffers_zc(struct i40e_ring *rx_ring, u16 count)
u32 nb_buffs, i;
dma_addr_t dma;
+ XSK_CHECK_PRIV_TYPE(struct i40e_xdp_buff);
+
rx_desc = I40E_RX_DESC(rx_ring, ntu);
xdp = i40e_rx_bi(rx_ring, ntu);
@@ -396,6 +398,14 @@ static void i40e_handle_xdp_result_zc(struct i40e_ring *rx_ring,
WARN_ON_ONCE(1);
}
+static struct i40e_xdp_buff *xsk_buff_to_i40e_ctx(struct xdp_buff *xdp)
+{
+ /* xdp_buff pointer used by ZC code path is allocated as xdp_buff_xsk.
+ * i40e_xdp_buff private fields overlap with xdp_buff_xsk->cb.
+ */
+ return (struct i40e_xdp_buff *)xdp;
+}
+
/**
* i40e_clean_rx_irq_zc - Consumes Rx packets from the hardware ring
* @rx_ring: Rx ring
@@ -472,6 +482,8 @@ int i40e_clean_rx_irq_zc(struct i40e_ring *rx_ring, int budget)
if (i40e_is_non_eop(rx_ring, rx_desc))
continue;
+ xsk_buff_to_i40e_ctx(first)->desc = rx_desc;
+
xdp_res = i40e_run_xdp_zc(rx_ring, first, xdp_prog);
i40e_handle_xdp_result_zc(rx_ring, first, rx_desc, &rx_packets,
&rx_bytes, xdp_res, &failure);
diff --git a/drivers/net/ethernet/intel/ice/devlink/health.c b/drivers/net/ethernet/intel/ice/devlink/health.c
index 8e9a8a8178d48..a83eb9f104c83 100644
--- a/drivers/net/ethernet/intel/ice/devlink/health.c
+++ b/drivers/net/ethernet/intel/ice/devlink/health.c
@@ -101,6 +101,8 @@ static const struct ice_health_status ice_health_status_lookup[] = {
"Supplied MIB file is invalid. DCB reverted to default configuration.",
"Disable FW-LLDP and check DCBx system configuration.",
{ice_port_number_label, "MIB ID"}},
+ {ICE_AQC_HEALTH_STATUS_INFO_LOSS_OF_LOCK, "Local DPLL lock status",
+ NULL,},
};
static int ice_health_status_lookup_compare(const void *a, const void *b)
@@ -242,6 +244,10 @@ void ice_process_health_status_event(struct ice_pf *pf, struct ice_rq_event_info
pf->health_reporters.fw_status = *health_info;
devlink_health_report(pf->health_reporters.fw,
"FW syndrome reported", NULL);
+ if (status_code == ICE_AQC_HEALTH_STATUS_INFO_LOSS_OF_LOCK &&
+ test_bit(ICE_FLAG_DPLL, pf->flags) &&
+ pf->dplls.unmanaged)
+ ice_dpll_lock_state_set_unmanaged(pf, health_info, true);
break;
case ICE_AQC_HEALTH_STATUS_PF:
case ICE_AQC_HEALTH_STATUS_PORT:
diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
index 42878abac9eb1..848ac58342979 100644
--- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
+++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
@@ -1500,6 +1500,7 @@ struct ice_aqc_get_link_topo {
#define ICE_AQC_GET_LINK_TOPO_NODE_NR_PCA9575 0x21
#define ICE_AQC_GET_LINK_TOPO_NODE_NR_ZL30632_80032 0x24
#define ICE_AQC_GET_LINK_TOPO_NODE_NR_SI5383_5384 0x25
+#define ICE_AQC_GET_LINK_TOPO_NODE_NR_ZL80640 0x27
#define ICE_AQC_GET_LINK_TOPO_NODE_NR_E822_PHY 0x30
#define ICE_AQC_GET_LINK_TOPO_NODE_NR_C827 0x31
#define ICE_AQC_GET_LINK_TOPO_NODE_NR_GEN_CLK_MUX 0x47
@@ -2483,11 +2484,14 @@ enum ice_aqc_health_status {
ICE_AQC_HEALTH_STATUS_ERR_BMC_RESET = 0x50B,
ICE_AQC_HEALTH_STATUS_ERR_LAST_MNG_FAIL = 0x50C,
ICE_AQC_HEALTH_STATUS_ERR_RESOURCE_ALLOC_FAIL = 0x50D,
+ ICE_AQC_HEALTH_STATUS_INFO_LOSS_OF_LOCK = 0x601,
ICE_AQC_HEALTH_STATUS_ERR_FW_LOOP = 0x1000,
ICE_AQC_HEALTH_STATUS_ERR_FW_PFR_FAIL = 0x1001,
ICE_AQC_HEALTH_STATUS_ERR_LAST_FAIL_AQ = 0x1002,
};
+#define ICE_AQC_HEALTH_STATUS_CODE_NUM 64
+
/* Get Health Status (indirect 0xFF22) */
struct ice_aqc_get_health_status {
__le16 health_status_count;
@@ -2514,6 +2518,13 @@ struct ice_aqc_health_status_elem {
__le32 internal_data2;
};
+/* Get Health Status response buffer entry, (0xFF21)
+ * repeated per reported health status
+ */
+struct ice_aqc_health_status_supp_elem {
+ __le16 health_status_code;
+};
+
/* Admin Queue command opcodes */
enum ice_adminq_opc {
/* AQ commands */
@@ -2677,6 +2688,7 @@ enum ice_adminq_opc {
/* System Diagnostic commands */
ice_aqc_opc_set_health_status_cfg = 0xFF20,
+ ice_aqc_opc_get_supported_health_status_codes = 0xFF21,
ice_aqc_opc_get_health_status = 0xFF22,
/* FW Logging Commands */
diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c
index ef1ce106f81b5..2c72ed18695c5 100644
--- a/drivers/net/ethernet/intel/ice/ice_common.c
+++ b/drivers/net/ethernet/intel/ice/ice_common.c
@@ -3048,6 +3048,29 @@ bool ice_is_cgu_in_netlist(struct ice_hw *hw)
return false;
}
+/**
+ * ice_is_unmanaged_cgu_in_netlist - check for unmanaged CGU presence
+ * @hw: pointer to the hw struct
+ *
+ * Check if the unmanaged Clock Generation Unit (CGU) device is present in the netlist.
+ * Save the CGU part number in the hw structure for later use.
+ * Return:
+ * * true - unmanaged cgu is present
+ * * false - unmanaged cgu is not present
+ */
+bool ice_is_unmanaged_cgu_in_netlist(struct ice_hw *hw)
+{
+ if (!ice_find_netlist_node(hw, ICE_AQC_LINK_TOPO_NODE_TYPE_CLK_CTRL,
+ ICE_AQC_LINK_TOPO_NODE_CTX_GLOBAL,
+ ICE_AQC_GET_LINK_TOPO_NODE_NR_ZL80640,
+ NULL)) {
+ hw->cgu_part_number = ICE_AQC_GET_LINK_TOPO_NODE_NR_ZL80640;
+ return true;
+ }
+
+ return false;
+}
+
/**
* ice_is_gps_in_netlist
* @hw: pointer to the hw struct
@@ -6312,6 +6335,119 @@ bool ice_is_fw_health_report_supported(struct ice_hw *hw)
ICE_FW_API_HEALTH_REPORT_PATCH);
}
+/**
+ * ice_aq_get_health_status_supported - get supported health status codes
+ * @hw: pointer to the HW struct
+ * @buff: pointer to buffer where health status elements will be stored
+ * @num: number of health status elements buffer can hold
+ *
+ * Return:
+ * * 0 - success,
+ * * negative - AQ error code.
+ */
+static int
+ice_aq_get_health_status_supported(struct ice_hw *hw,
+ struct ice_aqc_health_status_supp_elem *buff,
+ int num)
+{
+ u16 code = ice_aqc_opc_get_supported_health_status_codes;
+ struct libie_aq_desc desc;
+
+ ice_fill_dflt_direct_cmd_desc(&desc, code);
+
+ return ice_aq_send_cmd(hw, &desc, buff, num * sizeof(*buff), NULL);
+}
+
+/**
+ * ice_aq_get_health_status - get current health status array from the firmware
+ * @hw: pointer to the HW struct
+ * @buff: pointer to buffer where health status elements will be stored
+ * @num: number of health status elements buffer can hold
+ *
+ * Return:
+ * * 0 - success,
+ * * negative - AQ error code.
+ */
+int ice_aq_get_health_status(struct ice_hw *hw,
+ struct ice_aqc_health_status_elem *buff, int num)
+{
+ struct libie_aq_desc desc;
+
+ ice_fill_dflt_direct_cmd_desc(&desc,
+ ice_aqc_opc_get_health_status);
+
+ return ice_aq_send_cmd(hw, &desc, buff, num * sizeof(*buff), NULL);
+}
+
+/**
+ * ice_is_health_status_code_supported - check if health status code is supported
+ * @hw: pointer to the hardware structure
+ * @code: health status code to check
+ * @supported: pointer to boolean result
+ *
+ * Return: 0 on success, negative error code otherwise
+ */
+int ice_is_health_status_code_supported(struct ice_hw *hw, u16 code,
+ bool *supported)
+{
+ const int BUFF_SIZE = ICE_AQC_HEALTH_STATUS_CODE_NUM;
+ struct ice_aqc_health_status_supp_elem *buff;
+ int ret;
+
+ *supported = false;
+ buff = kzalloc_objs(*buff, BUFF_SIZE);
+ if (!buff)
+ return -ENOMEM;
+ ret = ice_aq_get_health_status_supported(hw, buff, BUFF_SIZE);
+ if (ret)
+ goto free_buff;
+ for (int i = 0; i < BUFF_SIZE && buff[i].health_status_code; i++)
+ if (le16_to_cpu(buff[i].health_status_code) == code) {
+ *supported = true;
+ break;
+ }
+
+free_buff:
+ kfree(buff);
+ return ret;
+}
+
+/**
+ * ice_get_last_health_status_code - get last health status for given code
+ * @hw: pointer to the hardware structure
+ * @out: pointer to the health status struct to be filled
+ * @code: health status code to check
+ *
+ * Return: 0 on success, negative error code otherwise
+ */
+int ice_get_last_health_status_code(struct ice_hw *hw,
+ struct ice_aqc_health_status_elem *out,
+ u16 code)
+{
+ const int BUFF_SIZE = ICE_AQC_HEALTH_STATUS_CODE_NUM;
+ struct ice_aqc_health_status_elem *buff;
+ int ret, last_status = -1;
+
+ buff = kzalloc_objs(*buff, BUFF_SIZE);
+ if (!buff)
+ return -ENOMEM;
+ ret = ice_aq_get_health_status(hw, buff, BUFF_SIZE);
+ if (ret)
+ goto free_buff;
+ for (int i = 0; i < BUFF_SIZE && buff[i].health_status_code; i++)
+ if (le16_to_cpu(buff[i].health_status_code) == code)
+ last_status = i;
+
+ if (last_status >= 0)
+ memcpy(out, &buff[last_status], sizeof(*out));
+ else
+ memset(out, 0, sizeof(*out));
+
+free_buff:
+ kfree(buff);
+ return ret;
+}
+
/**
* ice_aq_set_health_status_cfg - Configure FW health events
* @hw: pointer to the HW struct
diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h
index 9f53442121955..51036188cd396 100644
--- a/drivers/net/ethernet/intel/ice/ice_common.h
+++ b/drivers/net/ethernet/intel/ice/ice_common.h
@@ -162,6 +162,7 @@ ice_aq_get_phy_caps(struct ice_port_info *pi, bool qual_mods, u8 report_mode,
bool ice_is_phy_rclk_in_netlist(struct ice_hw *hw);
bool ice_is_clock_mux_in_netlist(struct ice_hw *hw);
bool ice_is_cgu_in_netlist(struct ice_hw *hw);
+bool ice_is_unmanaged_cgu_in_netlist(struct ice_hw *hw);
bool ice_is_gps_in_netlist(struct ice_hw *hw);
int
ice_aq_get_netlist_node(struct ice_hw *hw, struct ice_aqc_get_link_topo *cmd,
@@ -188,6 +189,13 @@ ice_get_link_default_override(struct ice_link_default_override_tlv *ldo,
struct ice_port_info *pi);
bool ice_is_phy_caps_an_enabled(struct ice_aqc_get_phy_caps_data *caps);
bool ice_is_fw_health_report_supported(struct ice_hw *hw);
+int ice_aq_get_health_status(struct ice_hw *hw,
+ struct ice_aqc_health_status_elem *buff, int num);
+int ice_is_health_status_code_supported(struct ice_hw *hw, u16 code,
+ bool *supported);
+int ice_get_last_health_status_code(struct ice_hw *hw,
+ struct ice_aqc_health_status_elem *out,
+ u16 code);
int ice_aq_set_health_status_cfg(struct ice_hw *hw, u8 event_source);
int ice_aq_get_phy_equalization(struct ice_hw *hw, u16 data_in, u16 op_code,
u8 serdes_num, int *output);
diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_nl.c b/drivers/net/ethernet/intel/ice/ice_dcb_nl.c
index a10c1c8d86977..bb5cc0a2ba69b 100644
--- a/drivers/net/ethernet/intel/ice/ice_dcb_nl.c
+++ b/drivers/net/ethernet/intel/ice/ice_dcb_nl.c
@@ -872,7 +872,7 @@ static int ice_dcbnl_delapp(struct net_device *netdev, struct dcb_app *app)
int ret = 0;
if (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED) {
- netdev_err(netdev, "can't delete DSCP netlink app when FW DCB agent is active\n");
+ netdev_dbg(netdev, "can't delete DSCP netlink app when FW DCB agent is active\n");
return -EINVAL;
}
diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c
index 85a74cd6ea1f3..1ca137f67dd48 100644
--- a/drivers/net/ethernet/intel/ice/ice_dpll.c
+++ b/drivers/net/ethernet/intel/ice/ice_dpll.c
@@ -19,6 +19,8 @@
#define ICE_DPLL_SW_PIN_INPUT_BASE_SFP 4
#define ICE_DPLL_SW_PIN_INPUT_BASE_QSFP 6
#define ICE_DPLL_SW_PIN_OUTPUT_BASE 0
+#define ICE_DPLL_HEALTH_STATUS_LOCKED 1
+#define ICE_DPLL_HEALTH_STATUS_UNLOCKED 0
#define E825_RCLK_PARENT_0_PIN_IDX 0
#define E825_RCLK_PARENT_1_PIN_IDX 1
@@ -89,6 +91,10 @@ static const struct dpll_pin_frequency ice_esync_range[] = {
DPLL_PIN_FREQUENCY_RANGE(0, DPLL_PIN_FREQUENCY_1_HZ),
};
+static const struct dpll_pin_frequency ice_esync_range_unmanaged[] = {
+ DPLL_PIN_FREQUENCY_1PPS,
+};
+
/**
* ice_dpll_is_sw_pin - check if given pin shall be controlled by SW
* @pf: private board structure
@@ -1098,9 +1104,11 @@ ice_dpll_pin_state_get(const struct dpll_pin *pin, void *pin_priv,
return -EBUSY;
mutex_lock(&pf->dplls.lock);
- ret = ice_dpll_pin_state_update(pf, p, pin_type, extack);
- if (ret)
- goto unlock;
+ if (!pf->dplls.unmanaged) {
+ ret = ice_dpll_pin_state_update(pf, p, pin_type, extack);
+ if (ret)
+ goto unlock;
+ }
if (pin_type == ICE_DPLL_PIN_TYPE_INPUT ||
pin_type == ICE_DPLL_PIN_TYPE_OUTPUT)
*state = p->state[d->dpll_idx];
@@ -2243,9 +2251,14 @@ ice_dpll_input_esync_get(const struct dpll_pin *pin, void *pin_priv,
mutex_unlock(&pf->dplls.lock);
return -EOPNOTSUPP;
}
- esync->range = ice_esync_range;
- esync->range_num = ARRAY_SIZE(ice_esync_range);
- if (p->flags[0] & ICE_AQC_GET_CGU_IN_CFG_FLG2_ESYNC_EN) {
+ if (pf->dplls.unmanaged) {
+ esync->range = ice_esync_range_unmanaged;
+ esync->range_num = ARRAY_SIZE(ice_esync_range_unmanaged);
+ } else {
+ esync->range = ice_esync_range;
+ esync->range_num = ARRAY_SIZE(ice_esync_range);
+ }
+ if (p->flags[0] & ICE_DPLL_IN_ESYNC_ENABLED) {
esync->freq = DPLL_PIN_FREQUENCY_1_HZ;
esync->pulse = ICE_DPLL_PIN_ESYNC_PULSE_HIGH_PERCENT;
} else {
@@ -2876,6 +2889,19 @@ static const struct dpll_pin_ops ice_dpll_output_ops = {
.esync_get = ice_dpll_output_esync_get,
};
+static const struct dpll_pin_ops ice_dpll_input_unmanaged_ops = {
+ .frequency_get = ice_dpll_input_frequency_get,
+ .direction_get = ice_dpll_input_direction,
+ .state_on_dpll_get = ice_dpll_input_state_get,
+ .esync_get = ice_dpll_input_esync_get,
+};
+
+static const struct dpll_pin_ops ice_dpll_output_unmanaged_ops = {
+ .frequency_get = ice_dpll_output_frequency_get,
+ .direction_get = ice_dpll_output_direction,
+ .state_on_dpll_get = ice_dpll_output_state_get,
+};
+
static const struct dpll_device_ops ice_dpll_ops = {
.lock_status_get = ice_dpll_lock_status_get,
.mode_get = ice_dpll_mode_get,
@@ -3439,8 +3465,10 @@ ice_dpll_deinit_direct_pins(struct ice_pf *pf, bool cgu,
struct dpll_device *second)
{
if (cgu) {
- ice_dpll_unregister_pins(first, pins, ops, count);
- ice_dpll_unregister_pins(second, pins, ops, count);
+ if (first)
+ ice_dpll_unregister_pins(first, pins, ops, count);
+ if (second)
+ ice_dpll_unregister_pins(second, pins, ops, count);
}
ice_dpll_release_pins(pins, count);
}
@@ -3472,12 +3500,15 @@ ice_dpll_init_direct_pins(struct ice_pf *pf, bool cgu,
int ret;
ret = ice_dpll_get_pins(pf, pins, start_idx, count, pf->dplls.clock_id);
- if (ret)
+ if (!cgu || ret)
return ret;
- if (cgu) {
+
+ if (first) {
ret = ice_dpll_register_pins(first, pins, ops, count);
if (ret)
goto release_pins;
+ }
+ if (second) {
ret = ice_dpll_register_pins(second, pins, ops, count);
if (ret)
goto unregister_first;
@@ -3486,7 +3517,8 @@ ice_dpll_init_direct_pins(struct ice_pf *pf, bool cgu,
return 0;
unregister_first:
- ice_dpll_unregister_pins(first, pins, ops, count);
+ if (first)
+ ice_dpll_unregister_pins(first, pins, ops, count);
release_pins:
ice_dpll_release_pins(pins, count);
return ret;
@@ -3824,6 +3856,18 @@ static void ice_dpll_deinit_pins(struct ice_pf *pf, bool cgu)
struct ice_dpll *de = &d->eec;
struct ice_dpll *dp = &d->pps;
+ if (d->unmanaged) {
+ ice_dpll_unregister_pins(dp->dpll, inputs,
+ &ice_dpll_input_unmanaged_ops,
+ num_inputs);
+ ice_dpll_unregister_pins(dp->dpll, outputs,
+ &ice_dpll_output_unmanaged_ops,
+ num_outputs);
+ ice_dpll_release_pins(inputs, num_inputs);
+ ice_dpll_release_pins(outputs, num_outputs);
+ return;
+ }
+
ice_dpll_deinit_rclk_pin(pf);
if (pf->hw.mac_type == ICE_MAC_GENERIC_3K_E825) {
ice_dpll_deinit_txclk_pins(pf);
@@ -4082,23 +4126,29 @@ static int ice_dpll_init_pins(struct ice_pf *pf, bool cgu)
const struct dpll_pin_ops *input_ops;
int ret, count;
- input_ops = &ice_dpll_input_ops;
- output_ops = &ice_dpll_output_ops;
+ if (!pf->dplls.unmanaged) {
+ input_ops = &ice_dpll_input_ops;
+ output_ops = &ice_dpll_output_ops;
+ } else {
+ input_ops = &ice_dpll_input_unmanaged_ops;
+ output_ops = &ice_dpll_output_unmanaged_ops;
+ }
ret = ice_dpll_init_direct_pins(pf, cgu, pf->dplls.inputs, 0,
pf->dplls.num_inputs, input_ops,
- pf->dplls.eec.dpll,
- pf->dplls.pps.dpll);
+ pf->dplls.eec.dpll, pf->dplls.pps.dpll);
if (ret)
return ret;
count = pf->dplls.num_inputs;
- if (cgu) {
+ if (cgu || pf->dplls.unmanaged) {
ret = ice_dpll_init_direct_pins(pf, cgu, pf->dplls.outputs,
count, pf->dplls.num_outputs,
output_ops, pf->dplls.eec.dpll,
pf->dplls.pps.dpll);
if (ret)
goto deinit_inputs;
+ if (pf->dplls.unmanaged)
+ return 0;
count += pf->dplls.num_outputs;
if (!pf->dplls.generic) {
ret = ice_dpll_init_direct_pins(pf, cgu, pf->dplls.sma,
@@ -4206,12 +4256,13 @@ ice_dpll_init_dpll(struct ice_pf *pf, struct ice_dpll *d, bool cgu,
return ret;
}
d->pf = pf;
- if (cgu || pf->hw.mac_type == ICE_MAC_GENERIC_3K_E825) {
+ if (cgu || pf->dplls.unmanaged ||
+ pf->hw.mac_type == ICE_MAC_GENERIC_3K_E825) {
const struct dpll_device_ops *ops = &ice_dpll_ops;
if (type == DPLL_TYPE_PPS && ice_dpll_is_pps_phase_monitor(pf))
ops = &ice_dpll_pom_ops;
- if (cgu)
+ if (cgu && !pf->dplls.unmanaged)
ice_dpll_update_state(pf, d, true);
ret = dpll_device_register(d->dpll, type, ops, d);
if (ret) {
@@ -4239,6 +4290,33 @@ static void ice_dpll_deinit_worker(struct ice_pf *pf)
kthread_destroy_worker(d->kworker);
}
+/**
+ * ice_dpll_pin_freq_info - find pin frequency from supported ones
+ * @hw: pointer to the hardware structure
+ * @pin_idx: pin index
+ * @input: if input pin
+ *
+ * This function searches through the array of supported frequencies for a
+ * DPLL pin and returns single frequency pin is capable, if pin support only
+ * one frequency. Shall be used only for dpll with driver hardcoded frequency.
+ *
+ * Return:
+ * * 0 - failure, pin uses multiple frequencies,
+ * * frequency - success.
+ */
+static u64 ice_dpll_pin_freq_info(struct ice_hw *hw, u8 pin_idx, bool input)
+{
+ struct dpll_pin_frequency *freqs;
+ u8 freq_num;
+
+ /* Get supported frequencies for this pin */
+ freqs = ice_cgu_get_pin_freq_supp(hw, pin_idx, input, &freq_num);
+ if (!freqs || freq_num != 1 || freqs[0].min != freqs[0].max)
+ return 0;
+
+ return freqs[0].min;
+}
+
/**
* ice_dpll_init_worker - Initialize DPLLs periodic worker
* @pf: board private structure
@@ -4398,6 +4476,19 @@ ice_dpll_init_info_direct_pins(struct ice_pf *pf,
pins[i].prop.board_label = ice_cgu_get_pin_name(hw, i, input);
pins[i].prop.type = ice_cgu_get_pin_type(hw, i, input);
if (input) {
+ if (pf->dplls.unmanaged) {
+ pins[i].freq = ice_dpll_pin_freq_info(hw, i,
+ input);
+ pins[i].state[0] = DPLL_PIN_STATE_CONNECTED;
+ pins[i].status =
+ ICE_AQC_GET_CGU_IN_CFG_STATUS_ESYNC_CAP;
+ pins[i].flags[0] = ICE_DPLL_IN_ESYNC_ENABLED;
+ /* skip priority, capabilities, phase range,
+ * pin state AQ query and freq_supported -
+ * not available for unmanaged DPLL
+ */
+ continue;
+ }
ret = ice_aq_get_cgu_ref_prio(hw, de->dpll_idx, i,
&de->input_prio[i]);
if (ret)
@@ -4411,6 +4502,16 @@ ice_dpll_init_info_direct_pins(struct ice_pf *pf,
if (ice_dpll_is_sw_pin(pf, i, true))
pins[i].hidden = true;
} else {
+ if (pf->dplls.unmanaged) {
+ pins[i].freq = ice_dpll_pin_freq_info(hw, i,
+ input);
+ pins[i].state[0] = DPLL_PIN_STATE_CONNECTED;
+ /* skip output state caps, phase range,
+ * pin state AQ query and freq_supported -
+ * not available for unmanaged DPLL
+ */
+ continue;
+ }
ret = ice_cgu_get_output_pin_state_caps(hw, i, &caps);
if (ret)
return ret;
@@ -4428,10 +4529,13 @@ ice_dpll_init_info_direct_pins(struct ice_pf *pf,
pins[i].prop.freq_supported_num = freq_supp_num;
pins[i].pf = pf;
}
- if (input)
+ if (input && !pf->dplls.unmanaged) {
ret = ice_dpll_init_ref_sync_inputs(pf);
+ if (ret)
+ return ret;
+ }
- return ret;
+ return 0;
}
/**
@@ -4712,6 +4816,82 @@ static int ice_dpll_init_info_e825c(struct ice_pf *pf)
return ret;
}
+/**
+ * ice_dpll_lock_state_init_unmanaged - initialize lock state for unmanaged dpll
+ * @pf: board private structure
+ *
+ * Initialize the lock state for unmanaged DPLL by checking health status.
+ * For unmanaged DPLL, we rely on hardware autonomous operation.
+ *
+ * Return:
+ * * 0 - success
+ * * negative - init failure reason
+ */
+static int ice_dpll_lock_state_init_unmanaged(struct ice_pf *pf)
+{
+ u16 code = ICE_AQC_HEALTH_STATUS_INFO_LOSS_OF_LOCK;
+ struct ice_aqc_health_status_elem buff;
+ int ret;
+
+ ret = ice_get_last_health_status_code(&pf->hw, &buff, code);
+ if (ret)
+ return ret;
+ ice_dpll_lock_state_set_unmanaged(pf, &buff, false);
+
+ return ret;
+}
+
+/**
+ * ice_dpll_init_info_unmanaged - init dpll information for unmanaged dpll
+ * @pf: board private structure
+ *
+ * Acquire (from HW) and set basic dpll information (on pf->dplls struct).
+ * For unmanaged dpll mode.
+ *
+ * Return:
+ * * 0 - success
+ * * negative - init failure reason
+ */
+static int ice_dpll_init_info_unmanaged(struct ice_pf *pf)
+{
+ struct ice_dplls *d = &pf->dplls;
+ int ret;
+
+ d->clock_id = ice_generate_clock_id(pf);
+ d->num_inputs = ice_cgu_get_pin_num(&pf->hw, true);
+ d->num_outputs = ice_cgu_get_pin_num(&pf->hw, false);
+ ret = ice_dpll_lock_state_init_unmanaged(pf);
+ if (ret)
+ return ret;
+ d->inputs = kzalloc_objs(*d->inputs, d->num_inputs);
+ if (!d->inputs)
+ return -ENOMEM;
+
+ ret = ice_dpll_init_pins_info(pf, ICE_DPLL_PIN_TYPE_INPUT);
+ if (ret)
+ goto deinit_info;
+
+ d->outputs = kzalloc_objs(*d->outputs, d->num_outputs);
+ if (!d->outputs) {
+ ret = -ENOMEM;
+ goto deinit_info;
+ }
+
+ ret = ice_dpll_init_pins_info(pf, ICE_DPLL_PIN_TYPE_OUTPUT);
+ if (ret)
+ goto deinit_info;
+
+ d->pps.mode = DPLL_MODE_MANUAL;
+ dev_dbg(ice_pf_to_dev(pf), "%s - success, inputs:%u, outputs:%u\n",
+ __func__, d->num_inputs, d->num_outputs);
+ return 0;
+deinit_info:
+ dev_err(ice_pf_to_dev(pf), "%s - fail: d->inputs:%p, d->outputs:%p\n",
+ __func__, d->inputs, d->outputs);
+ ice_dpll_deinit_info(pf);
+ return ret;
+}
+
/**
* ice_dpll_init_info - prepare pf's dpll information structure
* @pf: board private structure
@@ -4815,6 +4995,42 @@ static int ice_dpll_init_info(struct ice_pf *pf, bool cgu)
return ret;
}
+/**
+ * ice_dpll_lock_state_set_unmanaged - determine lock state from health status
+ * @pf: board private structure
+ * @buff: health status buffer
+ * @notify: if true, notify dpll device
+ *
+ * Set unmanaged dpll lock state based on health status code and internal data.
+ * Context: Acquires and releases pf->dplls.lock (must release before notify
+ * if called).
+ */
+void ice_dpll_lock_state_set_unmanaged(struct ice_pf *pf,
+ const struct ice_aqc_health_status_elem *buff,
+ bool notify)
+{
+ u32 internal_data = le32_to_cpu(buff->internal_data1);
+ struct ice_dpll *d = &pf->dplls.pps;
+
+ if (!ice_pf_src_tmr_owned(pf))
+ return;
+
+ mutex_lock(&pf->dplls.lock);
+ if (buff->health_status_code == 0 ||
+ internal_data == ICE_DPLL_HEALTH_STATUS_LOCKED)
+ d->dpll_state = DPLL_LOCK_STATUS_LOCKED;
+ else
+ d->dpll_state = DPLL_LOCK_STATUS_UNLOCKED;
+
+ if (d->prev_dpll_state == d->dpll_state)
+ notify = false;
+ else
+ d->prev_dpll_state = d->dpll_state;
+ mutex_unlock(&pf->dplls.lock);
+ if (notify && d->dpll)
+ dpll_device_change_ntf(d->dpll);
+}
+
/**
* ice_dpll_deinit - Disable the driver/HW support for dpll subsystem
* the dpll device.
@@ -4854,9 +5070,10 @@ void ice_dpll_deinit(struct ice_pf *pf)
if (pf->hw.mac_type == ICE_MAC_GENERIC_3K_E825)
cancel_work_sync(&pf->dplls.txclk_work);
- ice_dpll_deinit_pins(pf, cgu);
+ ice_dpll_deinit_pins(pf, cgu || pf->dplls.unmanaged);
if (!IS_ERR_OR_NULL(pf->dplls.pps.dpll))
- ice_dpll_deinit_dpll(pf, &pf->dplls.pps, cgu);
+ ice_dpll_deinit_dpll(pf, &pf->dplls.pps,
+ cgu || pf->dplls.unmanaged);
if (!IS_ERR_OR_NULL(pf->dplls.eec.dpll))
ice_dpll_deinit_dpll(pf, &pf->dplls.eec, cgu);
if (!IS_ERR_OR_NULL(pf->dplls.txc.dpll))
@@ -4866,6 +5083,45 @@ void ice_dpll_deinit(struct ice_pf *pf)
mutex_destroy(&pf->dplls.lock);
}
+/**
+ * ice_dpll_init_unmanaged - initialize support for unmanaged dpll subsystem
+ * @pf: board private structure
+ *
+ * Set up the device dplls for unmanaged mode, register them and pins connected
+ * within Linux dpll subsystem. Allow userspace to obtain state of DPLL.
+ *
+ * Context: Initializes pf->dplls.lock mutex.
+ */
+static void ice_dpll_init_unmanaged(struct ice_pf *pf)
+{
+ struct ice_dplls *d = &pf->dplls;
+ int err;
+
+ if (!ice_pf_src_tmr_owned(pf))
+ return;
+ mutex_init(&d->lock);
+ err = ice_dpll_init_info_unmanaged(pf);
+ if (err)
+ goto err_exit;
+ err = ice_dpll_init_dpll(pf, &pf->dplls.pps, true, DPLL_TYPE_PPS);
+ if (err)
+ goto deinit_info;
+ err = ice_dpll_init_pins(pf, true);
+ if (err)
+ goto deinit_pps;
+ set_bit(ICE_FLAG_DPLL, pf->flags);
+
+ return;
+
+deinit_pps:
+ ice_dpll_deinit_dpll(pf, &pf->dplls.pps, true);
+deinit_info:
+ ice_dpll_deinit_info(pf);
+err_exit:
+ mutex_destroy(&d->lock);
+ dev_warn(ice_pf_to_dev(pf), "DPLLs init failure err:%d\n", err);
+}
+
/**
* ice_dpll_init_e825 - initialize support for dpll subsystem
* @pf: board private structure
@@ -4975,8 +5231,23 @@ static void ice_dpll_init_e810(struct ice_pf *pf)
dev_warn(ice_pf_to_dev(pf), "DPLLs init failure err:%d\n", err);
}
+/**
+ * ice_dpll_init - initialize support for dpll subsystem
+ * @pf: board private structure
+ *
+ * Set up the device dplls, register them and pins connected within Linux dpll
+ * subsystem. Allow userspace to obtain state of DPLL and handling of DPLL
+ * configuration requests.
+ *
+ * Context: Initializes pf->dplls.lock mutex.
+ */
void ice_dpll_init(struct ice_pf *pf)
{
+ if (pf->dplls.unmanaged) {
+ ice_dpll_init_unmanaged(pf);
+ return;
+ }
+
switch (pf->hw.mac_type) {
case ICE_MAC_GENERIC_3K_E825:
ice_dpll_init_e825(pf);
diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.h b/drivers/net/ethernet/intel/ice/ice_dpll.h
index 103ba3e490682..c59d746a85671 100644
--- a/drivers/net/ethernet/intel/ice/ice_dpll.h
+++ b/drivers/net/ethernet/intel/ice/ice_dpll.h
@@ -26,6 +26,8 @@
#define ICE_CGU_R11_SYNCE_S_BYP_CLK GENMASK(6, 1)
#define ICE_CGU_BYPASS_MUX_OFFSET_E825C 3
+#define ICE_DPLL_UNMANAGED_PIN_NUM 4
+#define ICE_DPLL_IN_ESYNC_ENABLED ICE_AQC_GET_CGU_IN_CFG_FLG2_ESYNC_EN
/**
* enum ice_dpll_pin_sw - enumerate ice software pin indices:
@@ -193,6 +195,7 @@ struct ice_dplls {
s32 output_phase_adj_max;
u32 periodic_counter;
bool generic;
+ bool unmanaged;
struct work_struct txclk_work;
bool txclk_switch_requested;
struct rw_semaphore txclk_notify_rwsem;
@@ -201,9 +204,16 @@ struct ice_dplls {
#if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
void ice_dpll_init(struct ice_pf *pf);
void ice_dpll_deinit(struct ice_pf *pf);
+void ice_dpll_lock_state_set_unmanaged(struct ice_pf *pf,
+ const struct ice_aqc_health_status_elem *buff,
+ bool notify);
#else
static inline void ice_dpll_init(struct ice_pf *pf) { }
static inline void ice_dpll_deinit(struct ice_pf *pf) { }
+static inline void
+ice_dpll_lock_state_set_unmanaged(struct ice_pf *pf,
+ const struct ice_aqc_health_status_elem *buff,
+ bool notify) { }
#endif
#endif
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c
index 8cdc4fda89e97..fc9d4e0fa7558 100644
--- a/drivers/net/ethernet/intel/ice/ice_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_lib.c
@@ -1415,6 +1415,10 @@ static int ice_vsi_alloc_rings(struct ice_vsi *vsi)
set_bit(ICE_TX_RING_FLAGS_VLAN_L2TAG2, ring->flags);
else
set_bit(ICE_TX_RING_FLAGS_VLAN_L2TAG1, ring->flags);
+
+ if (ice_is_feature_supported(pf, ICE_F_GCS))
+ set_bit(ICE_TX_RING_FLAGS_GCS, ring->flags);
+
WRITE_ONCE(vsi->tx_rings[i], ring);
}
diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
index d88835482d3aa..fefbc51c71900 100644
--- a/drivers/net/ethernet/intel/ice/ice_main.c
+++ b/drivers/net/ethernet/intel/ice/ice_main.c
@@ -3428,7 +3428,7 @@ static int ice_req_irq_msix_misc(struct ice_pf *pf)
((pf->ll_ts_irq.index + pf_intr_start_offset) &
PFINT_SB_CTL_MSIX_INDX_M) | PFINT_SB_CTL_CAUSE_ENA_M);
wr32(hw, GLINT_ITR(ICE_RX_ITR, pf->oicr_irq.index),
- ITR_REG_ALIGN(ICE_ITR_8K) >> ICE_ITR_GRAN_S);
+ ITR_REG_ALIGN(ICE_ITR_20K) >> ICE_ITR_GRAN_S);
ice_flush(hw);
ice_irq_dynamic_ena(hw, NULL, NULL);
@@ -3491,9 +3491,8 @@ void ice_set_netdev_features(struct net_device *netdev)
NETIF_F_RXHASH;
csumo_features = NETIF_F_RXCSUM |
- NETIF_F_IP_CSUM |
NETIF_F_SCTP_CRC |
- NETIF_F_IPV6_CSUM;
+ NETIF_F_HW_CSUM;
vlano_features = NETIF_F_HW_VLAN_CTAG_FILTER |
NETIF_F_HW_VLAN_CTAG_TX |
@@ -3555,12 +3554,6 @@ void ice_set_netdev_features(struct net_device *netdev)
/* Allow core to manage IRQs affinity */
netif_set_affinity_auto(netdev);
- /* Mutual exclusivity for TSO and GCS is enforced by the set features
- * ndo callback.
- */
- if (ice_is_feature_supported(pf, ICE_F_GCS))
- netdev->hw_features |= NETIF_F_HW_CSUM;
-
netif_set_tso_max_size(netdev, ICE_MAX_TSO_SIZE);
}
@@ -4720,7 +4713,9 @@ void ice_deinit_dev(struct ice_pf *pf)
static void ice_init_features(struct ice_pf *pf)
{
+ u16 code = ICE_AQC_HEALTH_STATUS_INFO_LOSS_OF_LOCK;
struct device *dev = ice_pf_to_dev(pf);
+ int err;
if (ice_is_safe_mode(pf))
return;
@@ -4732,8 +4727,15 @@ static void ice_init_features(struct ice_pf *pf)
if (ice_is_feature_supported(pf, ICE_F_GNSS))
ice_gnss_init(pf);
+ /* Initialize unmanaged DPLL detection */
+ err = ice_is_health_status_code_supported(&pf->hw, code,
+ &pf->dplls.unmanaged);
+ if (err || !ice_is_unmanaged_cgu_in_netlist(&pf->hw))
+ pf->dplls.unmanaged = false;
+
if (ice_is_feature_supported(pf, ICE_F_CGU) ||
- ice_is_feature_supported(pf, ICE_F_PHY_RCLK))
+ ice_is_feature_supported(pf, ICE_F_PHY_RCLK) ||
+ pf->dplls.unmanaged)
ice_dpll_init(pf);
/* Note: Flow director init failure is non-fatal to load */
@@ -6510,18 +6512,6 @@ ice_set_features(struct net_device *netdev, netdev_features_t features)
if (changed & NETIF_F_LOOPBACK)
ret = ice_set_loopback(vsi, !!(features & NETIF_F_LOOPBACK));
- /* Due to E830 hardware limitations, TSO (NETIF_F_ALL_TSO) with GCS
- * (NETIF_F_HW_CSUM) is not supported.
- */
- if (ice_is_feature_supported(pf, ICE_F_GCS) &&
- ((features & NETIF_F_HW_CSUM) && (features & NETIF_F_ALL_TSO))) {
- if (netdev->features & NETIF_F_HW_CSUM)
- dev_err(ice_pf_to_dev(pf), "To enable TSO, you must first disable HW checksum.\n");
- else
- dev_err(ice_pf_to_dev(pf), "To enable HW checksum, you must first disable TSO.\n");
- return -EIO;
- }
-
return ret;
}
diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c
index eaec36ab6ae3f..e8392ec4f1348 100644
--- a/drivers/net/ethernet/intel/ice/ice_ptp.c
+++ b/drivers/net/ethernet/intel/ice/ice_ptp.c
@@ -2327,6 +2327,8 @@ u64 ice_ptp_get_rx_hwts(const union ice_32b_rx_flex_desc *rx_desc,
ts_high = le32_to_cpu(rx_desc->wb.flex_ts.ts_high);
ts_ns = ice_ptp_extend_32b_ts(cached_time, ts_high);
+ ice_trace(rx_hwtstamp, cached_time, ts_high, ts_ns);
+
return ts_ns;
}
diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c
index 8e5f97835954c..f905104f95d88 100644
--- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c
+++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c
@@ -20,6 +20,10 @@ static struct dpll_pin_frequency ice_cgu_pin_freq_10_mhz[] = {
DPLL_PIN_FREQUENCY_10MHZ,
};
+static struct dpll_pin_frequency ice_cgu_pin_freq_156_25mhz[] = {
+ DPLL_PIN_FREQUENCY_RANGE(156250000, 156250000),
+};
+
static const struct ice_cgu_pin_desc ice_e810t_sfp_cgu_inputs[] = {
{ "CVL-SDP22", ZL_REF0P, DPLL_PIN_TYPE_INT_OSCILLATOR,
ARRAY_SIZE(ice_cgu_pin_freq_common), ice_cgu_pin_freq_common },
@@ -131,6 +135,18 @@ static const struct ice_cgu_pin_desc ice_e823_zl_cgu_outputs[] = {
{ "NONE", ZL_OUT5, 0, 0 },
};
+static const struct ice_cgu_pin_desc ice_e830_unmanaged_inputs[] = {
+ { "1588-TIME_SYNC", 0, DPLL_PIN_TYPE_EXT,
+ ARRAY_SIZE(ice_cgu_pin_freq_10_mhz), ice_cgu_pin_freq_10_mhz },
+};
+
+static const struct ice_cgu_pin_desc ice_e830_unmanaged_outputs[] = {
+ { "MAC-PHY-CLK", 0, DPLL_PIN_TYPE_SYNCE_ETH_PORT,
+ ARRAY_SIZE(ice_cgu_pin_freq_156_25mhz), ice_cgu_pin_freq_156_25mhz },
+ { "1588-TIME_REF", 1, DPLL_PIN_TYPE_INT_OSCILLATOR,
+ ARRAY_SIZE(ice_cgu_pin_freq_1_hz), ice_cgu_pin_freq_1_hz},
+};
+
/* Low level functions for interacting with and managing the device clock used
* for the Precision Time Protocol.
*
@@ -5979,6 +5995,24 @@ ice_cgu_get_pin_desc(struct ice_hw *hw, bool input, int *size)
case ICE_DEV_ID_E823C_SGMII:
t = ice_cgu_get_pin_desc_e823(hw, input, size);
break;
+ case ICE_DEV_ID_E830CC_BACKPLANE:
+ case ICE_DEV_ID_E830CC_QSFP56:
+ case ICE_DEV_ID_E830CC_SFP:
+ case ICE_DEV_ID_E830CC_SFP_DD:
+ case ICE_DEV_ID_E830C_BACKPLANE:
+ case ICE_DEV_ID_E830C_QSFP:
+ case ICE_DEV_ID_E830C_SFP:
+ case ICE_DEV_ID_E830_XXV_BACKPLANE:
+ case ICE_DEV_ID_E830_XXV_QSFP:
+ case ICE_DEV_ID_E830_XXV_SFP:
+ if (input) {
+ t = ice_e830_unmanaged_inputs;
+ *size = ARRAY_SIZE(ice_e830_unmanaged_inputs);
+ } else {
+ t = ice_e830_unmanaged_outputs;
+ *size = ARRAY_SIZE(ice_e830_unmanaged_outputs);
+ }
+ break;
default:
break;
}
@@ -6005,6 +6039,18 @@ int ice_cgu_get_num_pins(struct ice_hw *hw, bool input)
return 0;
}
+/**
+ * ice_cgu_get_pin_num - get pin description array size
+ * @hw: pointer to the hw struct
+ * @input: if request is done against input or output pins
+ *
+ * Return: size of pin description array for given hw.
+ */
+int ice_cgu_get_pin_num(struct ice_hw *hw, bool input)
+{
+ return ice_cgu_get_num_pins(hw, input);
+}
+
/**
* ice_cgu_get_pin_type - get pin's type
* @hw: pointer to the hw struct
diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h
index 16b1988e993d2..fa1e908cebac6 100644
--- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h
+++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h
@@ -364,6 +364,7 @@ int ice_read_sma_ctrl(struct ice_hw *hw, u8 *data);
int ice_write_sma_ctrl(struct ice_hw *hw, u8 data);
int ice_ptp_read_sdp_ac(struct ice_hw *hw, __le16 *entries, uint *num_entries);
int ice_cgu_get_num_pins(struct ice_hw *hw, bool input);
+int ice_cgu_get_pin_num(struct ice_hw *hw, bool input);
enum dpll_pin_type ice_cgu_get_pin_type(struct ice_hw *hw, u8 pin, bool input);
struct dpll_pin_frequency *
ice_cgu_get_pin_freq_supp(struct ice_hw *hw, u8 pin, bool input, u8 *num);
diff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c
index 6a5875bd9c6b1..4daee252e2a63 100644
--- a/drivers/net/ethernet/intel/ice/ice_switch.c
+++ b/drivers/net/ethernet/intel/ice/ice_switch.c
@@ -2612,7 +2612,6 @@ ice_fill_sw_rule(struct ice_hw *hw, struct ice_fltr_info *f_info,
u16 vlan_id = ICE_MAX_VLAN_ID + 1;
u16 vlan_tpid = ETH_P_8021Q;
void *daddr = NULL;
- u16 eth_hdr_sz;
u8 *eth_hdr;
u32 act = 0;
__be16 *off;
@@ -2625,11 +2624,10 @@ ice_fill_sw_rule(struct ice_hw *hw, struct ice_fltr_info *f_info,
return;
}
- eth_hdr_sz = sizeof(dummy_eth_header);
eth_hdr = s_rule->hdr_data;
/* initialize the ether header with a dummy header */
- memcpy(eth_hdr, dummy_eth_header, eth_hdr_sz);
+ ice_fill_eth_hdr(eth_hdr);
ice_fill_sw_info(hw, f_info);
switch (f_info->fltr_act) {
@@ -2730,7 +2728,7 @@ ice_fill_sw_rule(struct ice_hw *hw, struct ice_fltr_info *f_info,
/* Create the switch rule with the final dummy Ethernet header */
if (opc != ice_aqc_opc_update_sw_rules)
- s_rule->hdr_len = cpu_to_le16(eth_hdr_sz);
+ s_rule->hdr_len = cpu_to_le16(DUMMY_ETH_HDR_LEN);
}
/**
diff --git a/drivers/net/ethernet/intel/ice/ice_tc_lib.c b/drivers/net/ethernet/intel/ice/ice_tc_lib.c
index d20357c041273..4560e55c8f9c9 100644
--- a/drivers/net/ethernet/intel/ice/ice_tc_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_tc_lib.c
@@ -174,6 +174,7 @@ static u16 ice_check_supported_vlan_tpid(u16 vlan_tpid)
case ETH_P_8021Q:
case ETH_P_8021AD:
case ETH_P_QINQ1:
+ case ETH_P_8021AH:
return vlan_tpid;
default:
return 0;
diff --git a/drivers/net/ethernet/intel/ice/ice_trace.h b/drivers/net/ethernet/intel/ice/ice_trace.h
index 4f35ef8d6b299..3cb8c6ea03cf6 100644
--- a/drivers/net/ethernet/intel/ice/ice_trace.h
+++ b/drivers/net/ethernet/intel/ice/ice_trace.h
@@ -241,6 +241,24 @@ DEFINE_TX_TSTAMP_OP_EVENT(ice_tx_tstamp_fw_req);
DEFINE_TX_TSTAMP_OP_EVENT(ice_tx_tstamp_fw_done);
DEFINE_TX_TSTAMP_OP_EVENT(ice_tx_tstamp_complete);
+/* Trace event for Rx timestamp */
+TRACE_EVENT(ice_rx_hwtstamp,
+ TP_PROTO(u64 cached_time, u32 ts_high, u64 ts_ns),
+
+ TP_ARGS(cached_time, ts_high, ts_ns),
+
+ TP_STRUCT__entry(__field(u64, cached_time)
+ __field(u32, ts_high)
+ __field(u64, ts_ns)),
+
+ TP_fast_assign(__entry->cached_time = cached_time;
+ __entry->ts_high = ts_high;
+ __entry->ts_ns = ts_ns;),
+
+ TP_printk("cached_time=%llu ts_high=%u ts_ns=%llu",
+ __entry->cached_time, __entry->ts_high, __entry->ts_ns)
+);
+
DECLARE_EVENT_CLASS(ice_esw_br_fdb_template,
TP_PROTO(struct ice_esw_br_fdb_entry *fdb),
TP_ARGS(fdb),
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c
index 31303ab5be175..477c86d8c53bc 100644
--- a/drivers/net/ethernet/intel/ice/ice_txrx.c
+++ b/drivers/net/ethernet/intel/ice/ice_txrx.c
@@ -1739,7 +1739,7 @@ int ice_tx_csum(struct ice_tx_buf *first, struct ice_tx_offload_params *off)
l3_len = l4.hdr - ip.hdr;
offset |= (l3_len / 4) << ICE_TX_DESC_LEN_IPLEN_S;
- if ((tx_ring->netdev->features & NETIF_F_HW_CSUM) &&
+ if (test_bit(ICE_TX_RING_FLAGS_GCS, tx_ring->flags) &&
!(first->tx_flags & ICE_TX_FLAGS_TSO) &&
!skb_csum_is_sctp(skb)) {
/* Set GCS */
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.h b/drivers/net/ethernet/intel/ice/ice_txrx.h
index 5e517f2193798..15dbd51009125 100644
--- a/drivers/net/ethernet/intel/ice/ice_txrx.h
+++ b/drivers/net/ethernet/intel/ice/ice_txrx.h
@@ -217,6 +217,7 @@ enum ice_tx_ring_flags {
ICE_TX_RING_FLAGS_VLAN_L2TAG1,
ICE_TX_RING_FLAGS_VLAN_L2TAG2,
ICE_TX_RING_FLAGS_TXTIME,
+ ICE_TX_RING_FLAGS_GCS,
ICE_TX_RING_FLAGS_NBITS,
};
diff --git a/drivers/net/ethernet/intel/ice/ice_vsi_vlan_lib.c b/drivers/net/ethernet/intel/ice/ice_vsi_vlan_lib.c
index 54984966851d5..b67272e2f603c 100644
--- a/drivers/net/ethernet/intel/ice/ice_vsi_vlan_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_vsi_vlan_lib.c
@@ -24,7 +24,8 @@ static void print_invalid_tpid(struct ice_vsi *vsi, u16 tpid)
static bool validate_vlan(struct ice_vsi *vsi, struct ice_vlan *vlan)
{
if (vlan->tpid != ETH_P_8021Q && vlan->tpid != ETH_P_8021AD &&
- vlan->tpid != ETH_P_QINQ1 && (vlan->tpid || vlan->vid)) {
+ vlan->tpid != ETH_P_QINQ1 && vlan->tpid != ETH_P_8021AH &&
+ (vlan->tpid || vlan->vid)) {
print_invalid_tpid(vsi, vlan->tpid);
return false;
}
diff --git a/drivers/net/ethernet/intel/ice/virt/virtchnl.c b/drivers/net/ethernet/intel/ice/virt/virtchnl.c
index ca8018e3dd428..06d2f9be93ae4 100644
--- a/drivers/net/ethernet/intel/ice/virt/virtchnl.c
+++ b/drivers/net/ethernet/intel/ice/virt/virtchnl.c
@@ -1702,6 +1702,9 @@ static bool ice_vc_validate_vlan_tpid(u16 filtering_caps, u16 tpid)
case ETH_P_QINQ1:
vlan_ethertype = VIRTCHNL_VLAN_ETHERTYPE_9100;
break;
+ case ETH_P_8021AH:
+ vlan_ethertype = VIRTCHNL_VLAN_ETHERTYPE_88E7;
+ break;
}
if (!(filtering_caps & vlan_ethertype))
@@ -2136,6 +2139,9 @@ static int ice_vc_get_tpid(u32 ethertype_setting, u16 *tpid)
case VIRTCHNL_VLAN_ETHERTYPE_9100:
*tpid = ETH_P_QINQ1;
break;
+ case VIRTCHNL_VLAN_ETHERTYPE_88E7:
+ *tpid = ETH_P_8021AH;
+ break;
default:
*tpid = 0;
return -EINVAL;
diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
index 21d2fe38a41a6..424c12c0394a3 100644
--- a/drivers/net/ethernet/intel/igc/igc_main.c
+++ b/drivers/net/ethernet/intel/igc/igc_main.c
@@ -11,6 +11,8 @@
#include <net/pkt_sched.h>
#include <linux/bpf_trace.h>
#include <net/xdp_sock_drv.h>
+#include <linux/acpi.h>
+#include <linux/hex.h>
#include <linux/pci.h>
#include <linux/mdio.h>
@@ -7105,6 +7107,57 @@ static enum hrtimer_restart igc_qbv_scheduling_timer(struct hrtimer *timer)
return HRTIMER_NORESTART;
}
+static bool igc_get_acpi_mac_passthru(u8 *mac)
+{
+ static const struct {
+ const char *name;
+ acpi_object_type type;
+ u32 length;
+ } sources[] = {
+ { "\\_SB.AMAC", ACPI_TYPE_BUFFER, 23 },
+ { "\\MACA", ACPI_TYPE_STRING, 22 },
+ };
+ struct acpi_buffer buffer;
+ union acpi_object *obj;
+ bool mac_found = false;
+ acpi_status status;
+ u8 buf[ETH_ALEN];
+ int i;
+
+ if (!IS_ENABLED(CONFIG_ACPI))
+ return false;
+
+ for (i = 0; i < ARRAY_SIZE(sources) && !mac_found; i++) {
+ buffer.length = ACPI_ALLOCATE_BUFFER;
+ buffer.pointer = NULL;
+
+ status = acpi_evaluate_object(NULL, (char *)sources[i].name,
+ NULL, &buffer);
+ if (ACPI_FAILURE(status))
+ continue;
+
+ obj = buffer.pointer;
+ if (!obj || obj->type != sources[i].type ||
+ obj->string.length != sources[i].length)
+ goto free_obj;
+
+ if (strncmp(obj->string.pointer, "_AUXMAC_#", 9) ||
+ obj->string.pointer[21] != '#')
+ goto free_obj;
+
+ if (hex2bin(buf, obj->string.pointer + 9, ETH_ALEN) ||
+ !is_valid_ether_addr(buf))
+ goto free_obj;
+
+ ether_addr_copy(mac, buf);
+ mac_found = true;
+free_obj:
+ kfree(obj);
+ }
+
+ return mac_found;
+}
+
/**
* igc_probe - Device Initialization Routine
* @pdev: PCI device information struct
@@ -7268,9 +7321,16 @@ static int igc_probe(struct pci_dev *pdev,
}
if (eth_platform_get_mac_address(&pdev->dev, hw->mac.addr)) {
- /* copy the MAC address out of the NVM */
- if (hw->mac.ops.read_mac_addr(hw))
+ /* Look for a system-provided MAC in the ACPI table before
+ * falling back to reading the address from the NVM.
+ */
+ if (igc_get_acpi_mac_passthru(hw->mac.addr)) {
+ netdev->addr_assign_type = NET_ADDR_STOLEN;
+ dev_info(&pdev->dev, "Using ACPI pass-through MAC addr %pM\n",
+ hw->mac.addr);
+ } else if (hw->mac.ops.read_mac_addr(hw)) {
dev_err(&pdev->dev, "NVM Read Error\n");
+ }
}
eth_hw_addr_set(netdev, hw->mac.addr);
diff --git a/include/linux/avf/virtchnl.h b/include/linux/avf/virtchnl.h
index 11bdab5522fd5..511c8827c640f 100644
--- a/include/linux/avf/virtchnl.h
+++ b/include/linux/avf/virtchnl.h
@@ -636,6 +636,7 @@ enum virtchnl_vlan_support {
VIRTCHNL_VLAN_ETHERTYPE_8100 = BIT(0),
VIRTCHNL_VLAN_ETHERTYPE_88A8 = BIT(1),
VIRTCHNL_VLAN_ETHERTYPE_9100 = BIT(2),
+ VIRTCHNL_VLAN_ETHERTYPE_88E7 = BIT(3),
VIRTCHNL_VLAN_TAG_LOCATION_L2TAG1 = BIT(8),
VIRTCHNL_VLAN_TAG_LOCATION_L2TAG2 = BIT(9),
VIRTCHNL_VLAN_TAG_LOCATION_L2TAG2_2 = BIT(10),
|
| 3/2 | 2026/08/05 22:47 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 27433 output: 45 thoughts: 2522 Thoughts: **Analysis of the Patch Series and Fuzzing Strategy** Okay, so I'm looking at a patch series that touches several Intel Ethernet drivers: `e1000e`, `i40e`, `ice`, and `igc`. The primary concern here is how this will impact fuzzing efforts, particularly within a QEMU environment. The main drivers I'm interested in are those that are emulated. My initial assessment is that `e1000e` is definitely reachable and emulated, so it's a prime target. `i40e` and `ice` are not natively emulated in standard QEMU. `igc` is also not emulated. Therefore, my focus narrows to the `e1000e` changes. Looking at the `e1000e` diff in `netdev.c`, the changes are centered around `e1000_alloc_rx_buffers` and `e1000_clean_rx_irq`. These are core RX path functions – they're critical for receiving packets, so, by definition, they're "hot-path". This is a functional change. The prompt, however, instructs me to avoid listing *generic* hot-path functions. However, are these functions *generic* or specific to the `e1000e` driver? Because these are the *only* modified functions within the *reachable* driver, listing them feels appropriate. While they are indeed hot-path, they are *specific* to this driver and thus are ideal. I should also note that `e1000e` is being fuzzed already. Syzkaller includes descriptions for e1000e. I will also double check to see if e1000e is enabled by default or needs a config, I will need to look at its Kconfig for this. |
| 4/2 | 2026/08/05 22:47 | tool | grepper |
0mError:no matches Args: {
"Expression": "config E1000E",
"PathPrefix": "drivers/net/ethernet/intel/e1000e/Kconfig"
}Results: {
"error": "no matches"
} |
| 5/2 | 2026/08/05 22:47 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 30420 output: 38 thoughts: 20 Thoughts: Okay, here's my attempt at summarizing that thought process, tailored for an expert audience: **Kernel Configuration Hunting** Right, so I need to figure out where that network driver's Kconfig file resides. My initial hunch is to check the standard location. Intel's ethernet drivers are usually pretty well-organized within the kernel source. My first guess, based on years of experience, is that it'll be under `drivers/net/ethernet/intel/`. That directory structure is the typical home for these sorts of drivers, and Kconfig files are almost always located within the appropriate driver's subdirectory. It's the most logical place to begin my search. |
| 6/2 | 2026/08/05 22:47 | tool | grepper |
0mArgs:{
"Expression": "config E1000E",
"PathPrefix": "drivers/net/ethernet/intel/Kconfig"
}Results: {
"Output": "drivers/net/ethernet/intel/Kconfig=45=config E1000\n--\ndrivers/net/ethernet/intel/Kconfig-60-\ndrivers/net/ethernet/intel/Kconfig:61:config E1000E\ndrivers/net/ethernet/intel/Kconfig-62-\ttristate \"Intel(R) PRO/1000 PCI-Express Gigabit Ethernet support\"\n--\ndrivers/net/ethernet/intel/Kconfig-80-\ndrivers/net/ethernet/intel/Kconfig:81:config E1000E_HWTS\ndrivers/net/ethernet/intel/Kconfig-82-\tbool \"Support HW cross-timestamp on PCH devices\"\n"
} |
| 7/2 | 2026/08/05 22:47 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 30805 output: 38 thoughts: 14 Thoughts: Here's my thought process, as if I were considering the dependencies of E1000E: **Delving into the E1000E's Relationships** Okay, so we're talking about the dependencies of E1000E. Right off the bat, I need to consider this from a few angles. Firstly, I'll think about the software dependencies: What libraries, headers, and kernel modules is it relying on? Is it a standalone driver, or does it hook into some lower-level networking stack components, maybe specific network protocols or hardware abstraction layers? That could be important for understanding any potential issues and when working on it with others, it would be useful to let them know. Then, there's the hardware side. E1000E is an Intel Gigabit Ethernet controller driver, so it’s likely tightly coupled to the hardware registers and how they are handled. I would think about which specific hardware versions it supports, any specific silicon revisions that might require conditional code paths, and any firmware dependencies within the NIC itself. A deep dive into the datasheet would likely be necessary to confirm this. Finally, I would want to look at the build environment and how it's integrated into the operating system kernel. What build tools are used? How does it interact with the build system? Is it a module that is loaded at runtime, or is it compiled directly into the kernel? The kernel configuration is also a factor, particularly which features are enabled or disabled that E1000E requires. I'll need to remember to check for any dependencies on specific kernel versions or features, especially if this is an older driver. |
| 8/2 | 2026/08/05 22:47 | tool | read-file |
0mArgs:{
"File": "drivers/net/ethernet/intel/Kconfig",
"FirstLine": 60,
"LineCount": 20
}Results: {
"Contents": " 60:\t\n 61:\tconfig E1000E\n 62:\t\ttristate \"Intel(R) PRO/1000 PCI-Express Gigabit Ethernet support\"\n 63:\t\tdepends on PCI \u0026\u0026 (!SPARC32 || BROKEN)\n 64:\t\tdepends on PTP_1588_CLOCK_OPTIONAL\n 65:\t\tselect CRC32\n 66:\t\thelp\n 67:\t\t This driver supports the PCI-Express Intel(R) PRO/1000 gigabit\n 68:\t\t ethernet family of adapters. For PCI or PCI-X e1000 adapters,\n 69:\t\t use the regular e1000 driver For more information on how to\n 70:\t\t identify your adapter, go to the Adapter \u0026 Driver ID Guide that\n 71:\t\t can be located at:\n 72:\t\n 73:\t\t \u003chttp://support.intel.com\u003e\n 74:\t\n 75:\t\t More specific information on configuring the driver is in\n 76:\t\t \u003cfile:Documentation/networking/device_drivers/ethernet/intel/e1000e.rst\u003e.\n 77:\t\n 78:\t\t To compile this driver as a module, choose M here. The module\n 79:\t\t will be called e1000e.\n"
} |
| 9/2 | 2026/08/05 22:47 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 31543 output: 52 thoughts: 703 Thoughts: **Analysis of the Proposed Patch and Fuzzing Strategy** Okay, let's break this down. First, the configuration `E1000E` is definitely relevant. The patch modifies `drivers/net/ethernet/intel/e1000e/netdev.c`, so we're dealing with the e1000e network driver. Now, the question is, is this driver emulated in QEMU? Yes, e1000e is *definitely* emulated, unlike `igc`, `i40e`, or `ice` which the prompt indicates *aren't*. Thus, `E1000E` is the configuration to focus on. The patch's core modification appears to address an issue in the e1000e's receive (RX) path, specifically within the `e1000_alloc_rx_buffers` function. The code suggests a potential problem related to DMA unmapping. This suggests that this change is reachable in a simulated environment. Given that this is a fix in a real and emulated driver, I'm confident in setting `WorthFuzzing=true`. For the focus symbols, I'm initially considering `e1000_alloc_rx_buffers` and `e1000_clean_rx_irq`, because they are clearly touched by the patch. But hold on, are these functions `static`? Yes, they are. And the prompt prefers non-static functions. Because the functions are `static`, they're likely inlined by the compiler and may not have distinct symbol addresses. So, I will proceed with caution in this instance, and re-check my rationale. I'll stick with `E1000E` as the relevant config, and keep in mind these `static` functions for further analysis. |
| 10/2 | 2026/08/05 22:48 | tool | grepper |
0mArgs:{
"Expression": "e1000_clean_rx_irq",
"PathPrefix": "drivers/net/ethernet/intel/e1000e/netdev.c"
}Results: {
"Output": "drivers/net/ethernet/intel/e1000e/netdev.c=915=static inline void e1000_rx_hash(struct net_device *netdev, __le32 rss,\n--\ndrivers/net/ethernet/intel/e1000e/netdev.c-922-/**\ndrivers/net/ethernet/intel/e1000e/netdev.c:923: * e1000_clean_rx_irq - Send received data up the network stack\ndrivers/net/ethernet/intel/e1000e/netdev.c-924- * @rx_ring: Rx descriptor ring\n--\ndrivers/net/ethernet/intel/e1000e/netdev.c-930- **/\ndrivers/net/ethernet/intel/e1000e/netdev.c:931:static bool e1000_clean_rx_irq(struct e1000_ring *rx_ring, int *work_done,\ndrivers/net/ethernet/intel/e1000e/netdev.c-932-\t\t\t int work_to_do)\n--\ndrivers/net/ethernet/intel/e1000e/netdev.c=1238=static bool e1000_clean_tx_irq(struct e1000_ring *tx_ring)\n--\ndrivers/net/ethernet/intel/e1000e/netdev.c-1324-/**\ndrivers/net/ethernet/intel/e1000e/netdev.c:1325: * e1000_clean_rx_irq_ps - Send received data up the network stack; packet split\ndrivers/net/ethernet/intel/e1000e/netdev.c-1326- * @rx_ring: Rx descriptor ring\n--\ndrivers/net/ethernet/intel/e1000e/netdev.c-1332- **/\ndrivers/net/ethernet/intel/e1000e/netdev.c:1333:static bool e1000_clean_rx_irq_ps(struct e1000_ring *rx_ring, int *work_done,\ndrivers/net/ethernet/intel/e1000e/netdev.c-1334-\t\t\t\t int work_to_do)\n--\ndrivers/net/ethernet/intel/e1000e/netdev.c=1694=static void e1000_clean_rx_ring(struct e1000_ring *rx_ring)\n--\ndrivers/net/ethernet/intel/e1000e/netdev.c-1705-\t\tif (buffer_info-\u003edma) {\ndrivers/net/ethernet/intel/e1000e/netdev.c:1706:\t\t\tif (adapter-\u003eclean_rx == e1000_clean_rx_irq)\ndrivers/net/ethernet/intel/e1000e/netdev.c-1707-\t\t\t\tdma_unmap_single(\u0026pdev-\u003edev, buffer_info-\u003edma,\n--\ndrivers/net/ethernet/intel/e1000e/netdev.c-1712-\t\t\t\t\t PAGE_SIZE, DMA_FROM_DEVICE);\ndrivers/net/ethernet/intel/e1000e/netdev.c:1713:\t\t\telse if (adapter-\u003eclean_rx == e1000_clean_rx_irq_ps)\ndrivers/net/ethernet/intel/e1000e/netdev.c-1714-\t\t\t\tdma_unmap_single(\u0026pdev-\u003edev, buffer_info-\u003edma,\n--\ndrivers/net/ethernet/intel/e1000e/netdev.c=3203=static void e1000_configure_rx(struct e1000_adapter *adapter)\n--\ndrivers/net/ethernet/intel/e1000e/netdev.c-3213-\t\t sizeof(union e1000_rx_desc_packet_split);\ndrivers/net/ethernet/intel/e1000e/netdev.c:3214:\t\tadapter-\u003eclean_rx = e1000_clean_rx_irq_ps;\ndrivers/net/ethernet/intel/e1000e/netdev.c-3215-\t\tadapter-\u003ealloc_rx_buf = e1000_alloc_rx_buffers_ps;\n--\ndrivers/net/ethernet/intel/e1000e/netdev.c-3221-\t\trdlen = rx_ring-\u003ecount * sizeof(union e1000_rx_desc_extended);\ndrivers/net/ethernet/intel/e1000e/netdev.c:3222:\t\tadapter-\u003eclean_rx = e1000_clean_rx_irq;\ndrivers/net/ethernet/intel/e1000e/netdev.c-3223-\t\tadapter-\u003ealloc_rx_buf = e1000_alloc_rx_buffers;\n"
} |
| 11/2 | 2026/08/05 22:48 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 33984 output: 160 thoughts: 247 Thoughts: **Analyzing the E1000E Driver's Rx Path** Okay, so I'm diving into this code. The first thing I've got to understand is the interrupt-driven RX path for the emulated E1000E device. These functions, `adapter->clean_rx = e1000_clean_rx_irq;` and so on, are assigned via function pointers, which immediately tells me they aren't inlined. That's good; it keeps things manageable. I see there's some broader activity with XDP metadata operations; the patch seems to touch `i40e_xdp_rx_hash` and `i40e_xdp_rx_vlan_tag`. Plus, there are modifications for the `ice` and `igc` drivers as well. Since this is an emulation context, and the only emulated device in play here is E1000E, my focus is definitely going to be on that driver. Now, I'll quickly confirm that `E1000E` is the *only* necessary configuration flag to enable the E1000E support. Alright, yep, confirmed. That simplifies things considerably. Next step: I need to verify what's happening in `e1000e/netdev.c` regarding the RX buffer allocation and cleaning. I'll need to check `e1000_alloc_rx_buffers` and specifically `e1000_clean_rx_irq` to confirm the code structure, and make sure that, as suspected, they are not inlined. Looks like there aren't any other relevant configurations beyond `E1000E` that will impact this. Alright, I'm ready to proceed with using the `set-results` tool, as I've got a good handle on where the key functions reside and how they are used. |
| 12/2 | 2026/08/05 22:48 | tool | set-results |
0mArgs:{
"EnableConfigs": [
"E1000E"
],
"FocusSymbols": [
"e1000_alloc_rx_buffers",
"e1000_clean_rx_irq"
],
"Reasoning": "The patch modifies the RX path of the e1000e driver (e1000_alloc_rx_buffers and e1000_clean_rx_irq), which is fully emulated in QEMU and reachable. It also modifies i40e, ice, and igc drivers, but those are not natively emulated in standard QEMU. We focus on the e1000e changes.",
"WorthFuzzing": true
}Results: {
"EnableConfigs": [
"E1000E"
],
"FocusSymbols": [
"e1000_alloc_rx_buffers",
"e1000_clean_rx_irq"
],
"Reasoning": "The patch modifies the RX path of the e1000e driver (e1000_alloc_rx_buffers and e1000_clean_rx_irq), which is fully emulated in QEMU and reachable. It also modifies i40e, ice, and igc drivers, but those are not natively emulated in standard QEMU. We focus on the e1000e changes.",
"WorthFuzzing": true
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|