From: Sasha Levin Date: Mon, 9 Dec 2024 11:18:29 +0000 (-0500) Subject: Fixes for 6.6 X-Git-Tag: v6.6.65~49 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e8363c272a271116aafc5b0d41799627b82c6c24;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for 6.6 Signed-off-by: Sasha Levin --- diff --git a/queue-6.6/can-c_can-c_can_handle_bus_err-update-statistics-if-.patch b/queue-6.6/can-c_can-c_can_handle_bus_err-update-statistics-if-.patch new file mode 100644 index 00000000000..45f1df11fe7 --- /dev/null +++ b/queue-6.6/can-c_can-c_can_handle_bus_err-update-statistics-if-.patch @@ -0,0 +1,96 @@ +From 03881dba95f32762f86a058a5c864b27e34427fd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 Nov 2024 23:15:42 +0100 +Subject: can: c_can: c_can_handle_bus_err(): update statistics if skb + allocation fails + +From: Dario Binacchi + +[ Upstream commit 9e66242504f49e17481d8e197730faba7d99c934 ] + +Ensure that the statistics are always updated, even if the skb +allocation fails. + +Fixes: 4d6d26537940 ("can: c_can: fix {rx,tx}_errors statistics") +Signed-off-by: Dario Binacchi +Link: https://patch.msgid.link/20241122221650.633981-2-dario.binacchi@amarulasolutions.com +Signed-off-by: Marc Kleine-Budde +Signed-off-by: Sasha Levin +--- + drivers/net/can/c_can/c_can_main.c | 26 +++++++++++++++++--------- + 1 file changed, 17 insertions(+), 9 deletions(-) + +diff --git a/drivers/net/can/c_can/c_can_main.c b/drivers/net/can/c_can/c_can_main.c +index 511615dc33419..cc371d0c9f3c7 100644 +--- a/drivers/net/can/c_can/c_can_main.c ++++ b/drivers/net/can/c_can/c_can_main.c +@@ -1014,49 +1014,57 @@ static int c_can_handle_bus_err(struct net_device *dev, + + /* propagate the error condition to the CAN stack */ + skb = alloc_can_err_skb(dev, &cf); +- if (unlikely(!skb)) +- return 0; + + /* check for 'last error code' which tells us the + * type of the last error to occur on the CAN bus + */ +- cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; ++ if (likely(skb)) ++ cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; + + switch (lec_type) { + case LEC_STUFF_ERROR: + netdev_dbg(dev, "stuff error\n"); +- cf->data[2] |= CAN_ERR_PROT_STUFF; ++ if (likely(skb)) ++ cf->data[2] |= CAN_ERR_PROT_STUFF; + stats->rx_errors++; + break; + case LEC_FORM_ERROR: + netdev_dbg(dev, "form error\n"); +- cf->data[2] |= CAN_ERR_PROT_FORM; ++ if (likely(skb)) ++ cf->data[2] |= CAN_ERR_PROT_FORM; + stats->rx_errors++; + break; + case LEC_ACK_ERROR: + netdev_dbg(dev, "ack error\n"); +- cf->data[3] = CAN_ERR_PROT_LOC_ACK; ++ if (likely(skb)) ++ cf->data[3] = CAN_ERR_PROT_LOC_ACK; + stats->tx_errors++; + break; + case LEC_BIT1_ERROR: + netdev_dbg(dev, "bit1 error\n"); +- cf->data[2] |= CAN_ERR_PROT_BIT1; ++ if (likely(skb)) ++ cf->data[2] |= CAN_ERR_PROT_BIT1; + stats->tx_errors++; + break; + case LEC_BIT0_ERROR: + netdev_dbg(dev, "bit0 error\n"); +- cf->data[2] |= CAN_ERR_PROT_BIT0; ++ if (likely(skb)) ++ cf->data[2] |= CAN_ERR_PROT_BIT0; + stats->tx_errors++; + break; + case LEC_CRC_ERROR: + netdev_dbg(dev, "CRC error\n"); +- cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; ++ if (likely(skb)) ++ cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; + stats->rx_errors++; + break; + default: + break; + } + ++ if (unlikely(!skb)) ++ return 0; ++ + netif_receive_skb(skb); + return 1; + } +-- +2.43.0 + diff --git a/queue-6.6/can-ems_usb-ems_usb_rx_err-fix-rx-tx-_errors-statist.patch b/queue-6.6/can-ems_usb-ems_usb_rx_err-fix-rx-tx-_errors-statist.patch new file mode 100644 index 00000000000..6d779bc2508 --- /dev/null +++ b/queue-6.6/can-ems_usb-ems_usb_rx_err-fix-rx-tx-_errors-statist.patch @@ -0,0 +1,126 @@ +From 26ce242f03658fecc4c03ffefbc9fcb06a19c781 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 Nov 2024 23:15:52 +0100 +Subject: can: ems_usb: ems_usb_rx_err(): fix {rx,tx}_errors statistics + +From: Dario Binacchi + +[ Upstream commit 72a7e2e74b3075959f05e622bae09b115957dffe ] + +The ems_usb_rx_err() function only incremented the receive error counter +and never the transmit error counter, even if the ECC_DIR flag reported +that an error had occurred during transmission. + +Increment the receive/transmit error counter based on the value of the +ECC_DIR flag. + +Fixes: 702171adeed3 ("ems_usb: Added support for EMS CPC-USB/ARM7 CAN/USB interface") +Signed-off-by: Dario Binacchi +Link: https://patch.msgid.link/20241122221650.633981-12-dario.binacchi@amarulasolutions.com +Signed-off-by: Marc Kleine-Budde +Signed-off-by: Sasha Levin +--- + drivers/net/can/usb/ems_usb.c | 58 ++++++++++++++++++++--------------- + 1 file changed, 33 insertions(+), 25 deletions(-) + +diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c +index 050c0b49938a4..5355bac4dccbe 100644 +--- a/drivers/net/can/usb/ems_usb.c ++++ b/drivers/net/can/usb/ems_usb.c +@@ -335,15 +335,14 @@ static void ems_usb_rx_err(struct ems_usb *dev, struct ems_cpc_msg *msg) + struct net_device_stats *stats = &dev->netdev->stats; + + skb = alloc_can_err_skb(dev->netdev, &cf); +- if (skb == NULL) +- return; + + if (msg->type == CPC_MSG_TYPE_CAN_STATE) { + u8 state = msg->msg.can_state; + + if (state & SJA1000_SR_BS) { + dev->can.state = CAN_STATE_BUS_OFF; +- cf->can_id |= CAN_ERR_BUSOFF; ++ if (skb) ++ cf->can_id |= CAN_ERR_BUSOFF; + + dev->can.can_stats.bus_off++; + can_bus_off(dev->netdev); +@@ -361,44 +360,53 @@ static void ems_usb_rx_err(struct ems_usb *dev, struct ems_cpc_msg *msg) + + /* bus error interrupt */ + dev->can.can_stats.bus_error++; +- stats->rx_errors++; + +- cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; ++ if (skb) { ++ cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; + +- switch (ecc & SJA1000_ECC_MASK) { +- case SJA1000_ECC_BIT: +- cf->data[2] |= CAN_ERR_PROT_BIT; +- break; +- case SJA1000_ECC_FORM: +- cf->data[2] |= CAN_ERR_PROT_FORM; +- break; +- case SJA1000_ECC_STUFF: +- cf->data[2] |= CAN_ERR_PROT_STUFF; +- break; +- default: +- cf->data[3] = ecc & SJA1000_ECC_SEG; +- break; ++ switch (ecc & SJA1000_ECC_MASK) { ++ case SJA1000_ECC_BIT: ++ cf->data[2] |= CAN_ERR_PROT_BIT; ++ break; ++ case SJA1000_ECC_FORM: ++ cf->data[2] |= CAN_ERR_PROT_FORM; ++ break; ++ case SJA1000_ECC_STUFF: ++ cf->data[2] |= CAN_ERR_PROT_STUFF; ++ break; ++ default: ++ cf->data[3] = ecc & SJA1000_ECC_SEG; ++ break; ++ } + } + + /* Error occurred during transmission? */ +- if ((ecc & SJA1000_ECC_DIR) == 0) +- cf->data[2] |= CAN_ERR_PROT_TX; ++ if ((ecc & SJA1000_ECC_DIR) == 0) { ++ stats->tx_errors++; ++ if (skb) ++ cf->data[2] |= CAN_ERR_PROT_TX; ++ } else { ++ stats->rx_errors++; ++ } + +- if (dev->can.state == CAN_STATE_ERROR_WARNING || +- dev->can.state == CAN_STATE_ERROR_PASSIVE) { ++ if (skb && (dev->can.state == CAN_STATE_ERROR_WARNING || ++ dev->can.state == CAN_STATE_ERROR_PASSIVE)) { + cf->can_id |= CAN_ERR_CRTL; + cf->data[1] = (txerr > rxerr) ? + CAN_ERR_CRTL_TX_PASSIVE : CAN_ERR_CRTL_RX_PASSIVE; + } + } else if (msg->type == CPC_MSG_TYPE_OVERRUN) { +- cf->can_id |= CAN_ERR_CRTL; +- cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; ++ if (skb) { ++ cf->can_id |= CAN_ERR_CRTL; ++ cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; ++ } + + stats->rx_over_errors++; + stats->rx_errors++; + } + +- netif_rx(skb); ++ if (skb) ++ netif_rx(skb); + } + + /* +-- +2.43.0 + diff --git a/queue-6.6/can-f81604-f81604_handle_can_bus_errors-fix-rx-tx-_e.patch b/queue-6.6/can-f81604-f81604_handle_can_bus_errors-fix-rx-tx-_e.patch new file mode 100644 index 00000000000..0beef839a48 --- /dev/null +++ b/queue-6.6/can-f81604-f81604_handle_can_bus_errors-fix-rx-tx-_e.patch @@ -0,0 +1,59 @@ +From 79c18bbd3f10adf36c9e01319d04567db36b2481 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 Nov 2024 23:15:53 +0100 +Subject: can: f81604: f81604_handle_can_bus_errors(): fix {rx,tx}_errors + statistics + +From: Dario Binacchi + +[ Upstream commit d7b916540c2ba3d2a88c27b2a6287b39d8eac052 ] + +The f81604_handle_can_bus_errors() function only incremented the receive +error counter and never the transmit error counter, even if the ECC_DIR +flag reported that an error had occurred during transmission. + +Increment the receive/transmit error counter based on the value of the +ECC_DIR flag. + +Fixes: 88da17436973 ("can: usb: f81604: add Fintek F81604 support") +Signed-off-by: Dario Binacchi +Link: https://patch.msgid.link/20241122221650.633981-13-dario.binacchi@amarulasolutions.com +Signed-off-by: Marc Kleine-Budde +Signed-off-by: Sasha Levin +--- + drivers/net/can/usb/f81604.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/can/usb/f81604.c b/drivers/net/can/usb/f81604.c +index ec8cef7fd2d53..fb9fb16507f0b 100644 +--- a/drivers/net/can/usb/f81604.c ++++ b/drivers/net/can/usb/f81604.c +@@ -526,7 +526,6 @@ static void f81604_handle_can_bus_errors(struct f81604_port_priv *priv, + netdev_dbg(netdev, "bus error interrupt\n"); + + priv->can.can_stats.bus_error++; +- stats->rx_errors++; + + if (skb) { + cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; +@@ -548,10 +547,15 @@ static void f81604_handle_can_bus_errors(struct f81604_port_priv *priv, + + /* set error location */ + cf->data[3] = data->ecc & F81604_SJA1000_ECC_SEG; ++ } + +- /* Error occurred during transmission? */ +- if ((data->ecc & F81604_SJA1000_ECC_DIR) == 0) ++ /* Error occurred during transmission? */ ++ if ((data->ecc & F81604_SJA1000_ECC_DIR) == 0) { ++ stats->tx_errors++; ++ if (skb) + cf->data[2] |= CAN_ERR_PROT_TX; ++ } else { ++ stats->rx_errors++; + } + + set_bit(F81604_CLEAR_ECC, &priv->clear_flags); +-- +2.43.0 + diff --git a/queue-6.6/can-gs_usb-add-usb-endpoint-address-detection-at-dri.patch b/queue-6.6/can-gs_usb-add-usb-endpoint-address-detection-at-dri.patch new file mode 100644 index 00000000000..e30e42dedd0 --- /dev/null +++ b/queue-6.6/can-gs_usb-add-usb-endpoint-address-detection-at-dri.patch @@ -0,0 +1,138 @@ +From ced30bbf6aa465629eccf76344bbd345e73e9df9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 18 Oct 2024 23:24:26 +0200 +Subject: can: gs_usb: add usb endpoint address detection at driver probe step + +From: Alexander Kozhinov + +[ Upstream commit 889b2ae9139a87b3390f7003cb1bb3d65bf90a26 ] + +There is an approach made to implement gs_usb firmware/driver based on +Zephyr RTOS. It was found that USB stack of Zephyr RTOS overwrites USB +EP addresses, if they have different last 4 bytes in absence of other +endpoints. + +For example in case of gs_usb candlelight firmware EP-IN is 0x81 and +EP-OUT 0x02. If there are no additional USB endpoints, Zephyr RTOS will +overwrite EP-OUT to 0x01. More information can be found in the +discussion with Zephyr RTOS USB stack maintainer here: + +https://github.com/zephyrproject-rtos/zephyr/issues/67812 + +There are already two different gs_usb FW driver implementations based +on Zephyr RTOS: + +1. https://github.com/CANnectivity/cannectivity + (by: https://github.com/henrikbrixandersen) +2. https://github.com/zephyrproject-rtos/zephyr/compare/main...KozhinovAlexander:zephyr:gs_usb + (by: https://github.com/KozhinovAlexander) + +At the moment both Zephyr RTOS implementations use dummy USB endpoint, +to overcome described USB stack behavior from Zephyr itself. Since +Zephyr RTOS is intended to be used on microcontrollers with very +constrained amount of resources (ROM, RAM) and additional endpoint +requires memory, it is more convenient to update the gs_usb driver in +the Linux kernel. + +To fix this problem, update the gs_usb driver from using hard coded +endpoint numbers to evaluate the endpoint descriptors and use the +endpoints provided there. + +Fixes: d08e973a77d1 ("can: gs_usb: Added support for the GS_USB CAN devices") +Reviewed-by: Vincent Mailhol +Signed-off-by: Alexander Kozhinov +Link: https://patch.msgid.link/20241018212450.31746-1-ak.alexander.kozhinov@gmail.com +Signed-off-by: Marc Kleine-Budde +Signed-off-by: Sasha Levin +--- + drivers/net/can/usb/gs_usb.c | 25 ++++++++++++++++++------- + 1 file changed, 18 insertions(+), 7 deletions(-) + +diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c +index ed59451f03cdd..de616d6589c0b 100644 +--- a/drivers/net/can/usb/gs_usb.c ++++ b/drivers/net/can/usb/gs_usb.c +@@ -43,9 +43,6 @@ + #define USB_XYLANTA_SAINT3_VENDOR_ID 0x16d0 + #define USB_XYLANTA_SAINT3_PRODUCT_ID 0x0f30 + +-#define GS_USB_ENDPOINT_IN 1 +-#define GS_USB_ENDPOINT_OUT 2 +- + /* Timestamp 32 bit timer runs at 1 MHz (1 µs tick). Worker accounts + * for timer overflow (will be after ~71 minutes) + */ +@@ -336,6 +333,9 @@ struct gs_usb { + + unsigned int hf_size_rx; + u8 active_channels; ++ ++ unsigned int pipe_in; ++ unsigned int pipe_out; + }; + + /* 'allocate' a tx context. +@@ -687,7 +687,7 @@ static void gs_usb_receive_bulk_callback(struct urb *urb) + + resubmit_urb: + usb_fill_bulk_urb(urb, parent->udev, +- usb_rcvbulkpipe(parent->udev, GS_USB_ENDPOINT_IN), ++ parent->pipe_in, + hf, dev->parent->hf_size_rx, + gs_usb_receive_bulk_callback, parent); + +@@ -819,7 +819,7 @@ static netdev_tx_t gs_can_start_xmit(struct sk_buff *skb, + } + + usb_fill_bulk_urb(urb, dev->udev, +- usb_sndbulkpipe(dev->udev, GS_USB_ENDPOINT_OUT), ++ dev->parent->pipe_out, + hf, dev->hf_size_tx, + gs_usb_xmit_callback, txc); + +@@ -925,8 +925,7 @@ static int gs_can_open(struct net_device *netdev) + /* fill, anchor, and submit rx urb */ + usb_fill_bulk_urb(urb, + dev->udev, +- usb_rcvbulkpipe(dev->udev, +- GS_USB_ENDPOINT_IN), ++ dev->parent->pipe_in, + buf, + dev->parent->hf_size_rx, + gs_usb_receive_bulk_callback, parent); +@@ -1413,6 +1412,7 @@ static int gs_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) + { + struct usb_device *udev = interface_to_usbdev(intf); ++ struct usb_endpoint_descriptor *ep_in, *ep_out; + struct gs_host_frame *hf; + struct gs_usb *parent; + struct gs_host_config hconf = { +@@ -1422,6 +1422,13 @@ static int gs_usb_probe(struct usb_interface *intf, + unsigned int icount, i; + int rc; + ++ rc = usb_find_common_endpoints(intf->cur_altsetting, ++ &ep_in, &ep_out, NULL, NULL); ++ if (rc) { ++ dev_err(&intf->dev, "Required endpoints not found\n"); ++ return rc; ++ } ++ + /* send host config */ + rc = usb_control_msg_send(udev, 0, + GS_USB_BREQ_HOST_FORMAT, +@@ -1466,6 +1473,10 @@ static int gs_usb_probe(struct usb_interface *intf, + usb_set_intfdata(intf, parent); + parent->udev = udev; + ++ /* store the detected endpoints */ ++ parent->pipe_in = usb_rcvbulkpipe(parent->udev, ep_in->bEndpointAddress); ++ parent->pipe_out = usb_sndbulkpipe(parent->udev, ep_out->bEndpointAddress); ++ + for (i = 0; i < icount; i++) { + unsigned int hf_size_rx = 0; + +-- +2.43.0 + diff --git a/queue-6.6/can-gs_usb-add-vid-pid-for-xylanta-saint3-product-fa.patch b/queue-6.6/can-gs_usb-add-vid-pid-for-xylanta-saint3-product-fa.patch new file mode 100644 index 00000000000..4bb01af0ee2 --- /dev/null +++ b/queue-6.6/can-gs_usb-add-vid-pid-for-xylanta-saint3-product-fa.patch @@ -0,0 +1,48 @@ +From c6584ec49db0d12f88974454e13041b9968a1c06 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 25 Jun 2024 16:03:52 +0200 +Subject: can: gs_usb: add VID/PID for Xylanta SAINT3 product family + +From: Marc Kleine-Budde + +[ Upstream commit 69e2326a21ef409d6c709cb990565331727b9f27 ] + +Add support for the Xylanta SAINT3 product family. + +Cc: Andy Jackson +Cc: Ken Aitchison +Tested-by: Andy Jackson +Link: https://lore.kernel.org/all/20240625140353.769373-1-mkl@pengutronix.de +Signed-off-by: Marc Kleine-Budde +Stable-dep-of: 889b2ae9139a ("can: gs_usb: add usb endpoint address detection at driver probe step") +Signed-off-by: Sasha Levin +--- + drivers/net/can/usb/gs_usb.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c +index 95b0fdb602c8f..ed59451f03cdd 100644 +--- a/drivers/net/can/usb/gs_usb.c ++++ b/drivers/net/can/usb/gs_usb.c +@@ -40,6 +40,9 @@ + #define USB_ABE_CANDEBUGGER_FD_VENDOR_ID 0x16d0 + #define USB_ABE_CANDEBUGGER_FD_PRODUCT_ID 0x10b8 + ++#define USB_XYLANTA_SAINT3_VENDOR_ID 0x16d0 ++#define USB_XYLANTA_SAINT3_PRODUCT_ID 0x0f30 ++ + #define GS_USB_ENDPOINT_IN 1 + #define GS_USB_ENDPOINT_OUT 2 + +@@ -1530,6 +1533,8 @@ static const struct usb_device_id gs_usb_table[] = { + USB_CES_CANEXT_FD_PRODUCT_ID, 0) }, + { USB_DEVICE_INTERFACE_NUMBER(USB_ABE_CANDEBUGGER_FD_VENDOR_ID, + USB_ABE_CANDEBUGGER_FD_PRODUCT_ID, 0) }, ++ { USB_DEVICE_INTERFACE_NUMBER(USB_XYLANTA_SAINT3_VENDOR_ID, ++ USB_XYLANTA_SAINT3_PRODUCT_ID, 0) }, + {} /* Terminating entry */ + }; + +-- +2.43.0 + diff --git a/queue-6.6/can-hi311x-hi3110_can_ist-fix-potential-use-after-fr.patch b/queue-6.6/can-hi311x-hi3110_can_ist-fix-potential-use-after-fr.patch new file mode 100644 index 00000000000..13f1d27601a --- /dev/null +++ b/queue-6.6/can-hi311x-hi3110_can_ist-fix-potential-use-after-fr.patch @@ -0,0 +1,55 @@ +From 48ecbd4bf967fc428cf9027685aef41bd86408e1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 Nov 2024 23:15:45 +0100 +Subject: can: hi311x: hi3110_can_ist(): fix potential use-after-free + +From: Dario Binacchi + +[ Upstream commit 9ad86d377ef4a19c75a9c639964879a5b25a433b ] + +The commit a22bd630cfff ("can: hi311x: do not report txerr and rxerr +during bus-off") removed the reporting of rxerr and txerr even in case +of correct operation (i. e. not bus-off). + +The error count information added to the CAN frame after netif_rx() is +a potential use after free, since there is no guarantee that the skb +is in the same state. It might be freed or reused. + +Fix the issue by postponing the netif_rx() call in case of txerr and +rxerr reporting. + +Fixes: a22bd630cfff ("can: hi311x: do not report txerr and rxerr during bus-off") +Signed-off-by: Dario Binacchi +Link: https://patch.msgid.link/20241122221650.633981-5-dario.binacchi@amarulasolutions.com +Signed-off-by: Marc Kleine-Budde +Signed-off-by: Sasha Levin +--- + drivers/net/can/spi/hi311x.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/can/spi/hi311x.c b/drivers/net/can/spi/hi311x.c +index e1b8533a602e2..fb58e294f7b79 100644 +--- a/drivers/net/can/spi/hi311x.c ++++ b/drivers/net/can/spi/hi311x.c +@@ -671,9 +671,9 @@ static irqreturn_t hi3110_can_ist(int irq, void *dev_id) + tx_state = txerr >= rxerr ? new_state : 0; + rx_state = txerr <= rxerr ? new_state : 0; + can_change_state(net, cf, tx_state, rx_state); +- netif_rx(skb); + + if (new_state == CAN_STATE_BUS_OFF) { ++ netif_rx(skb); + can_bus_off(net); + if (priv->can.restart_ms == 0) { + priv->force_quit = 1; +@@ -684,6 +684,7 @@ static irqreturn_t hi3110_can_ist(int irq, void *dev_id) + cf->can_id |= CAN_ERR_CNT; + cf->data[6] = txerr; + cf->data[7] = rxerr; ++ netif_rx(skb); + } + } + +-- +2.43.0 + diff --git a/queue-6.6/can-hi311x-hi3110_can_ist-fix-rx-tx-_errors-statisti.patch b/queue-6.6/can-hi311x-hi3110_can_ist-fix-rx-tx-_errors-statisti.patch new file mode 100644 index 00000000000..f525c905438 --- /dev/null +++ b/queue-6.6/can-hi311x-hi3110_can_ist-fix-rx-tx-_errors-statisti.patch @@ -0,0 +1,89 @@ +From a8c11ccdf258bded6d6ba5daee789ac661d2dd2e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 Nov 2024 23:15:49 +0100 +Subject: can: hi311x: hi3110_can_ist(): fix {rx,tx}_errors statistics + +From: Dario Binacchi + +[ Upstream commit 3e4645931655776e757f9fb5ae29371cd7cb21a2 ] + +The hi3110_can_ist() function was incorrectly incrementing only the +receive error counter, even in cases of bit or acknowledgment errors that +occur during transmission. + +The fix the issue by incrementing the appropriate counter based on the +type of error. + +Fixes: 57e83fb9b746 ("can: hi311x: Add Holt HI-311x CAN driver") +Signed-off-by: Dario Binacchi +Link: https://patch.msgid.link/20241122221650.633981-9-dario.binacchi@amarulasolutions.com +Signed-off-by: Marc Kleine-Budde +Signed-off-by: Sasha Levin +--- + drivers/net/can/spi/hi311x.c | 47 ++++++++++++++++++++++-------------- + 1 file changed, 29 insertions(+), 18 deletions(-) + +diff --git a/drivers/net/can/spi/hi311x.c b/drivers/net/can/spi/hi311x.c +index fb58e294f7b79..b757555ed4c4f 100644 +--- a/drivers/net/can/spi/hi311x.c ++++ b/drivers/net/can/spi/hi311x.c +@@ -697,27 +697,38 @@ static irqreturn_t hi3110_can_ist(int irq, void *dev_id) + /* Check for protocol errors */ + if (eflag & HI3110_ERR_PROTOCOL_MASK) { + skb = alloc_can_err_skb(net, &cf); +- if (!skb) +- break; ++ if (skb) ++ cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; + +- cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; + priv->can.can_stats.bus_error++; +- priv->net->stats.rx_errors++; +- if (eflag & HI3110_ERR_BITERR) +- cf->data[2] |= CAN_ERR_PROT_BIT; +- else if (eflag & HI3110_ERR_FRMERR) +- cf->data[2] |= CAN_ERR_PROT_FORM; +- else if (eflag & HI3110_ERR_STUFERR) +- cf->data[2] |= CAN_ERR_PROT_STUFF; +- else if (eflag & HI3110_ERR_CRCERR) +- cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ; +- else if (eflag & HI3110_ERR_ACKERR) +- cf->data[3] |= CAN_ERR_PROT_LOC_ACK; +- +- cf->data[6] = hi3110_read(spi, HI3110_READ_TEC); +- cf->data[7] = hi3110_read(spi, HI3110_READ_REC); ++ if (eflag & HI3110_ERR_BITERR) { ++ priv->net->stats.tx_errors++; ++ if (skb) ++ cf->data[2] |= CAN_ERR_PROT_BIT; ++ } else if (eflag & HI3110_ERR_FRMERR) { ++ priv->net->stats.rx_errors++; ++ if (skb) ++ cf->data[2] |= CAN_ERR_PROT_FORM; ++ } else if (eflag & HI3110_ERR_STUFERR) { ++ priv->net->stats.rx_errors++; ++ if (skb) ++ cf->data[2] |= CAN_ERR_PROT_STUFF; ++ } else if (eflag & HI3110_ERR_CRCERR) { ++ priv->net->stats.rx_errors++; ++ if (skb) ++ cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ; ++ } else if (eflag & HI3110_ERR_ACKERR) { ++ priv->net->stats.tx_errors++; ++ if (skb) ++ cf->data[3] |= CAN_ERR_PROT_LOC_ACK; ++ } ++ + netdev_dbg(priv->net, "Bus Error\n"); +- netif_rx(skb); ++ if (skb) { ++ cf->data[6] = hi3110_read(spi, HI3110_READ_TEC); ++ cf->data[7] = hi3110_read(spi, HI3110_READ_REC); ++ netif_rx(skb); ++ } + } + } + +-- +2.43.0 + diff --git a/queue-6.6/can-ifi_canfd-ifi_canfd_handle_lec_err-fix-rx-tx-_er.patch b/queue-6.6/can-ifi_canfd-ifi_canfd_handle_lec_err-fix-rx-tx-_er.patch new file mode 100644 index 00000000000..2ff29a582b5 --- /dev/null +++ b/queue-6.6/can-ifi_canfd-ifi_canfd_handle_lec_err-fix-rx-tx-_er.patch @@ -0,0 +1,118 @@ +From 94a8c514f07e7beec8df7de3c7407e1d7200c712 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 Nov 2024 23:15:48 +0100 +Subject: can: ifi_canfd: ifi_canfd_handle_lec_err(): fix {rx,tx}_errors + statistics + +From: Dario Binacchi + +[ Upstream commit bb03d568bb21b4afe7935d1943bcf68ddea3ea45 ] + +The ifi_canfd_handle_lec_err() function was incorrectly incrementing only +the receive error counter, even in cases of bit or acknowledgment errors +that occur during transmission. + +Fix the issue by incrementing the appropriate counter based on the +type of error. + +Fixes: 5bbd655a8bd0 ("can: ifi: Add more detailed error reporting") +Signed-off-by: Dario Binacchi +Reviewed-by: Marek Vasut +Link: https://patch.msgid.link/20241122221650.633981-8-dario.binacchi@amarulasolutions.com +Signed-off-by: Marc Kleine-Budde +Signed-off-by: Sasha Levin +--- + drivers/net/can/ifi_canfd/ifi_canfd.c | 58 ++++++++++++++++++--------- + 1 file changed, 40 insertions(+), 18 deletions(-) + +diff --git a/drivers/net/can/ifi_canfd/ifi_canfd.c b/drivers/net/can/ifi_canfd/ifi_canfd.c +index 72307297d75e4..5145a6a73d2d7 100644 +--- a/drivers/net/can/ifi_canfd/ifi_canfd.c ++++ b/drivers/net/can/ifi_canfd/ifi_canfd.c +@@ -390,36 +390,55 @@ static int ifi_canfd_handle_lec_err(struct net_device *ndev) + return 0; + + priv->can.can_stats.bus_error++; +- stats->rx_errors++; + + /* Propagate the error condition to the CAN stack. */ + skb = alloc_can_err_skb(ndev, &cf); +- if (unlikely(!skb)) +- return 0; + + /* Read the error counter register and check for new errors. */ +- cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; ++ if (likely(skb)) ++ cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; + +- if (errctr & IFI_CANFD_ERROR_CTR_OVERLOAD_FIRST) +- cf->data[2] |= CAN_ERR_PROT_OVERLOAD; ++ if (errctr & IFI_CANFD_ERROR_CTR_OVERLOAD_FIRST) { ++ stats->rx_errors++; ++ if (likely(skb)) ++ cf->data[2] |= CAN_ERR_PROT_OVERLOAD; ++ } + +- if (errctr & IFI_CANFD_ERROR_CTR_ACK_ERROR_FIRST) +- cf->data[3] = CAN_ERR_PROT_LOC_ACK; ++ if (errctr & IFI_CANFD_ERROR_CTR_ACK_ERROR_FIRST) { ++ stats->tx_errors++; ++ if (likely(skb)) ++ cf->data[3] = CAN_ERR_PROT_LOC_ACK; ++ } + +- if (errctr & IFI_CANFD_ERROR_CTR_BIT0_ERROR_FIRST) +- cf->data[2] |= CAN_ERR_PROT_BIT0; ++ if (errctr & IFI_CANFD_ERROR_CTR_BIT0_ERROR_FIRST) { ++ stats->tx_errors++; ++ if (likely(skb)) ++ cf->data[2] |= CAN_ERR_PROT_BIT0; ++ } + +- if (errctr & IFI_CANFD_ERROR_CTR_BIT1_ERROR_FIRST) +- cf->data[2] |= CAN_ERR_PROT_BIT1; ++ if (errctr & IFI_CANFD_ERROR_CTR_BIT1_ERROR_FIRST) { ++ stats->tx_errors++; ++ if (likely(skb)) ++ cf->data[2] |= CAN_ERR_PROT_BIT1; ++ } + +- if (errctr & IFI_CANFD_ERROR_CTR_STUFF_ERROR_FIRST) +- cf->data[2] |= CAN_ERR_PROT_STUFF; ++ if (errctr & IFI_CANFD_ERROR_CTR_STUFF_ERROR_FIRST) { ++ stats->rx_errors++; ++ if (likely(skb)) ++ cf->data[2] |= CAN_ERR_PROT_STUFF; ++ } + +- if (errctr & IFI_CANFD_ERROR_CTR_CRC_ERROR_FIRST) +- cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; ++ if (errctr & IFI_CANFD_ERROR_CTR_CRC_ERROR_FIRST) { ++ stats->rx_errors++; ++ if (likely(skb)) ++ cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; ++ } + +- if (errctr & IFI_CANFD_ERROR_CTR_FORM_ERROR_FIRST) +- cf->data[2] |= CAN_ERR_PROT_FORM; ++ if (errctr & IFI_CANFD_ERROR_CTR_FORM_ERROR_FIRST) { ++ stats->rx_errors++; ++ if (likely(skb)) ++ cf->data[2] |= CAN_ERR_PROT_FORM; ++ } + + /* Reset the error counter, ack the IRQ and re-enable the counter. */ + writel(IFI_CANFD_ERROR_CTR_ER_RESET, priv->base + IFI_CANFD_ERROR_CTR); +@@ -427,6 +446,9 @@ static int ifi_canfd_handle_lec_err(struct net_device *ndev) + priv->base + IFI_CANFD_INTERRUPT); + writel(IFI_CANFD_ERROR_CTR_ER_ENABLE, priv->base + IFI_CANFD_ERROR_CTR); + ++ if (unlikely(!skb)) ++ return 0; ++ + netif_receive_skb(skb); + + return 1; +-- +2.43.0 + diff --git a/queue-6.6/can-j1939-j1939_session_new-fix-skb-reference-counti.patch b/queue-6.6/can-j1939-j1939_session_new-fix-skb-reference-counti.patch new file mode 100644 index 00000000000..2c681bb31e5 --- /dev/null +++ b/queue-6.6/can-j1939-j1939_session_new-fix-skb-reference-counti.patch @@ -0,0 +1,43 @@ +From 43e9011e938c79bb47dac06337297dc3d49ed542 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 5 Nov 2024 12:48:23 +0300 +Subject: can: j1939: j1939_session_new(): fix skb reference counting + +From: Dmitry Antipov + +[ Upstream commit a8c695005bfe6569acd73d777ca298ddddd66105 ] + +Since j1939_session_skb_queue() does an extra skb_get() for each new +skb, do the same for the initial one in j1939_session_new() to avoid +refcount underflow. + +Reported-by: syzbot+d4e8dc385d9258220c31@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=d4e8dc385d9258220c31 +Fixes: 9d71dd0c7009 ("can: add support of SAE J1939 protocol") +Signed-off-by: Dmitry Antipov +Tested-by: Oleksij Rempel +Acked-by: Oleksij Rempel +Link: https://patch.msgid.link/20241105094823.2403806-1-dmantipov@yandex.ru +[mkl: clean up commit message] +Signed-off-by: Marc Kleine-Budde +Signed-off-by: Sasha Levin +--- + net/can/j1939/transport.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/can/j1939/transport.c b/net/can/j1939/transport.c +index 319f47df33300..95f7a7e65a73f 100644 +--- a/net/can/j1939/transport.c ++++ b/net/can/j1939/transport.c +@@ -1505,7 +1505,7 @@ static struct j1939_session *j1939_session_new(struct j1939_priv *priv, + session->state = J1939_SESSION_NEW; + + skb_queue_head_init(&session->skb_queue); +- skb_queue_tail(&session->skb_queue, skb); ++ skb_queue_tail(&session->skb_queue, skb_get(skb)); + + skcb = j1939_skb_to_cb(skb); + memcpy(&session->skcb, skcb, sizeof(session->skcb)); +-- +2.43.0 + diff --git a/queue-6.6/can-m_can-m_can_handle_lec_err-fix-rx-tx-_errors-sta.patch b/queue-6.6/can-m_can-m_can_handle_lec_err-fix-rx-tx-_errors-sta.patch new file mode 100644 index 00000000000..ef9fe7322e8 --- /dev/null +++ b/queue-6.6/can-m_can-m_can_handle_lec_err-fix-rx-tx-_errors-sta.patch @@ -0,0 +1,103 @@ +From d554849a38eceb5f7452e832d9f70a9762a20a9d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 Nov 2024 23:15:47 +0100 +Subject: can: m_can: m_can_handle_lec_err(): fix {rx,tx}_errors statistics + +From: Dario Binacchi + +[ Upstream commit 988d4222bf9039a875a3d48f2fe35c317831ff68 ] + +The m_can_handle_lec_err() function was incorrectly incrementing only the +receive error counter, even in cases of bit or acknowledgment errors that +occur during transmission. + +Fix the issue by incrementing the appropriate counter based on the +type of error. + +Fixes: e0d1f4816f2a ("can: m_can: add Bosch M_CAN controller support") +Signed-off-by: Dario Binacchi +Link: https://patch.msgid.link/20241122221650.633981-7-dario.binacchi@amarulasolutions.com +Signed-off-by: Marc Kleine-Budde +Signed-off-by: Sasha Levin +--- + drivers/net/can/m_can/m_can.c | 33 +++++++++++++++++++++++---------- + 1 file changed, 23 insertions(+), 10 deletions(-) + +diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c +index ec6e740b03247..2a258986eed02 100644 +--- a/drivers/net/can/m_can/m_can.c ++++ b/drivers/net/can/m_can/m_can.c +@@ -636,47 +636,60 @@ static int m_can_handle_lec_err(struct net_device *dev, + u32 timestamp = 0; + + cdev->can.can_stats.bus_error++; +- stats->rx_errors++; + + /* propagate the error condition to the CAN stack */ + skb = alloc_can_err_skb(dev, &cf); +- if (unlikely(!skb)) +- return 0; + + /* check for 'last error code' which tells us the + * type of the last error to occur on the CAN bus + */ +- cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; ++ if (likely(skb)) ++ cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; + + switch (lec_type) { + case LEC_STUFF_ERROR: + netdev_dbg(dev, "stuff error\n"); +- cf->data[2] |= CAN_ERR_PROT_STUFF; ++ stats->rx_errors++; ++ if (likely(skb)) ++ cf->data[2] |= CAN_ERR_PROT_STUFF; + break; + case LEC_FORM_ERROR: + netdev_dbg(dev, "form error\n"); +- cf->data[2] |= CAN_ERR_PROT_FORM; ++ stats->rx_errors++; ++ if (likely(skb)) ++ cf->data[2] |= CAN_ERR_PROT_FORM; + break; + case LEC_ACK_ERROR: + netdev_dbg(dev, "ack error\n"); +- cf->data[3] = CAN_ERR_PROT_LOC_ACK; ++ stats->tx_errors++; ++ if (likely(skb)) ++ cf->data[3] = CAN_ERR_PROT_LOC_ACK; + break; + case LEC_BIT1_ERROR: + netdev_dbg(dev, "bit1 error\n"); +- cf->data[2] |= CAN_ERR_PROT_BIT1; ++ stats->tx_errors++; ++ if (likely(skb)) ++ cf->data[2] |= CAN_ERR_PROT_BIT1; + break; + case LEC_BIT0_ERROR: + netdev_dbg(dev, "bit0 error\n"); +- cf->data[2] |= CAN_ERR_PROT_BIT0; ++ stats->tx_errors++; ++ if (likely(skb)) ++ cf->data[2] |= CAN_ERR_PROT_BIT0; + break; + case LEC_CRC_ERROR: + netdev_dbg(dev, "CRC error\n"); +- cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; ++ stats->rx_errors++; ++ if (likely(skb)) ++ cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; + break; + default: + break; + } + ++ if (unlikely(!skb)) ++ return 0; ++ + if (cdev->is_peripheral) + timestamp = m_can_get_timestamp(cdev); + +-- +2.43.0 + diff --git a/queue-6.6/can-sja1000-sja1000_err-fix-rx-tx-_errors-statistics.patch b/queue-6.6/can-sja1000-sja1000_err-fix-rx-tx-_errors-statistics.patch new file mode 100644 index 00000000000..c772a61054e --- /dev/null +++ b/queue-6.6/can-sja1000-sja1000_err-fix-rx-tx-_errors-statistics.patch @@ -0,0 +1,147 @@ +From c4170cc9ddec098126641ef47a7d1e08647a7262 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 Nov 2024 23:15:50 +0100 +Subject: can: sja1000: sja1000_err(): fix {rx,tx}_errors statistics + +From: Dario Binacchi + +[ Upstream commit 2c4ef3af4b028a0eaaf378df511d3b425b1df61f ] + +The sja1000_err() function only incremented the receive error counter +and never the transmit error counter, even if the ECC_DIR flag reported +that an error had occurred during transmission. + +Increment the receive/transmit error counter based on the value of the +ECC_DIR flag. + +Fixes: 429da1cc841b ("can: Driver for the SJA1000 CAN controller") +Signed-off-by: Dario Binacchi +Link: https://patch.msgid.link/20241122221650.633981-10-dario.binacchi@amarulasolutions.com +Signed-off-by: Marc Kleine-Budde +Signed-off-by: Sasha Levin +--- + drivers/net/can/sja1000/sja1000.c | 67 ++++++++++++++++++------------- + 1 file changed, 39 insertions(+), 28 deletions(-) + +diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c +index 743c2eb62b877..10e211d917e31 100644 +--- a/drivers/net/can/sja1000/sja1000.c ++++ b/drivers/net/can/sja1000/sja1000.c +@@ -416,8 +416,6 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) + int ret = 0; + + skb = alloc_can_err_skb(dev, &cf); +- if (skb == NULL) +- return -ENOMEM; + + txerr = priv->read_reg(priv, SJA1000_TXERR); + rxerr = priv->read_reg(priv, SJA1000_RXERR); +@@ -425,8 +423,11 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) + if (isrc & IRQ_DOI) { + /* data overrun interrupt */ + netdev_dbg(dev, "data overrun interrupt\n"); +- cf->can_id |= CAN_ERR_CRTL; +- cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; ++ if (skb) { ++ cf->can_id |= CAN_ERR_CRTL; ++ cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; ++ } ++ + stats->rx_over_errors++; + stats->rx_errors++; + sja1000_write_cmdreg(priv, CMD_CDO); /* clear bit */ +@@ -452,7 +453,7 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) + else + state = CAN_STATE_ERROR_ACTIVE; + } +- if (state != CAN_STATE_BUS_OFF) { ++ if (state != CAN_STATE_BUS_OFF && skb) { + cf->can_id |= CAN_ERR_CNT; + cf->data[6] = txerr; + cf->data[7] = rxerr; +@@ -460,33 +461,38 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) + if (isrc & IRQ_BEI) { + /* bus error interrupt */ + priv->can.can_stats.bus_error++; +- stats->rx_errors++; + + ecc = priv->read_reg(priv, SJA1000_ECC); ++ if (skb) { ++ cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; + +- cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; +- +- /* set error type */ +- switch (ecc & ECC_MASK) { +- case ECC_BIT: +- cf->data[2] |= CAN_ERR_PROT_BIT; +- break; +- case ECC_FORM: +- cf->data[2] |= CAN_ERR_PROT_FORM; +- break; +- case ECC_STUFF: +- cf->data[2] |= CAN_ERR_PROT_STUFF; +- break; +- default: +- break; +- } ++ /* set error type */ ++ switch (ecc & ECC_MASK) { ++ case ECC_BIT: ++ cf->data[2] |= CAN_ERR_PROT_BIT; ++ break; ++ case ECC_FORM: ++ cf->data[2] |= CAN_ERR_PROT_FORM; ++ break; ++ case ECC_STUFF: ++ cf->data[2] |= CAN_ERR_PROT_STUFF; ++ break; ++ default: ++ break; ++ } + +- /* set error location */ +- cf->data[3] = ecc & ECC_SEG; ++ /* set error location */ ++ cf->data[3] = ecc & ECC_SEG; ++ } + + /* Error occurred during transmission? */ +- if ((ecc & ECC_DIR) == 0) +- cf->data[2] |= CAN_ERR_PROT_TX; ++ if ((ecc & ECC_DIR) == 0) { ++ stats->tx_errors++; ++ if (skb) ++ cf->data[2] |= CAN_ERR_PROT_TX; ++ } else { ++ stats->rx_errors++; ++ } + } + if (isrc & IRQ_EPI) { + /* error passive interrupt */ +@@ -502,8 +508,10 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) + netdev_dbg(dev, "arbitration lost interrupt\n"); + alc = priv->read_reg(priv, SJA1000_ALC); + priv->can.can_stats.arbitration_lost++; +- cf->can_id |= CAN_ERR_LOSTARB; +- cf->data[0] = alc & 0x1f; ++ if (skb) { ++ cf->can_id |= CAN_ERR_LOSTARB; ++ cf->data[0] = alc & 0x1f; ++ } + } + + if (state != priv->can.state) { +@@ -516,6 +524,9 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) + can_bus_off(dev); + } + ++ if (!skb) ++ return -ENOMEM; ++ + netif_rx(skb); + + return ret; +-- +2.43.0 + diff --git a/queue-6.6/can-sun4i_can-sun4i_can_err-call-can_change_state-ev.patch b/queue-6.6/can-sun4i_can-sun4i_can_err-call-can_change_state-ev.patch new file mode 100644 index 00000000000..c4b1b88b3e7 --- /dev/null +++ b/queue-6.6/can-sun4i_can-sun4i_can_err-call-can_change_state-ev.patch @@ -0,0 +1,47 @@ +From 35de7f5125aa5f273724ee236659d0505689ca32 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 Nov 2024 23:15:43 +0100 +Subject: can: sun4i_can: sun4i_can_err(): call can_change_state() even if cf + is NULL + +From: Dario Binacchi + +[ Upstream commit ee6bf3677ae03569d833795064e17f605c2163c7 ] + +Call the function can_change_state() if the allocation of the skb +fails, as it handles the cf parameter when it is null. + +Additionally, this ensures that the statistics related to state error +counters (i. e. warning, passive, and bus-off) are updated. + +Fixes: 0738eff14d81 ("can: Allwinner A10/A20 CAN Controller support - Kernel module") +Signed-off-by: Dario Binacchi +Link: https://patch.msgid.link/20241122221650.633981-3-dario.binacchi@amarulasolutions.com +Signed-off-by: Marc Kleine-Budde +Signed-off-by: Sasha Levin +--- + drivers/net/can/sun4i_can.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/can/sun4i_can.c b/drivers/net/can/sun4i_can.c +index ab8d017846869..80f7aa2531dc0 100644 +--- a/drivers/net/can/sun4i_can.c ++++ b/drivers/net/can/sun4i_can.c +@@ -629,10 +629,10 @@ static int sun4i_can_err(struct net_device *dev, u8 isrc, u8 status) + tx_state = txerr >= rxerr ? state : 0; + rx_state = txerr <= rxerr ? state : 0; + +- if (likely(skb)) +- can_change_state(dev, cf, tx_state, rx_state); +- else +- priv->can.state = state; ++ /* The skb allocation might fail, but can_change_state() ++ * handles cf == NULL. ++ */ ++ can_change_state(dev, cf, tx_state, rx_state); + if (state == CAN_STATE_BUS_OFF) + can_bus_off(dev); + } +-- +2.43.0 + diff --git a/queue-6.6/can-sun4i_can-sun4i_can_err-fix-rx-tx-_errors-statis.patch b/queue-6.6/can-sun4i_can-sun4i_can_err-fix-rx-tx-_errors-statis.patch new file mode 100644 index 00000000000..12d3ddbdd2d --- /dev/null +++ b/queue-6.6/can-sun4i_can-sun4i_can_err-fix-rx-tx-_errors-statis.patch @@ -0,0 +1,63 @@ +From 5b370f0c836b3fd419bf6595def425ab0355c4d8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 Nov 2024 23:15:51 +0100 +Subject: can: sun4i_can: sun4i_can_err(): fix {rx,tx}_errors statistics + +From: Dario Binacchi + +[ Upstream commit 595a81988a6fe06eb5849e972c8b9cb21c4e0d54 ] + +The sun4i_can_err() function only incremented the receive error counter +and never the transmit error counter, even if the STA_ERR_DIR flag +reported that an error had occurred during transmission. + +Increment the receive/transmit error counter based on the value of the +STA_ERR_DIR flag. + +Fixes: 0738eff14d81 ("can: Allwinner A10/A20 CAN Controller support - Kernel module") +Signed-off-by: Dario Binacchi +Link: https://patch.msgid.link/20241122221650.633981-11-dario.binacchi@amarulasolutions.com +Signed-off-by: Marc Kleine-Budde +Signed-off-by: Sasha Levin +--- + drivers/net/can/sun4i_can.c | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/can/sun4i_can.c b/drivers/net/can/sun4i_can.c +index 80f7aa2531dc0..283fbf59e66d5 100644 +--- a/drivers/net/can/sun4i_can.c ++++ b/drivers/net/can/sun4i_can.c +@@ -579,11 +579,9 @@ static int sun4i_can_err(struct net_device *dev, u8 isrc, u8 status) + /* bus error interrupt */ + netdev_dbg(dev, "bus error interrupt\n"); + priv->can.can_stats.bus_error++; +- stats->rx_errors++; ++ ecc = readl(priv->base + SUN4I_REG_STA_ADDR); + + if (likely(skb)) { +- ecc = readl(priv->base + SUN4I_REG_STA_ADDR); +- + cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; + + switch (ecc & SUN4I_STA_MASK_ERR) { +@@ -601,9 +599,15 @@ static int sun4i_can_err(struct net_device *dev, u8 isrc, u8 status) + >> 16; + break; + } +- /* error occurred during transmission? */ +- if ((ecc & SUN4I_STA_ERR_DIR) == 0) ++ } ++ ++ /* error occurred during transmission? */ ++ if ((ecc & SUN4I_STA_ERR_DIR) == 0) { ++ if (likely(skb)) + cf->data[2] |= CAN_ERR_PROT_TX; ++ stats->tx_errors++; ++ } else { ++ stats->rx_errors++; + } + } + if (isrc & SUN4I_INT_ERR_PASSIVE) { +-- +2.43.0 + diff --git a/queue-6.6/dccp-fix-memory-leak-in-dccp_feat_change_recv.patch b/queue-6.6/dccp-fix-memory-leak-in-dccp_feat_change_recv.patch new file mode 100644 index 00000000000..b06d5ad6926 --- /dev/null +++ b/queue-6.6/dccp-fix-memory-leak-in-dccp_feat_change_recv.patch @@ -0,0 +1,78 @@ +From e7eea6fe3e6c2be7662d028c17c68348915eda5a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 Nov 2024 17:39:02 +0300 +Subject: dccp: Fix memory leak in dccp_feat_change_recv + +From: Ivan Solodovnikov + +[ Upstream commit 22be4727a8f898442066bcac34f8a1ad0bc72e14 ] + +If dccp_feat_push_confirm() fails after new value for SP feature was accepted +without reconciliation ('entry == NULL' branch), memory allocated for that value +with dccp_feat_clone_sp_val() is never freed. + +Here is the kmemleak stack for this: + +unreferenced object 0xffff88801d4ab488 (size 8): + comm "syz-executor310", pid 1127, jiffies 4295085598 (age 41.666s) + hex dump (first 8 bytes): + 01 b4 4a 1d 80 88 ff ff ..J..... + backtrace: + [<00000000db7cabfe>] kmemdup+0x23/0x50 mm/util.c:128 + [<0000000019b38405>] kmemdup include/linux/string.h:465 [inline] + [<0000000019b38405>] dccp_feat_clone_sp_val net/dccp/feat.c:371 [inline] + [<0000000019b38405>] dccp_feat_clone_sp_val net/dccp/feat.c:367 [inline] + [<0000000019b38405>] dccp_feat_change_recv net/dccp/feat.c:1145 [inline] + [<0000000019b38405>] dccp_feat_parse_options+0x1196/0x2180 net/dccp/feat.c:1416 + [<00000000b1f6d94a>] dccp_parse_options+0xa2a/0x1260 net/dccp/options.c:125 + [<0000000030d7b621>] dccp_rcv_state_process+0x197/0x13d0 net/dccp/input.c:650 + [<000000001f74c72e>] dccp_v4_do_rcv+0xf9/0x1a0 net/dccp/ipv4.c:688 + [<00000000a6c24128>] sk_backlog_rcv include/net/sock.h:1041 [inline] + [<00000000a6c24128>] __release_sock+0x139/0x3b0 net/core/sock.c:2570 + [<00000000cf1f3a53>] release_sock+0x54/0x1b0 net/core/sock.c:3111 + [<000000008422fa23>] inet_wait_for_connect net/ipv4/af_inet.c:603 [inline] + [<000000008422fa23>] __inet_stream_connect+0x5d0/0xf70 net/ipv4/af_inet.c:696 + [<0000000015b6f64d>] inet_stream_connect+0x53/0xa0 net/ipv4/af_inet.c:735 + [<0000000010122488>] __sys_connect_file+0x15c/0x1a0 net/socket.c:1865 + [<00000000b4b70023>] __sys_connect+0x165/0x1a0 net/socket.c:1882 + [<00000000f4cb3815>] __do_sys_connect net/socket.c:1892 [inline] + [<00000000f4cb3815>] __se_sys_connect net/socket.c:1889 [inline] + [<00000000f4cb3815>] __x64_sys_connect+0x6e/0xb0 net/socket.c:1889 + [<00000000e7b1e839>] do_syscall_64+0x33/0x40 arch/x86/entry/common.c:46 + [<0000000055e91434>] entry_SYSCALL_64_after_hwframe+0x67/0xd1 + +Clean up the allocated memory in case of dccp_feat_push_confirm() failure +and bail out with an error reset code. + +Found by Linux Verification Center (linuxtesting.org) with Syzkaller. + +Fixes: e77b8363b2ea ("dccp: Process incoming Change feature-negotiation options") +Signed-off-by: Ivan Solodovnikov +Link: https://patch.msgid.link/20241126143902.190853-1-solodovnikov.ia@phystech.edu +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/dccp/feat.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/net/dccp/feat.c b/net/dccp/feat.c +index 54086bb05c42c..f7554dcdaaba9 100644 +--- a/net/dccp/feat.c ++++ b/net/dccp/feat.c +@@ -1166,8 +1166,12 @@ static u8 dccp_feat_change_recv(struct list_head *fn, u8 is_mandatory, u8 opt, + goto not_valid_or_not_known; + } + +- return dccp_feat_push_confirm(fn, feat, local, &fval); ++ if (dccp_feat_push_confirm(fn, feat, local, &fval)) { ++ kfree(fval.sp.vec); ++ return DCCP_RESET_CODE_TOO_BUSY; ++ } + ++ return 0; + } else if (entry->state == FEAT_UNSTABLE) { /* 6.6.2 */ + return 0; + } +-- +2.43.0 + diff --git a/queue-6.6/driver-core-add-fwlink_flag_ignore-to-completely-ign.patch b/queue-6.6/driver-core-add-fwlink_flag_ignore-to-completely-ign.patch new file mode 100644 index 00000000000..76af4dd9f80 --- /dev/null +++ b/queue-6.6/driver-core-add-fwlink_flag_ignore-to-completely-ign.patch @@ -0,0 +1,86 @@ +From 04376b4e41eddbdc05a4b2b617aae9e80ec3448b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 4 Mar 2024 21:04:55 -0800 +Subject: driver core: Add FWLINK_FLAG_IGNORE to completely ignore a fwnode + link + +From: Saravana Kannan + +[ Upstream commit b7e1241d8f77ed64404a5e4450f43a319310fc91 ] + +A fwnode link between specific supplier-consumer fwnodes can be added +multiple times for multiple reasons. If that dependency doesn't exist, +deleting the fwnode link once doesn't guarantee that it won't get created +again. + +So, add FWLINK_FLAG_IGNORE flag to mark a fwnode link as one that needs to +be completely ignored. Since a fwnode link's flags is an OR of all the +flags passed to all the fwnode_link_add() calls to create that specific +fwnode link, the FWLINK_FLAG_IGNORE flag is preserved and can be used to +mark a fwnode link as on that need to be completely ignored until it is +deleted. + +Signed-off-by: Saravana Kannan +Acked-by: "Rafael J. Wysocki" +Reviewed-by: Rob Herring +Link: https://lore.kernel.org/r/20240305050458.1400667-3-saravanak@google.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: bac3b10b78e5 ("driver core: fw_devlink: Stop trying to optimize cycle detection logic") +Signed-off-by: Sasha Levin +--- + drivers/base/core.c | 9 ++++++++- + include/linux/fwnode.h | 2 ++ + 2 files changed, 10 insertions(+), 1 deletion(-) + +diff --git a/drivers/base/core.c b/drivers/base/core.c +index 499904f1ba6b3..3aaf234dbb088 100644 +--- a/drivers/base/core.c ++++ b/drivers/base/core.c +@@ -1025,7 +1025,8 @@ static struct fwnode_handle *fwnode_links_check_suppliers( + return NULL; + + list_for_each_entry(link, &fwnode->suppliers, c_hook) +- if (!(link->flags & FWLINK_FLAG_CYCLE)) ++ if (!(link->flags & ++ (FWLINK_FLAG_CYCLE | FWLINK_FLAG_IGNORE))) + return link->supplier; + + return NULL; +@@ -1976,6 +1977,9 @@ static bool __fw_devlink_relax_cycles(struct device *con, + } + + list_for_each_entry(link, &sup_handle->suppliers, c_hook) { ++ if (link->flags & FWLINK_FLAG_IGNORE) ++ continue; ++ + if (__fw_devlink_relax_cycles(con, link->supplier)) { + __fwnode_link_cycle(link); + ret = true; +@@ -2054,6 +2058,9 @@ static int fw_devlink_create_devlink(struct device *con, + int ret = 0; + u32 flags; + ++ if (link->flags & FWLINK_FLAG_IGNORE) ++ return 0; ++ + if (con->fwnode == link->consumer) + flags = fw_devlink_get_flags(link->flags); + else +diff --git a/include/linux/fwnode.h b/include/linux/fwnode.h +index 5700451b300fb..525cc031596b6 100644 +--- a/include/linux/fwnode.h ++++ b/include/linux/fwnode.h +@@ -51,8 +51,10 @@ struct fwnode_handle { + * fwnode link flags + * + * CYCLE: The fwnode link is part of a cycle. Don't defer probe. ++ * IGNORE: Completely ignore this link, even during cycle detection. + */ + #define FWLINK_FLAG_CYCLE BIT(0) ++#define FWLINK_FLAG_IGNORE BIT(1) + + struct fwnode_link { + struct fwnode_handle *supplier; +-- +2.43.0 + diff --git a/queue-6.6/driver-core-fw_devlink-improve-logs-for-cycle-detect.patch b/queue-6.6/driver-core-fw_devlink-improve-logs-for-cycle-detect.patch new file mode 100644 index 00000000000..baac5b9df0b --- /dev/null +++ b/queue-6.6/driver-core-fw_devlink-improve-logs-for-cycle-detect.patch @@ -0,0 +1,79 @@ +From 6a716baa913705f983ed10a53b944a57994d0378 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 2 Feb 2024 01:56:35 -0800 +Subject: driver core: fw_devlink: Improve logs for cycle detection + +From: Saravana Kannan + +[ Upstream commit 6e7ad1aebb4fc9fed0217dd50ef6e58a53f17d81 ] + +The links in a cycle are not all logged in a consistent manner or not +logged at all. Make them consistent by adding a "cycle:" string and log all +the link in the cycles (even the child ==> parent dependency) so that it's +easier to debug cycle detection code. Also, mark the start and end of a +cycle so it's easy to tell when multiple cycles are logged back to back. + +Signed-off-by: Saravana Kannan +Tested-by: Xu Yang +Link: https://lore.kernel.org/r/20240202095636.868578-4-saravanak@google.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: bac3b10b78e5 ("driver core: fw_devlink: Stop trying to optimize cycle detection logic") +Signed-off-by: Sasha Levin +--- + drivers/base/core.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/drivers/base/core.c b/drivers/base/core.c +index c9fb3243e353e..499904f1ba6b3 100644 +--- a/drivers/base/core.c ++++ b/drivers/base/core.c +@@ -125,7 +125,7 @@ static void __fwnode_link_del(struct fwnode_link *link) + */ + static void __fwnode_link_cycle(struct fwnode_link *link) + { +- pr_debug("%pfwf: Relaxing link with %pfwf\n", ++ pr_debug("%pfwf: cycle: depends on %pfwf\n", + link->consumer, link->supplier); + link->flags |= FWLINK_FLAG_CYCLE; + } +@@ -1959,6 +1959,7 @@ static bool __fw_devlink_relax_cycles(struct device *con, + + /* Termination condition. */ + if (sup_dev == con) { ++ pr_debug("----- cycle: start -----\n"); + ret = true; + goto out; + } +@@ -1990,8 +1991,11 @@ static bool __fw_devlink_relax_cycles(struct device *con, + else + par_dev = fwnode_get_next_parent_dev(sup_handle); + +- if (par_dev && __fw_devlink_relax_cycles(con, par_dev->fwnode)) ++ if (par_dev && __fw_devlink_relax_cycles(con, par_dev->fwnode)) { ++ pr_debug("%pfwf: cycle: child of %pfwf\n", sup_handle, ++ par_dev->fwnode); + ret = true; ++ } + + if (!sup_dev) + goto out; +@@ -2007,6 +2011,8 @@ static bool __fw_devlink_relax_cycles(struct device *con, + + if (__fw_devlink_relax_cycles(con, + dev_link->supplier->fwnode)) { ++ pr_debug("%pfwf: cycle: depends on %pfwf\n", sup_handle, ++ dev_link->supplier->fwnode); + fw_devlink_relax_link(dev_link); + dev_link->flags |= DL_FLAG_CYCLE; + ret = true; +@@ -2086,6 +2092,7 @@ static int fw_devlink_create_devlink(struct device *con, + if (__fw_devlink_relax_cycles(con, sup_handle)) { + __fwnode_link_cycle(link); + flags = fw_devlink_get_flags(link->flags); ++ pr_debug("----- cycle: end -----\n"); + dev_info(con, "Fixed dependency cycle(s) with %pfwf\n", + sup_handle); + } +-- +2.43.0 + diff --git a/queue-6.6/driver-core-fw_devlink-stop-trying-to-optimize-cycle.patch b/queue-6.6/driver-core-fw_devlink-stop-trying-to-optimize-cycle.patch new file mode 100644 index 00000000000..8d69fc5c59a --- /dev/null +++ b/queue-6.6/driver-core-fw_devlink-stop-trying-to-optimize-cycle.patch @@ -0,0 +1,169 @@ +From 387f86ff58a2578db852ab96354437d3b960c322 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 30 Oct 2024 10:10:07 -0700 +Subject: driver core: fw_devlink: Stop trying to optimize cycle detection + logic + +From: Saravana Kannan + +[ Upstream commit bac3b10b78e54b7da3cede397258f75a2180609b ] + +In attempting to optimize fw_devlink runtime, I introduced numerous cycle +detection bugs by foregoing cycle detection logic under specific +conditions. Each fix has further narrowed the conditions for optimization. + +It's time to give up on these optimization attempts and just run the cycle +detection logic every time fw_devlink tries to create a device link. + +The specific bug report that triggered this fix involved a supplier fwnode +that never gets a device created for it. Instead, the supplier fwnode is +represented by the device that corresponds to an ancestor fwnode. + +In this case, fw_devlink didn't do any cycle detection because the cycle +detection logic is only run when a device link is created between the +devices that correspond to the actual consumer and supplier fwnodes. + +With this change, fw_devlink will run cycle detection logic even when +creating SYNC_STATE_ONLY proxy device links from a device that is an +ancestor of a consumer fwnode. + +Reported-by: Tomi Valkeinen +Closes: https://lore.kernel.org/all/1a1ab663-d068-40fb-8c94-f0715403d276@ideasonboard.com/ +Fixes: 6442d79d880c ("driver core: fw_devlink: Improve detection of overlapping cycles") +Cc: stable +Tested-by: Tomi Valkeinen +Signed-off-by: Saravana Kannan +Link: https://lore.kernel.org/r/20241030171009.1853340-1-saravanak@google.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/base/core.c | 55 ++++++++++++++++++++------------------------- + 1 file changed, 24 insertions(+), 31 deletions(-) + +diff --git a/drivers/base/core.c b/drivers/base/core.c +index 3aaf234dbb088..18a73e4921026 100644 +--- a/drivers/base/core.c ++++ b/drivers/base/core.c +@@ -1936,10 +1936,10 @@ static bool fwnode_ancestor_init_without_drv(struct fwnode_handle *fwnode) + * + * Return true if one or more cycles were found. Otherwise, return false. + */ +-static bool __fw_devlink_relax_cycles(struct device *con, ++static bool __fw_devlink_relax_cycles(struct fwnode_handle *con_handle, + struct fwnode_handle *sup_handle) + { +- struct device *sup_dev = NULL, *par_dev = NULL; ++ struct device *sup_dev = NULL, *par_dev = NULL, *con_dev = NULL; + struct fwnode_link *link; + struct device_link *dev_link; + bool ret = false; +@@ -1956,22 +1956,22 @@ static bool __fw_devlink_relax_cycles(struct device *con, + + sup_handle->flags |= FWNODE_FLAG_VISITED; + +- sup_dev = get_dev_from_fwnode(sup_handle); +- + /* Termination condition. */ +- if (sup_dev == con) { ++ if (sup_handle == con_handle) { + pr_debug("----- cycle: start -----\n"); + ret = true; + goto out; + } + ++ sup_dev = get_dev_from_fwnode(sup_handle); ++ con_dev = get_dev_from_fwnode(con_handle); + /* + * If sup_dev is bound to a driver and @con hasn't started binding to a + * driver, sup_dev can't be a consumer of @con. So, no need to check + * further. + */ + if (sup_dev && sup_dev->links.status == DL_DEV_DRIVER_BOUND && +- con->links.status == DL_DEV_NO_DRIVER) { ++ con_dev && con_dev->links.status == DL_DEV_NO_DRIVER) { + ret = false; + goto out; + } +@@ -1980,7 +1980,7 @@ static bool __fw_devlink_relax_cycles(struct device *con, + if (link->flags & FWLINK_FLAG_IGNORE) + continue; + +- if (__fw_devlink_relax_cycles(con, link->supplier)) { ++ if (__fw_devlink_relax_cycles(con_handle, link->supplier)) { + __fwnode_link_cycle(link); + ret = true; + } +@@ -1995,7 +1995,7 @@ static bool __fw_devlink_relax_cycles(struct device *con, + else + par_dev = fwnode_get_next_parent_dev(sup_handle); + +- if (par_dev && __fw_devlink_relax_cycles(con, par_dev->fwnode)) { ++ if (par_dev && __fw_devlink_relax_cycles(con_handle, par_dev->fwnode)) { + pr_debug("%pfwf: cycle: child of %pfwf\n", sup_handle, + par_dev->fwnode); + ret = true; +@@ -2013,7 +2013,7 @@ static bool __fw_devlink_relax_cycles(struct device *con, + !(dev_link->flags & DL_FLAG_CYCLE)) + continue; + +- if (__fw_devlink_relax_cycles(con, ++ if (__fw_devlink_relax_cycles(con_handle, + dev_link->supplier->fwnode)) { + pr_debug("%pfwf: cycle: depends on %pfwf\n", sup_handle, + dev_link->supplier->fwnode); +@@ -2061,11 +2061,6 @@ static int fw_devlink_create_devlink(struct device *con, + if (link->flags & FWLINK_FLAG_IGNORE) + return 0; + +- if (con->fwnode == link->consumer) +- flags = fw_devlink_get_flags(link->flags); +- else +- flags = FW_DEVLINK_FLAGS_PERMISSIVE; +- + /* + * In some cases, a device P might also be a supplier to its child node + * C. However, this would defer the probe of C until the probe of P +@@ -2086,25 +2081,23 @@ static int fw_devlink_create_devlink(struct device *con, + return -EINVAL; + + /* +- * SYNC_STATE_ONLY device links don't block probing and supports cycles. +- * So, one might expect that cycle detection isn't necessary for them. +- * However, if the device link was marked as SYNC_STATE_ONLY because +- * it's part of a cycle, then we still need to do cycle detection. This +- * is because the consumer and supplier might be part of multiple cycles +- * and we need to detect all those cycles. ++ * Don't try to optimize by not calling the cycle detection logic under ++ * certain conditions. There's always some corner case that won't get ++ * detected. + */ +- if (!device_link_flag_is_sync_state_only(flags) || +- flags & DL_FLAG_CYCLE) { +- device_links_write_lock(); +- if (__fw_devlink_relax_cycles(con, sup_handle)) { +- __fwnode_link_cycle(link); +- flags = fw_devlink_get_flags(link->flags); +- pr_debug("----- cycle: end -----\n"); +- dev_info(con, "Fixed dependency cycle(s) with %pfwf\n", +- sup_handle); +- } +- device_links_write_unlock(); ++ device_links_write_lock(); ++ if (__fw_devlink_relax_cycles(link->consumer, sup_handle)) { ++ __fwnode_link_cycle(link); ++ pr_debug("----- cycle: end -----\n"); ++ pr_info("%pfwf: Fixed dependency cycle(s) with %pfwf\n", ++ link->consumer, sup_handle); + } ++ device_links_write_unlock(); ++ ++ if (con->fwnode == link->consumer) ++ flags = fw_devlink_get_flags(link->flags); ++ else ++ flags = FW_DEVLINK_FLAGS_PERMISSIVE; + + if (sup_handle->flags & FWNODE_FLAG_NOT_DEVICE) + sup_dev = fwnode_get_next_parent_dev(sup_handle); +-- +2.43.0 + diff --git a/queue-6.6/drm-bridge-it6505-fix-inverted-reset-polarity.patch b/queue-6.6/drm-bridge-it6505-fix-inverted-reset-polarity.patch new file mode 100644 index 00000000000..e5b9135ad14 --- /dev/null +++ b/queue-6.6/drm-bridge-it6505-fix-inverted-reset-polarity.patch @@ -0,0 +1,74 @@ +From 6d2e02bd1251f26dc78b83d6ffe7c38933d8c763 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 29 Oct 2024 17:54:10 +0800 +Subject: drm/bridge: it6505: Fix inverted reset polarity + +From: Chen-Yu Tsai + +[ Upstream commit c5f3f21728b069412e8072b8b1d0a3d9d3ab0265 ] + +The IT6505 bridge chip has a active low reset line. Since it is a +"reset" and not an "enable" line, the GPIO should be asserted to +put it in reset and deasserted to bring it out of reset during +the power on sequence. + +The polarity was inverted when the driver was first introduced, likely +because the device family that was targeted had an inverting level +shifter on the reset line. + +The MT8186 Corsola devices already have the IT6505 in their device tree, +but the whole display pipeline is actually disabled and won't be enabled +until some remaining issues are sorted out. The other known user is +the MT8183 Kukui / Jacuzzi family; their device trees currently do not +have the IT6505 included. + +Fix the polarity in the driver while there are no actual users. + +Fixes: b5c84a9edcd4 ("drm/bridge: add it6505 driver") +Cc: stable@vger.kernel.org +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Neil Armstrong +Link: https://patchwork.freedesktop.org/patch/msgid/20241029095411.657616-1-wenst@chromium.org +Signed-off-by: Chen-Yu Tsai +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/bridge/ite-it6505.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/ite-it6505.c b/drivers/gpu/drm/bridge/ite-it6505.c +index fda2c565fdb31..2a7c620626a03 100644 +--- a/drivers/gpu/drm/bridge/ite-it6505.c ++++ b/drivers/gpu/drm/bridge/ite-it6505.c +@@ -2611,9 +2611,9 @@ static int it6505_poweron(struct it6505 *it6505) + /* time interval between OVDD and SYSRSTN at least be 10ms */ + if (pdata->gpiod_reset) { + usleep_range(10000, 20000); +- gpiod_set_value_cansleep(pdata->gpiod_reset, 0); +- usleep_range(1000, 2000); + gpiod_set_value_cansleep(pdata->gpiod_reset, 1); ++ usleep_range(1000, 2000); ++ gpiod_set_value_cansleep(pdata->gpiod_reset, 0); + usleep_range(25000, 35000); + } + +@@ -2640,7 +2640,7 @@ static int it6505_poweroff(struct it6505 *it6505) + } + + if (pdata->gpiod_reset) +- gpiod_set_value_cansleep(pdata->gpiod_reset, 0); ++ gpiod_set_value_cansleep(pdata->gpiod_reset, 1); + + if (pdata->pwr18) { + err = regulator_disable(pdata->pwr18); +@@ -3132,7 +3132,7 @@ static int it6505_init_pdata(struct it6505 *it6505) + return PTR_ERR(pdata->ovdd); + } + +- pdata->gpiod_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); ++ pdata->gpiod_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(pdata->gpiod_reset)) { + dev_err(dev, "gpiod_reset gpio not found"); + return PTR_ERR(pdata->gpiod_reset); +-- +2.43.0 + diff --git a/queue-6.6/drm-bridge-it6505-update-usleep_range-for-rc-circuit.patch b/queue-6.6/drm-bridge-it6505-update-usleep_range-for-rc-circuit.patch new file mode 100644 index 00000000000..adcbb429a96 --- /dev/null +++ b/queue-6.6/drm-bridge-it6505-update-usleep_range-for-rc-circuit.patch @@ -0,0 +1,39 @@ +From 0937493f1deb1ffe52c20244c9736a0015fe8fc3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Jun 2024 10:44:05 +0800 +Subject: drm/bridge: it6505: update usleep_range for RC circuit charge time + +From: Kuro Chung + +[ Upstream commit 8814444e62b8a8b573fba2cbbb327d5817b74eb0 ] + +The spec of timing between IVDD/OVDD and SYSRTEN is 10ms, but SYSRSTN RC +circuit need at least 25ms for rising time, update for match spec + +Signed-off-by: Kuro Chung +Signed-off-by: Hermes Wu +Reviewed-by: Robert Foss +Signed-off-by: Robert Foss +Link: https://patchwork.freedesktop.org/patch/msgid/20240604024405.1122488-1-kuro.chung@ite.com.tw +Stable-dep-of: c5f3f21728b0 ("drm/bridge: it6505: Fix inverted reset polarity") +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/bridge/ite-it6505.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/bridge/ite-it6505.c b/drivers/gpu/drm/bridge/ite-it6505.c +index 93eb8fba23d42..fda2c565fdb31 100644 +--- a/drivers/gpu/drm/bridge/ite-it6505.c ++++ b/drivers/gpu/drm/bridge/ite-it6505.c +@@ -2614,7 +2614,7 @@ static int it6505_poweron(struct it6505 *it6505) + gpiod_set_value_cansleep(pdata->gpiod_reset, 0); + usleep_range(1000, 2000); + gpiod_set_value_cansleep(pdata->gpiod_reset, 1); +- usleep_range(10000, 20000); ++ usleep_range(25000, 35000); + } + + it6505->powered = true; +-- +2.43.0 + diff --git a/queue-6.6/ethtool-fix-wrong-mod-state-in-case-of-verbose-and-n.patch b/queue-6.6/ethtool-fix-wrong-mod-state-in-case-of-verbose-and-n.patch new file mode 100644 index 00000000000..50d0fa2bd1c --- /dev/null +++ b/queue-6.6/ethtool-fix-wrong-mod-state-in-case-of-verbose-and-n.patch @@ -0,0 +1,127 @@ +From b846b02e7a5210a64c3d7c2f7d664c6534d9fc82 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Dec 2024 16:33:57 +0100 +Subject: ethtool: Fix wrong mod state in case of verbose and no_mask bitset + +From: Kory Maincent + +[ Upstream commit 910c4788d6155b2202ec88273376cd7ecdc24f0a ] + +A bitset without mask in a _SET request means we want exactly the bits in +the bitset to be set. This works correctly for compact format but when +verbose format is parsed, ethnl_update_bitset32_verbose() only sets the +bits present in the request bitset but does not clear the rest. The commit +6699170376ab ("ethtool: fix application of verbose no_mask bitset") fixes +this issue by clearing the whole target bitmap before we start iterating. +The solution proposed brought an issue with the behavior of the mod +variable. As the bitset is always cleared the old value will always +differ to the new value. + +Fix it by adding a new function to compare bitmaps and a temporary variable +which save the state of the old bitmap. + +Fixes: 6699170376ab ("ethtool: fix application of verbose no_mask bitset") +Signed-off-by: Kory Maincent +Link: https://patch.msgid.link/20241202153358.1142095-1-kory.maincent@bootlin.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ethtool/bitset.c | 48 ++++++++++++++++++++++++++++++++++++++++---- + 1 file changed, 44 insertions(+), 4 deletions(-) + +diff --git a/net/ethtool/bitset.c b/net/ethtool/bitset.c +index 0515d6604b3b9..f0883357d12e5 100644 +--- a/net/ethtool/bitset.c ++++ b/net/ethtool/bitset.c +@@ -425,12 +425,32 @@ static int ethnl_parse_bit(unsigned int *index, bool *val, unsigned int nbits, + return 0; + } + ++/** ++ * ethnl_bitmap32_equal() - Compare two bitmaps ++ * @map1: first bitmap ++ * @map2: second bitmap ++ * @nbits: bit size to compare ++ * ++ * Return: true if first @nbits are equal, false if not ++ */ ++static bool ethnl_bitmap32_equal(const u32 *map1, const u32 *map2, ++ unsigned int nbits) ++{ ++ if (memcmp(map1, map2, nbits / 32 * sizeof(u32))) ++ return false; ++ if (nbits % 32 == 0) ++ return true; ++ return !((map1[nbits / 32] ^ map2[nbits / 32]) & ++ ethnl_lower_bits(nbits % 32)); ++} ++ + static int + ethnl_update_bitset32_verbose(u32 *bitmap, unsigned int nbits, + const struct nlattr *attr, struct nlattr **tb, + ethnl_string_array_t names, + struct netlink_ext_ack *extack, bool *mod) + { ++ u32 *saved_bitmap = NULL; + struct nlattr *bit_attr; + bool no_mask; + int rem; +@@ -448,8 +468,20 @@ ethnl_update_bitset32_verbose(u32 *bitmap, unsigned int nbits, + } + + no_mask = tb[ETHTOOL_A_BITSET_NOMASK]; +- if (no_mask) +- ethnl_bitmap32_clear(bitmap, 0, nbits, mod); ++ if (no_mask) { ++ unsigned int nwords = DIV_ROUND_UP(nbits, 32); ++ unsigned int nbytes = nwords * sizeof(u32); ++ bool dummy; ++ ++ /* The bitmap size is only the size of the map part without ++ * its mask part. ++ */ ++ saved_bitmap = kcalloc(nwords, sizeof(u32), GFP_KERNEL); ++ if (!saved_bitmap) ++ return -ENOMEM; ++ memcpy(saved_bitmap, bitmap, nbytes); ++ ethnl_bitmap32_clear(bitmap, 0, nbits, &dummy); ++ } + + nla_for_each_nested(bit_attr, tb[ETHTOOL_A_BITSET_BITS], rem) { + bool old_val, new_val; +@@ -458,22 +490,30 @@ ethnl_update_bitset32_verbose(u32 *bitmap, unsigned int nbits, + if (nla_type(bit_attr) != ETHTOOL_A_BITSET_BITS_BIT) { + NL_SET_ERR_MSG_ATTR(extack, bit_attr, + "only ETHTOOL_A_BITSET_BITS_BIT allowed in ETHTOOL_A_BITSET_BITS"); ++ kfree(saved_bitmap); + return -EINVAL; + } + ret = ethnl_parse_bit(&idx, &new_val, nbits, bit_attr, no_mask, + names, extack); +- if (ret < 0) ++ if (ret < 0) { ++ kfree(saved_bitmap); + return ret; ++ } + old_val = bitmap[idx / 32] & ((u32)1 << (idx % 32)); + if (new_val != old_val) { + if (new_val) + bitmap[idx / 32] |= ((u32)1 << (idx % 32)); + else + bitmap[idx / 32] &= ~((u32)1 << (idx % 32)); +- *mod = true; ++ if (!no_mask) ++ *mod = true; + } + } + ++ if (no_mask && !ethnl_bitmap32_equal(saved_bitmap, bitmap, nbits)) ++ *mod = true; ++ ++ kfree(saved_bitmap); + return 0; + } + +-- +2.43.0 + diff --git a/queue-6.6/f2fs-fix-to-drop-all-discards-after-creating-snapsho.patch b/queue-6.6/f2fs-fix-to-drop-all-discards-after-creating-snapsho.patch new file mode 100644 index 00000000000..70d1add4e40 --- /dev/null +++ b/queue-6.6/f2fs-fix-to-drop-all-discards-after-creating-snapsho.patch @@ -0,0 +1,103 @@ +From 4b9b904a869202f57de21ba665362b51809569d2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 Nov 2024 22:17:16 +0800 +Subject: f2fs: fix to drop all discards after creating snapshot on lvm device + +From: Chao Yu + +[ Upstream commit bc8aeb04fd80cb8cfae3058445c84410fd0beb5e ] + +Piergiorgio reported a bug in bugzilla as below: + +------------[ cut here ]------------ +WARNING: CPU: 2 PID: 969 at fs/f2fs/segment.c:1330 +RIP: 0010:__submit_discard_cmd+0x27d/0x400 [f2fs] +Call Trace: + __issue_discard_cmd+0x1ca/0x350 [f2fs] + issue_discard_thread+0x191/0x480 [f2fs] + kthread+0xcf/0x100 + ret_from_fork+0x31/0x50 + ret_from_fork_asm+0x1a/0x30 + +w/ below testcase, it can reproduce this bug quickly: +- pvcreate /dev/vdb +- vgcreate myvg1 /dev/vdb +- lvcreate -L 1024m -n mylv1 myvg1 +- mount /dev/myvg1/mylv1 /mnt/f2fs +- dd if=/dev/zero of=/mnt/f2fs/file bs=1M count=20 +- sync +- rm /mnt/f2fs/file +- sync +- lvcreate -L 1024m -s -n mylv1-snapshot /dev/myvg1/mylv1 +- umount /mnt/f2fs + +The root cause is: it will update discard_max_bytes of mounted lvm +device to zero after creating snapshot on this lvm device, then, +__submit_discard_cmd() will pass parameter @nr_sects w/ zero value +to __blkdev_issue_discard(), it returns a NULL bio pointer, result +in panic. + +This patch changes as below for fixing: +1. Let's drop all remained discards in f2fs_unfreeze() if snapshot +of lvm device is created. +2. Checking discard_max_bytes before submitting discard during +__submit_discard_cmd(). + +Cc: stable@vger.kernel.org +Fixes: 35ec7d574884 ("f2fs: split discard command in prior to block layer") +Reported-by: Piergiorgio Sartor +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=219484 +Signed-off-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Sasha Levin +--- + fs/f2fs/segment.c | 9 +++++++++ + fs/f2fs/super.c | 12 ++++++++++++ + 2 files changed, 21 insertions(+) + +diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c +index 670104628ddbe..156d92b945258 100644 +--- a/fs/f2fs/segment.c ++++ b/fs/f2fs/segment.c +@@ -1282,6 +1282,15 @@ static int __submit_discard_cmd(struct f2fs_sb_info *sbi, + } + #endif + ++ /* ++ * stop issuing discard for any of below cases: ++ * 1. device is conventional zone, but it doesn't support discard. ++ * 2. device is regulare device, after snapshot it doesn't support ++ * discard. ++ */ ++ if (!bdev_max_discard_sectors(bdev)) ++ return -EOPNOTSUPP; ++ + trace_f2fs_issue_discard(bdev, dc->di.start, dc->di.len); + + lstart = dc->di.lstart; +diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c +index f05d0e43db9e2..b72fa103b9632 100644 +--- a/fs/f2fs/super.c ++++ b/fs/f2fs/super.c +@@ -1735,6 +1735,18 @@ static int f2fs_freeze(struct super_block *sb) + + static int f2fs_unfreeze(struct super_block *sb) + { ++ struct f2fs_sb_info *sbi = F2FS_SB(sb); ++ ++ /* ++ * It will update discard_max_bytes of mounted lvm device to zero ++ * after creating snapshot on this lvm device, let's drop all ++ * remained discards. ++ * We don't need to disable real-time discard because discard_max_bytes ++ * will recover after removal of snapshot. ++ */ ++ if (test_opt(sbi, DISCARD) && !f2fs_hw_support_discard(sbi)) ++ f2fs_issue_discard_timeout(sbi); ++ + clear_sbi_flag(F2FS_SB(sb), SBI_IS_FREEZING); + return 0; + } +-- +2.43.0 + diff --git a/queue-6.6/geneve-do-not-assume-mac-header-is-set-in-geneve_xmi.patch b/queue-6.6/geneve-do-not-assume-mac-header-is-set-in-geneve_xmi.patch new file mode 100644 index 00000000000..9ebafc9b0c6 --- /dev/null +++ b/queue-6.6/geneve-do-not-assume-mac-header-is-set-in-geneve_xmi.patch @@ -0,0 +1,85 @@ +From 1f8d7560d3a7f72d5a0075aea45c9302ae46bf06 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Dec 2024 18:21:21 +0000 +Subject: geneve: do not assume mac header is set in geneve_xmit_skb() + +From: Eric Dumazet + +[ Upstream commit 8588c99c7d47448fcae39e3227d6e2bb97aad86d ] + +We should not assume mac header is set in output path. + +Use skb_eth_hdr() instead of eth_hdr() to fix the issue. + +sysbot reported the following : + + WARNING: CPU: 0 PID: 11635 at include/linux/skbuff.h:3052 skb_mac_header include/linux/skbuff.h:3052 [inline] + WARNING: CPU: 0 PID: 11635 at include/linux/skbuff.h:3052 eth_hdr include/linux/if_ether.h:24 [inline] + WARNING: CPU: 0 PID: 11635 at include/linux/skbuff.h:3052 geneve_xmit_skb drivers/net/geneve.c:898 [inline] + WARNING: CPU: 0 PID: 11635 at include/linux/skbuff.h:3052 geneve_xmit+0x4c38/0x5730 drivers/net/geneve.c:1039 +Modules linked in: +CPU: 0 UID: 0 PID: 11635 Comm: syz.4.1423 Not tainted 6.12.0-syzkaller-10296-gaaf20f870da0 #0 +Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 09/13/2024 + RIP: 0010:skb_mac_header include/linux/skbuff.h:3052 [inline] + RIP: 0010:eth_hdr include/linux/if_ether.h:24 [inline] + RIP: 0010:geneve_xmit_skb drivers/net/geneve.c:898 [inline] + RIP: 0010:geneve_xmit+0x4c38/0x5730 drivers/net/geneve.c:1039 +Code: 21 c6 02 e9 35 d4 ff ff e8 a5 48 4c fb 90 0f 0b 90 e9 fd f5 ff ff e8 97 48 4c fb 90 0f 0b 90 e9 d8 f5 ff ff e8 89 48 4c fb 90 <0f> 0b 90 e9 41 e4 ff ff e8 7b 48 4c fb 90 0f 0b 90 e9 cd e7 ff ff +RSP: 0018:ffffc90003b2f870 EFLAGS: 00010283 +RAX: 000000000000037a RBX: 000000000000ffff RCX: ffffc9000dc3d000 +RDX: 0000000000080000 RSI: ffffffff86428417 RDI: 0000000000000003 +RBP: ffffc90003b2f9f0 R08: 0000000000000003 R09: 000000000000ffff +R10: 000000000000ffff R11: 0000000000000002 R12: ffff88806603c000 +R13: 0000000000000000 R14: ffff8880685b2780 R15: 0000000000000e23 +FS: 00007fdc2deed6c0(0000) GS:ffff8880b8600000(0000) knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +CR2: 0000001b30a1dff8 CR3: 0000000056b8c000 CR4: 00000000003526f0 +DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 +DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 +Call Trace: + + __netdev_start_xmit include/linux/netdevice.h:5002 [inline] + netdev_start_xmit include/linux/netdevice.h:5011 [inline] + __dev_direct_xmit+0x58a/0x720 net/core/dev.c:4490 + dev_direct_xmit include/linux/netdevice.h:3181 [inline] + packet_xmit+0x1e4/0x360 net/packet/af_packet.c:285 + packet_snd net/packet/af_packet.c:3146 [inline] + packet_sendmsg+0x2700/0x5660 net/packet/af_packet.c:3178 + sock_sendmsg_nosec net/socket.c:711 [inline] + __sock_sendmsg net/socket.c:726 [inline] + __sys_sendto+0x488/0x4f0 net/socket.c:2197 + __do_sys_sendto net/socket.c:2204 [inline] + __se_sys_sendto net/socket.c:2200 [inline] + __x64_sys_sendto+0xe0/0x1c0 net/socket.c:2200 + do_syscall_x64 arch/x86/entry/common.c:52 [inline] + do_syscall_64+0xcd/0x250 arch/x86/entry/common.c:83 + entry_SYSCALL_64_after_hwframe+0x77/0x7f + +Fixes: a025fb5f49ad ("geneve: Allow configuration of DF behaviour") +Reported-by: syzbot+3ec5271486d7cb2d242a@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/netdev/674f4b72.050a0220.17bd51.004a.GAE@google.com/T/#u +Signed-off-by: Eric Dumazet +Reviewed-by: Stefano Brivio +Link: https://patch.msgid.link/20241203182122.2725517-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/geneve.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c +index 8333a5620deff..b939d4711c59b 100644 +--- a/drivers/net/geneve.c ++++ b/drivers/net/geneve.c +@@ -986,7 +986,7 @@ static int geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev, + if (geneve->cfg.df == GENEVE_DF_SET) { + df = htons(IP_DF); + } else if (geneve->cfg.df == GENEVE_DF_INHERIT) { +- struct ethhdr *eth = eth_hdr(skb); ++ struct ethhdr *eth = skb_eth_hdr(skb); + + if (ntohs(eth->h_proto) == ETH_P_IPV6) { + df = htons(IP_DF); +-- +2.43.0 + diff --git a/queue-6.6/gpio-grgpio-add-null-check-in-grgpio_probe.patch b/queue-6.6/gpio-grgpio-add-null-check-in-grgpio_probe.patch new file mode 100644 index 00000000000..8067b6f7681 --- /dev/null +++ b/queue-6.6/gpio-grgpio-add-null-check-in-grgpio_probe.patch @@ -0,0 +1,41 @@ +From 841304a688e9aaa79f09f51434501954bcc59198 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 14 Nov 2024 17:18:22 +0800 +Subject: gpio: grgpio: Add NULL check in grgpio_probe + +From: Charles Han + +[ Upstream commit 050b23d081da0f29474de043e9538c1f7a351b3b ] + +devm_kasprintf() can return a NULL pointer on failure,but this +returned value in grgpio_probe is not checked. +Add NULL check in grgpio_probe, to handle kernel NULL +pointer dereference error. + +Cc: stable@vger.kernel.org +Fixes: 7eb6ce2f2723 ("gpio: Convert to using %pOF instead of full_name") +Signed-off-by: Charles Han +Link: https://lore.kernel.org/r/20241114091822.78199-1-hanchunchao@inspur.com +Signed-off-by: Bartosz Golaszewski +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-grgpio.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c +index fe919d9bd46a3..637a4d45f8c77 100644 +--- a/drivers/gpio/gpio-grgpio.c ++++ b/drivers/gpio/gpio-grgpio.c +@@ -362,6 +362,9 @@ static int grgpio_probe(struct platform_device *ofdev) + gc->owner = THIS_MODULE; + gc->to_irq = grgpio_to_irq; + gc->label = devm_kasprintf(dev, GFP_KERNEL, "%pOF", np); ++ if (!gc->label) ++ return -ENOMEM; ++ + gc->base = -1; + + err = of_property_read_u32(np, "nbits", &prop); +-- +2.43.0 + diff --git a/queue-6.6/gpio-grgpio-use-a-helper-variable-to-store-the-addre.patch b/queue-6.6/gpio-grgpio-use-a-helper-variable-to-store-the-addre.patch new file mode 100644 index 00000000000..f3418182da8 --- /dev/null +++ b/queue-6.6/gpio-grgpio-use-a-helper-variable-to-store-the-addre.patch @@ -0,0 +1,114 @@ +From 53b0b618e0ea7c1ffbaa4e291f212de4d6c98084 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 15 Oct 2024 15:18:31 +0200 +Subject: gpio: grgpio: use a helper variable to store the address of + ofdev->dev + +From: Bartosz Golaszewski + +[ Upstream commit d036ae41cebdfae92666024163c109b8fef516fa ] + +Instead of dereferencing the platform device pointer repeatedly, just +store its address in a helper variable. + +Link: https://lore.kernel.org/r/20241015131832.44678-3-brgl@bgdev.pl +Signed-off-by: Bartosz Golaszewski +Stable-dep-of: 050b23d081da ("gpio: grgpio: Add NULL check in grgpio_probe") +Signed-off-by: Sasha Levin +--- + drivers/gpio/gpio-grgpio.c | 23 ++++++++++++----------- + 1 file changed, 12 insertions(+), 11 deletions(-) + +diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c +index 0163c95f6dd75..fe919d9bd46a3 100644 +--- a/drivers/gpio/gpio-grgpio.c ++++ b/drivers/gpio/gpio-grgpio.c +@@ -328,6 +328,7 @@ static const struct irq_domain_ops grgpio_irq_domain_ops = { + static int grgpio_probe(struct platform_device *ofdev) + { + struct device_node *np = ofdev->dev.of_node; ++ struct device *dev = &ofdev->dev; + void __iomem *regs; + struct gpio_chip *gc; + struct grgpio_priv *priv; +@@ -337,7 +338,7 @@ static int grgpio_probe(struct platform_device *ofdev) + int size; + int i; + +- priv = devm_kzalloc(&ofdev->dev, sizeof(*priv), GFP_KERNEL); ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + +@@ -346,28 +347,28 @@ static int grgpio_probe(struct platform_device *ofdev) + return PTR_ERR(regs); + + gc = &priv->gc; +- err = bgpio_init(gc, &ofdev->dev, 4, regs + GRGPIO_DATA, ++ err = bgpio_init(gc, dev, 4, regs + GRGPIO_DATA, + regs + GRGPIO_OUTPUT, NULL, regs + GRGPIO_DIR, NULL, + BGPIOF_BIG_ENDIAN_BYTE_ORDER); + if (err) { +- dev_err(&ofdev->dev, "bgpio_init() failed\n"); ++ dev_err(dev, "bgpio_init() failed\n"); + return err; + } + + priv->regs = regs; + priv->imask = gc->read_reg(regs + GRGPIO_IMASK); +- priv->dev = &ofdev->dev; ++ priv->dev = dev; + + gc->owner = THIS_MODULE; + gc->to_irq = grgpio_to_irq; +- gc->label = devm_kasprintf(&ofdev->dev, GFP_KERNEL, "%pOF", np); ++ gc->label = devm_kasprintf(dev, GFP_KERNEL, "%pOF", np); + gc->base = -1; + + err = of_property_read_u32(np, "nbits", &prop); + if (err || prop <= 0 || prop > GRGPIO_MAX_NGPIO) { + gc->ngpio = GRGPIO_MAX_NGPIO; +- dev_dbg(&ofdev->dev, +- "No or invalid nbits property: assume %d\n", gc->ngpio); ++ dev_dbg(dev, "No or invalid nbits property: assume %d\n", ++ gc->ngpio); + } else { + gc->ngpio = prop; + } +@@ -379,7 +380,7 @@ static int grgpio_probe(struct platform_device *ofdev) + irqmap = (s32 *)of_get_property(np, "irqmap", &size); + if (irqmap) { + if (size < gc->ngpio) { +- dev_err(&ofdev->dev, ++ dev_err(dev, + "irqmap shorter than ngpio (%d < %d)\n", + size, gc->ngpio); + return -EINVAL; +@@ -389,7 +390,7 @@ static int grgpio_probe(struct platform_device *ofdev) + &grgpio_irq_domain_ops, + priv); + if (!priv->domain) { +- dev_err(&ofdev->dev, "Could not add irq domain\n"); ++ dev_err(dev, "Could not add irq domain\n"); + return -EINVAL; + } + +@@ -419,13 +420,13 @@ static int grgpio_probe(struct platform_device *ofdev) + + err = gpiochip_add_data(gc, priv); + if (err) { +- dev_err(&ofdev->dev, "Could not add gpiochip\n"); ++ dev_err(dev, "Could not add gpiochip\n"); + if (priv->domain) + irq_domain_remove(priv->domain); + return err; + } + +- dev_info(&ofdev->dev, "regs=0x%p, base=%d, ngpio=%d, irqs=%s\n", ++ dev_info(dev, "regs=0x%p, base=%d, ngpio=%d, irqs=%s\n", + priv->regs, gc->base, gc->ngpio, priv->domain ? "on" : "off"); + + return 0; +-- +2.43.0 + diff --git a/queue-6.6/i3c-master-add-enable-disable-hot-join-in-sys-entry.patch b/queue-6.6/i3c-master-add-enable-disable-hot-join-in-sys-entry.patch new file mode 100644 index 00000000000..b9a76241066 --- /dev/null +++ b/queue-6.6/i3c-master-add-enable-disable-hot-join-in-sys-entry.patch @@ -0,0 +1,159 @@ +From bb1cfc79ceb7defbe32db97cf3662821eabced56 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 1 Dec 2023 17:25:27 -0500 +Subject: i3c: master: add enable(disable) hot join in sys entry + +From: Frank Li + +[ Upstream commit 317bacf960a4879af22d12175f47d284930b3273 ] + +Add hotjoin entry in sys file system allow user enable/disable hotjoin +feature. + +Add (*enable(disable)_hotjoin)() to i3c_master_controller_ops. +Add api i3c_master_enable(disable)_hotjoin(); + +Signed-off-by: Frank Li +Link: https://lore.kernel.org/r/20231201222532.2431484-2-Frank.Li@nxp.com +Signed-off-by: Alexandre Belloni +Stable-dep-of: 25bc99be5fe5 ("i3c: master: svc: Modify enabled_events bit 7:0 to act as IBI enable counter") +Signed-off-by: Sasha Levin +--- + drivers/i3c/master.c | 83 ++++++++++++++++++++++++++++++++++++++ + include/linux/i3c/master.h | 5 +++ + 2 files changed, 88 insertions(+) + +diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c +index 70d120dfb0908..bbd5dc89be229 100644 +--- a/drivers/i3c/master.c ++++ b/drivers/i3c/master.c +@@ -526,6 +526,88 @@ static ssize_t i2c_scl_frequency_show(struct device *dev, + } + static DEVICE_ATTR_RO(i2c_scl_frequency); + ++static int i3c_set_hotjoin(struct i3c_master_controller *master, bool enable) ++{ ++ int ret; ++ ++ if (!master || !master->ops) ++ return -EINVAL; ++ ++ if (!master->ops->enable_hotjoin || !master->ops->disable_hotjoin) ++ return -EINVAL; ++ ++ i3c_bus_normaluse_lock(&master->bus); ++ ++ if (enable) ++ ret = master->ops->enable_hotjoin(master); ++ else ++ ret = master->ops->disable_hotjoin(master); ++ ++ master->hotjoin = enable; ++ ++ i3c_bus_normaluse_unlock(&master->bus); ++ ++ return ret; ++} ++ ++static ssize_t hotjoin_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct i3c_bus *i3cbus = dev_to_i3cbus(dev); ++ int ret; ++ bool res; ++ ++ if (!i3cbus->cur_master) ++ return -EINVAL; ++ ++ if (kstrtobool(buf, &res)) ++ return -EINVAL; ++ ++ ret = i3c_set_hotjoin(i3cbus->cur_master->common.master, res); ++ if (ret) ++ return ret; ++ ++ return count; ++} ++ ++/* ++ * i3c_master_enable_hotjoin - Enable hotjoin ++ * @master: I3C master object ++ * ++ * Return: a 0 in case of success, an negative error code otherwise. ++ */ ++int i3c_master_enable_hotjoin(struct i3c_master_controller *master) ++{ ++ return i3c_set_hotjoin(master, true); ++} ++EXPORT_SYMBOL_GPL(i3c_master_enable_hotjoin); ++ ++/* ++ * i3c_master_disable_hotjoin - Disable hotjoin ++ * @master: I3C master object ++ * ++ * Return: a 0 in case of success, an negative error code otherwise. ++ */ ++int i3c_master_disable_hotjoin(struct i3c_master_controller *master) ++{ ++ return i3c_set_hotjoin(master, false); ++} ++EXPORT_SYMBOL_GPL(i3c_master_disable_hotjoin); ++ ++static ssize_t hotjoin_show(struct device *dev, struct device_attribute *da, char *buf) ++{ ++ struct i3c_bus *i3cbus = dev_to_i3cbus(dev); ++ ssize_t ret; ++ ++ i3c_bus_normaluse_lock(i3cbus); ++ ret = sysfs_emit(buf, "%d\n", i3cbus->cur_master->common.master->hotjoin); ++ i3c_bus_normaluse_unlock(i3cbus); ++ ++ return ret; ++} ++ ++static DEVICE_ATTR_RW(hotjoin); ++ + static struct attribute *i3c_masterdev_attrs[] = { + &dev_attr_mode.attr, + &dev_attr_current_master.attr, +@@ -536,6 +618,7 @@ static struct attribute *i3c_masterdev_attrs[] = { + &dev_attr_pid.attr, + &dev_attr_dynamic_address.attr, + &dev_attr_hdrcap.attr, ++ &dev_attr_hotjoin.attr, + NULL, + }; + ATTRIBUTE_GROUPS(i3c_masterdev); +diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h +index 0b52da4f23467..65b8965968af2 100644 +--- a/include/linux/i3c/master.h ++++ b/include/linux/i3c/master.h +@@ -452,6 +452,8 @@ struct i3c_master_controller_ops { + int (*disable_ibi)(struct i3c_dev_desc *dev); + void (*recycle_ibi_slot)(struct i3c_dev_desc *dev, + struct i3c_ibi_slot *slot); ++ int (*enable_hotjoin)(struct i3c_master_controller *master); ++ int (*disable_hotjoin)(struct i3c_master_controller *master); + }; + + /** +@@ -487,6 +489,7 @@ struct i3c_master_controller { + const struct i3c_master_controller_ops *ops; + unsigned int secondary : 1; + unsigned int init_done : 1; ++ unsigned int hotjoin: 1; + struct { + struct list_head i3c; + struct list_head i2c; +@@ -543,6 +546,8 @@ int i3c_master_register(struct i3c_master_controller *master, + const struct i3c_master_controller_ops *ops, + bool secondary); + void i3c_master_unregister(struct i3c_master_controller *master); ++int i3c_master_enable_hotjoin(struct i3c_master_controller *master); ++int i3c_master_disable_hotjoin(struct i3c_master_controller *master); + + /** + * i3c_dev_get_master_data() - get master private data attached to an I3C +-- +2.43.0 + diff --git a/queue-6.6/i3c-master-extend-address-status-bit-to-4-and-add-i3.patch b/queue-6.6/i3c-master-extend-address-status-bit-to-4-and-add-i3.patch new file mode 100644 index 00000000000..9e1908f40a7 --- /dev/null +++ b/queue-6.6/i3c-master-extend-address-status-bit-to-4-and-add-i3.patch @@ -0,0 +1,197 @@ +From 9d585a4b26f05be49f34f3da16658d20781f0f7d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 21 Oct 2024 11:45:07 -0400 +Subject: i3c: master: Extend address status bit to 4 and add + I3C_ADDR_SLOT_EXT_DESIRED +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Frank Li + +[ Upstream commit 2f552fa280590e61bd3dbe66a7b54b99caa642a4 ] + +Extend the address status bit to 4 and introduce the +I3C_ADDR_SLOT_EXT_DESIRED macro to indicate that a device prefers a +specific address. This is generally set by the 'assigned-address' in the +device tree source (dts) file. + + ┌────┬─────────────┬───┬─────────┬───┐ + │S/Sr│ 7'h7E RnW=0 │ACK│ ENTDAA │ T ├────┐ + └────┴─────────────┴───┴─────────┴───┘ │ + ┌─────────────────────────────────────────┘ + │ ┌──┬─────────────┬───┬─────────────────┬────────────────┬───┬─────────┐ + └─►│Sr│7'h7E RnW=1 │ACK│48bit UID BCR DCR│Assign 7bit Addr│PAR│ ACK/NACK│ + └──┴─────────────┴───┴─────────────────┴────────────────┴───┴─────────┘ + +Some master controllers (such as HCI) need to prepare the entire above +transaction before sending it out to the I3C bus. This means that a 7-bit +dynamic address needs to be allocated before knowing the target device's +UID information. + +However, some I3C targets may request specific addresses (called as +"init_dyn_addr"), which is typically specified by the DT-'s +assigned-address property. Lower addresses having higher IBI priority. If +it is available, i3c_bus_get_free_addr() preferably return a free address +that is not in the list of desired addresses (called as "init_dyn_addr"). +This allows the device with the "init_dyn_addr" to switch to its +"init_dyn_addr" when it hot-joins the I3C bus. Otherwise, if the +"init_dyn_addr" is already in use by another I3C device, the target device +will not be able to switch to its desired address. + +If the previous step fails, fallback returning one of the remaining +unassigned address, regardless of its state in the desired list. + +Reviewed-by: Miquel Raynal +Signed-off-by: Frank Li +Link: https://lore.kernel.org/r/20241021-i3c_dts_assign-v8-2-4098b8bde01e@nxp.com +Signed-off-by: Alexandre Belloni +Stable-dep-of: 851bd21cdb55 ("i3c: master: Fix dynamic address leak when 'assigned-address' is present") +Signed-off-by: Sasha Levin +--- + drivers/i3c/master.c | 65 +++++++++++++++++++++++++++++++------- + include/linux/i3c/master.h | 7 ++-- + 2 files changed, 59 insertions(+), 13 deletions(-) + +diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c +index 2b6bc03652139..d2a08a9a54414 100644 +--- a/drivers/i3c/master.c ++++ b/drivers/i3c/master.c +@@ -342,7 +342,7 @@ struct bus_type i3c_bus_type = { + }; + + static enum i3c_addr_slot_status +-i3c_bus_get_addr_slot_status(struct i3c_bus *bus, u16 addr) ++i3c_bus_get_addr_slot_status_mask(struct i3c_bus *bus, u16 addr, u32 mask) + { + unsigned long status; + int bitpos = addr * I3C_ADDR_SLOT_STATUS_BITS; +@@ -353,11 +353,17 @@ i3c_bus_get_addr_slot_status(struct i3c_bus *bus, u16 addr) + status = bus->addrslots[bitpos / BITS_PER_LONG]; + status >>= bitpos % BITS_PER_LONG; + +- return status & I3C_ADDR_SLOT_STATUS_MASK; ++ return status & mask; + } + +-static void i3c_bus_set_addr_slot_status(struct i3c_bus *bus, u16 addr, +- enum i3c_addr_slot_status status) ++static enum i3c_addr_slot_status ++i3c_bus_get_addr_slot_status(struct i3c_bus *bus, u16 addr) ++{ ++ return i3c_bus_get_addr_slot_status_mask(bus, addr, I3C_ADDR_SLOT_STATUS_MASK); ++} ++ ++static void i3c_bus_set_addr_slot_status_mask(struct i3c_bus *bus, u16 addr, ++ enum i3c_addr_slot_status status, u32 mask) + { + int bitpos = addr * I3C_ADDR_SLOT_STATUS_BITS; + unsigned long *ptr; +@@ -366,9 +372,14 @@ static void i3c_bus_set_addr_slot_status(struct i3c_bus *bus, u16 addr, + return; + + ptr = bus->addrslots + (bitpos / BITS_PER_LONG); +- *ptr &= ~((unsigned long)I3C_ADDR_SLOT_STATUS_MASK << +- (bitpos % BITS_PER_LONG)); +- *ptr |= (unsigned long)status << (bitpos % BITS_PER_LONG); ++ *ptr &= ~((unsigned long)mask << (bitpos % BITS_PER_LONG)); ++ *ptr |= ((unsigned long)status & mask) << (bitpos % BITS_PER_LONG); ++} ++ ++static void i3c_bus_set_addr_slot_status(struct i3c_bus *bus, u16 addr, ++ enum i3c_addr_slot_status status) ++{ ++ i3c_bus_set_addr_slot_status_mask(bus, addr, status, I3C_ADDR_SLOT_STATUS_MASK); + } + + static bool i3c_bus_dev_addr_is_avail(struct i3c_bus *bus, u8 addr) +@@ -380,13 +391,44 @@ static bool i3c_bus_dev_addr_is_avail(struct i3c_bus *bus, u8 addr) + return status == I3C_ADDR_SLOT_FREE; + } + ++/* ++ * ┌────┬─────────────┬───┬─────────┬───┐ ++ * │S/Sr│ 7'h7E RnW=0 │ACK│ ENTDAA │ T ├────┐ ++ * └────┴─────────────┴───┴─────────┴───┘ │ ++ * ┌─────────────────────────────────────────┘ ++ * │ ┌──┬─────────────┬───┬─────────────────┬────────────────┬───┬─────────┐ ++ * └─►│Sr│7'h7E RnW=1 │ACK│48bit UID BCR DCR│Assign 7bit Addr│PAR│ ACK/NACK│ ++ * └──┴─────────────┴───┴─────────────────┴────────────────┴───┴─────────┘ ++ * Some master controllers (such as HCI) need to prepare the entire above transaction before ++ * sending it out to the I3C bus. This means that a 7-bit dynamic address needs to be allocated ++ * before knowing the target device's UID information. ++ * ++ * However, some I3C targets may request specific addresses (called as "init_dyn_addr"), which is ++ * typically specified by the DT-'s assigned-address property. Lower addresses having higher IBI ++ * priority. If it is available, i3c_bus_get_free_addr() preferably return a free address that is ++ * not in the list of desired addresses (called as "init_dyn_addr"). This allows the device with ++ * the "init_dyn_addr" to switch to its "init_dyn_addr" when it hot-joins the I3C bus. Otherwise, ++ * if the "init_dyn_addr" is already in use by another I3C device, the target device will not be ++ * able to switch to its desired address. ++ * ++ * If the previous step fails, fallback returning one of the remaining unassigned address, ++ * regardless of its state in the desired list. ++ */ + static int i3c_bus_get_free_addr(struct i3c_bus *bus, u8 start_addr) + { + enum i3c_addr_slot_status status; + u8 addr; + + for (addr = start_addr; addr < I3C_MAX_ADDR; addr++) { +- status = i3c_bus_get_addr_slot_status(bus, addr); ++ status = i3c_bus_get_addr_slot_status_mask(bus, addr, ++ I3C_ADDR_SLOT_EXT_STATUS_MASK); ++ if (status == I3C_ADDR_SLOT_FREE) ++ return addr; ++ } ++ ++ for (addr = start_addr; addr < I3C_MAX_ADDR; addr++) { ++ status = i3c_bus_get_addr_slot_status_mask(bus, addr, ++ I3C_ADDR_SLOT_STATUS_MASK); + if (status == I3C_ADDR_SLOT_FREE) + return addr; + } +@@ -1877,9 +1919,10 @@ static int i3c_master_bus_init(struct i3c_master_controller *master) + goto err_rstdaa; + } + +- i3c_bus_set_addr_slot_status(&master->bus, +- i3cboardinfo->init_dyn_addr, +- I3C_ADDR_SLOT_I3C_DEV); ++ i3c_bus_set_addr_slot_status_mask(&master->bus, ++ i3cboardinfo->init_dyn_addr, ++ I3C_ADDR_SLOT_I3C_DEV | I3C_ADDR_SLOT_EXT_DESIRED, ++ I3C_ADDR_SLOT_EXT_STATUS_MASK); + + /* + * Only try to create/attach devices that have a static +diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h +index ed6b153481021..f2eb2452ffa5f 100644 +--- a/include/linux/i3c/master.h ++++ b/include/linux/i3c/master.h +@@ -290,7 +290,8 @@ enum i3c_open_drain_speed { + * @I3C_ADDR_SLOT_I2C_DEV: address is assigned to an I2C device + * @I3C_ADDR_SLOT_I3C_DEV: address is assigned to an I3C device + * @I3C_ADDR_SLOT_STATUS_MASK: address slot mask +- * ++ * @I3C_ADDR_SLOT_EXT_DESIRED: the bitmask represents addresses that are preferred by some devices, ++ * such as the "assigned-address" property in a device tree source. + * On an I3C bus, addresses are assigned dynamically, and we need to know which + * addresses are free to use and which ones are already assigned. + * +@@ -303,9 +304,11 @@ enum i3c_addr_slot_status { + I3C_ADDR_SLOT_I2C_DEV, + I3C_ADDR_SLOT_I3C_DEV, + I3C_ADDR_SLOT_STATUS_MASK = 3, ++ I3C_ADDR_SLOT_EXT_STATUS_MASK = 7, ++ I3C_ADDR_SLOT_EXT_DESIRED = BIT(2), + }; + +-#define I3C_ADDR_SLOT_STATUS_BITS 2 ++#define I3C_ADDR_SLOT_STATUS_BITS 4 + + /** + * struct i3c_bus - I3C bus object +-- +2.43.0 + diff --git a/queue-6.6/i3c-master-fix-dynamic-address-leak-when-assigned-ad.patch b/queue-6.6/i3c-master-fix-dynamic-address-leak-when-assigned-ad.patch new file mode 100644 index 00000000000..e9ac1d72153 --- /dev/null +++ b/queue-6.6/i3c-master-fix-dynamic-address-leak-when-assigned-ad.patch @@ -0,0 +1,104 @@ +From 8bd2096f0d46d0300978f67165577286bfddb7c8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 21 Oct 2024 11:45:08 -0400 +Subject: i3c: master: Fix dynamic address leak when 'assigned-address' is + present + +From: Frank Li + +[ Upstream commit 851bd21cdb55e727ab29280bc9f6b678164f802a ] + +If the DTS contains 'assigned-address', a dynamic address leak occurs +during hotjoin events. + +Assume a device have assigned-address 0xb. + - Device issue Hotjoin + - Call i3c_master_do_daa() + - Call driver xxx_do_daa() + - Call i3c_master_get_free_addr() to get dynamic address 0x9 + - i3c_master_add_i3c_dev_locked(0x9) + - expected_dyn_addr = newdev->boardinfo->init_dyn_addr (0xb); + - i3c_master_reattach_i3c_dev(newdev(0xb), old_dyn_addr(0x9)); + - if (dev->info.dyn_addr != old_dyn_addr && + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 0xb != 0x9 -> TRUE + (!dev->boardinfo || + ^^^^^^^^^^^^^^^ -> FALSE + dev->info.dyn_addr != dev->boardinfo->init_dyn_addr)) { + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 0xb != 0xb -> FALSE + ... + i3c_bus_set_addr_slot_status(&master->bus, old_dyn_addr, + I3C_ADDR_SLOT_FREE); + ^^^ + This will be skipped. So old_dyn_addr never free + } + + - i3c_master_get_free_addr() will return increased sequence number. + +Remove dev->info.dyn_addr != dev->boardinfo->init_dyn_addr condition check. +dev->info.dyn_addr should be checked before calling this function because +i3c_master_setnewda_locked() has already been called and the target device +has already accepted dyn_addr. It is too late to check if dyn_addr is free +in i3c_master_reattach_i3c_dev(). + +Add check to ensure expected_dyn_addr is free before +i3c_master_setnewda_locked(). + +Fixes: cc3a392d69b6 ("i3c: master: fix for SETDASA and DAA process") +Cc: stable@kernel.org +Reviewed-by: Miquel Raynal +Signed-off-by: Frank Li +Link: https://lore.kernel.org/r/20241021-i3c_dts_assign-v8-3-4098b8bde01e@nxp.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master.c | 15 +++++---------- + 1 file changed, 5 insertions(+), 10 deletions(-) + +diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c +index d2a08a9a54414..5d737bdbfe478 100644 +--- a/drivers/i3c/master.c ++++ b/drivers/i3c/master.c +@@ -1507,16 +1507,9 @@ static int i3c_master_reattach_i3c_dev(struct i3c_dev_desc *dev, + u8 old_dyn_addr) + { + struct i3c_master_controller *master = i3c_dev_get_master(dev); +- enum i3c_addr_slot_status status; + int ret; + +- if (dev->info.dyn_addr != old_dyn_addr && +- (!dev->boardinfo || +- dev->info.dyn_addr != dev->boardinfo->init_dyn_addr)) { +- status = i3c_bus_get_addr_slot_status(&master->bus, +- dev->info.dyn_addr); +- if (status != I3C_ADDR_SLOT_FREE) +- return -EBUSY; ++ if (dev->info.dyn_addr != old_dyn_addr) { + i3c_bus_set_addr_slot_status(&master->bus, + dev->info.dyn_addr, + I3C_ADDR_SLOT_I3C_DEV); +@@ -1919,9 +1912,10 @@ static int i3c_master_bus_init(struct i3c_master_controller *master) + goto err_rstdaa; + } + ++ /* Do not mark as occupied until real device exist in bus */ + i3c_bus_set_addr_slot_status_mask(&master->bus, + i3cboardinfo->init_dyn_addr, +- I3C_ADDR_SLOT_I3C_DEV | I3C_ADDR_SLOT_EXT_DESIRED, ++ I3C_ADDR_SLOT_EXT_DESIRED, + I3C_ADDR_SLOT_EXT_STATUS_MASK); + + /* +@@ -2085,7 +2079,8 @@ int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master, + else + expected_dyn_addr = newdev->info.dyn_addr; + +- if (newdev->info.dyn_addr != expected_dyn_addr) { ++ if (newdev->info.dyn_addr != expected_dyn_addr && ++ i3c_bus_get_addr_slot_status(&master->bus, expected_dyn_addr) == I3C_ADDR_SLOT_FREE) { + /* + * Try to apply the expected dynamic address. If it fails, keep + * the address assigned by the master. +-- +2.43.0 + diff --git a/queue-6.6/i3c-master-fix-kernel-doc-check-warning.patch b/queue-6.6/i3c-master-fix-kernel-doc-check-warning.patch new file mode 100644 index 00000000000..cb08faf6f90 --- /dev/null +++ b/queue-6.6/i3c-master-fix-kernel-doc-check-warning.patch @@ -0,0 +1,50 @@ +From 6b70fb834f8fa3e49b9d0fce093cd47b90d6057f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Jan 2024 00:25:48 -0500 +Subject: i3c: master: fix kernel-doc check warning + +From: Frank Li + +[ Upstream commit 34d946b723b53488ab39d8ac540ddf9db255317a ] + +Fix warning found by + 'scripts/kernel-doc -v -none include/linux/i3c/master.h' + +include/linux/i3c/master.h:457: warning: Function parameter or member 'enable_hotjoin' not described in 'i3c_master_controller_ops' +include/linux/i3c/master.h:457: warning: Function parameter or member 'disable_hotjoin' not described in 'i3c_master_controller_ops' +include/linux/i3c/master.h:499: warning: Function parameter or member 'hotjoin' not described in 'i3c_master_controller' + +Signed-off-by: Frank Li +Reviewed-by: Miquel Raynal +Link: https://lore.kernel.org/r/20240109052548.2128133-1-Frank.Li@nxp.com +Signed-off-by: Alexandre Belloni +Stable-dep-of: 25bc99be5fe5 ("i3c: master: svc: Modify enabled_events bit 7:0 to act as IBI enable counter") +Signed-off-by: Sasha Levin +--- + include/linux/i3c/master.h | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h +index 65b8965968af2..1cbf0baca65fe 100644 +--- a/include/linux/i3c/master.h ++++ b/include/linux/i3c/master.h +@@ -426,6 +426,8 @@ struct i3c_bus { + * for a future IBI + * This method is mandatory only if ->request_ibi is not + * NULL. ++ * @enable_hotjoin: enable hot join event detect. ++ * @disable_hotjoin: disable hot join event detect. + */ + struct i3c_master_controller_ops { + int (*bus_init)(struct i3c_master_controller *master); +@@ -467,6 +469,7 @@ struct i3c_master_controller_ops { + * @ops: master operations. See &struct i3c_master_controller_ops + * @secondary: true if the master is a secondary master + * @init_done: true when the bus initialization is done ++ * @hotjoin: true if the master support hotjoin + * @boardinfo.i3c: list of I3C boardinfo objects + * @boardinfo.i2c: list of I2C boardinfo objects + * @boardinfo: board-level information attached to devices connected on the bus +-- +2.43.0 + diff --git a/queue-6.6/i3c-master-replace-hard-code-2-with-macro-i3c_addr_s.patch b/queue-6.6/i3c-master-replace-hard-code-2-with-macro-i3c_addr_s.patch new file mode 100644 index 00000000000..58271c611f5 --- /dev/null +++ b/queue-6.6/i3c-master-replace-hard-code-2-with-macro-i3c_addr_s.patch @@ -0,0 +1,72 @@ +From 05199ecbf1aac4835dd62c110407083df6113bd3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 21 Oct 2024 11:45:06 -0400 +Subject: i3c: master: Replace hard code 2 with macro I3C_ADDR_SLOT_STATUS_BITS + +From: Frank Li + +[ Upstream commit 16aed0a6520ba01b7d22c32e193fc1ec674f92d4 ] + +Replace the hardcoded value 2, which indicates 2 bits for I3C address +status, with the predefined macro I3C_ADDR_SLOT_STATUS_BITS. + +Improve maintainability and extensibility of the code. + +Reviewed-by: Miquel Raynal +Signed-off-by: Frank Li +Link: https://lore.kernel.org/r/20241021-i3c_dts_assign-v8-1-4098b8bde01e@nxp.com +Signed-off-by: Alexandre Belloni +Stable-dep-of: 851bd21cdb55 ("i3c: master: Fix dynamic address leak when 'assigned-address' is present") +Signed-off-by: Sasha Levin +--- + drivers/i3c/master.c | 4 ++-- + include/linux/i3c/master.h | 4 +++- + 2 files changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c +index 78171a754a3f8..2b6bc03652139 100644 +--- a/drivers/i3c/master.c ++++ b/drivers/i3c/master.c +@@ -345,7 +345,7 @@ static enum i3c_addr_slot_status + i3c_bus_get_addr_slot_status(struct i3c_bus *bus, u16 addr) + { + unsigned long status; +- int bitpos = addr * 2; ++ int bitpos = addr * I3C_ADDR_SLOT_STATUS_BITS; + + if (addr > I2C_MAX_ADDR) + return I3C_ADDR_SLOT_RSVD; +@@ -359,7 +359,7 @@ i3c_bus_get_addr_slot_status(struct i3c_bus *bus, u16 addr) + static void i3c_bus_set_addr_slot_status(struct i3c_bus *bus, u16 addr, + enum i3c_addr_slot_status status) + { +- int bitpos = addr * 2; ++ int bitpos = addr * I3C_ADDR_SLOT_STATUS_BITS; + unsigned long *ptr; + + if (addr > I2C_MAX_ADDR) +diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h +index f0aa4c549aa7f..ed6b153481021 100644 +--- a/include/linux/i3c/master.h ++++ b/include/linux/i3c/master.h +@@ -305,6 +305,8 @@ enum i3c_addr_slot_status { + I3C_ADDR_SLOT_STATUS_MASK = 3, + }; + ++#define I3C_ADDR_SLOT_STATUS_BITS 2 ++ + /** + * struct i3c_bus - I3C bus object + * @cur_master: I3C master currently driving the bus. Since I3C is multi-master +@@ -346,7 +348,7 @@ enum i3c_addr_slot_status { + struct i3c_bus { + struct i3c_dev_desc *cur_master; + int id; +- unsigned long addrslots[((I2C_MAX_ADDR + 1) * 2) / BITS_PER_LONG]; ++ unsigned long addrslots[((I2C_MAX_ADDR + 1) * I3C_ADDR_SLOT_STATUS_BITS) / BITS_PER_LONG]; + enum i3c_bus_mode mode; + struct { + unsigned long i3c; +-- +2.43.0 + diff --git a/queue-6.6/i3c-master-support-to-adjust-first-broadcast-address.patch b/queue-6.6/i3c-master-support-to-adjust-first-broadcast-address.patch new file mode 100644 index 00000000000..143eda61d2a --- /dev/null +++ b/queue-6.6/i3c-master-support-to-adjust-first-broadcast-address.patch @@ -0,0 +1,101 @@ +From 9941ab62d3766426b1b56b7260a8049bcc7559ef Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Sep 2024 13:16:25 +0800 +Subject: i3c: master: support to adjust first broadcast address speed + +From: Carlos Song + +[ Upstream commit aef79e189ba2b32f78bd35daf2c0b41f3868a321 ] + +According to I3C spec 6.2 Timing Specification, the Open Drain High Period +of SCL Clock timing for first broadcast address should be adjusted to 200ns +at least. I3C device working as i2c device will see the broadcast to close +its Spike Filter then change to work at I3C mode. After that I3C open drain +SCL high level should be adjusted back. + +Signed-off-by: Carlos Song +Reviewed-by: Miquel Raynal +Reviewed-by: Frank Li +Link: https://lore.kernel.org/r/20240910051626.4052552-1-carlos.song@nxp.com +Signed-off-by: Alexandre Belloni +Stable-dep-of: 25bc99be5fe5 ("i3c: master: svc: Modify enabled_events bit 7:0 to act as IBI enable counter") +Signed-off-by: Sasha Levin +--- + drivers/i3c/master.c | 12 ++++++++++++ + include/linux/i3c/master.h | 16 ++++++++++++++++ + 2 files changed, 28 insertions(+) + +diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c +index bbd5dc89be229..78171a754a3f8 100644 +--- a/drivers/i3c/master.c ++++ b/drivers/i3c/master.c +@@ -1827,6 +1827,12 @@ static int i3c_master_bus_init(struct i3c_master_controller *master) + goto err_bus_cleanup; + } + ++ if (master->ops->set_speed) { ++ ret = master->ops->set_speed(master, I3C_OPEN_DRAIN_SLOW_SPEED); ++ if (ret) ++ goto err_bus_cleanup; ++ } ++ + /* + * Reset all dynamic address that may have been assigned before + * (assigned by the bootloader for example). +@@ -1835,6 +1841,12 @@ static int i3c_master_bus_init(struct i3c_master_controller *master) + if (ret && ret != I3C_ERROR_M2) + goto err_bus_cleanup; + ++ if (master->ops->set_speed) { ++ master->ops->set_speed(master, I3C_OPEN_DRAIN_NORMAL_SPEED); ++ if (ret) ++ goto err_bus_cleanup; ++ } ++ + /* Disable all slave events before starting DAA. */ + ret = i3c_master_disec_locked(master, I3C_BROADCAST_ADDR, + I3C_CCC_EVENT_SIR | I3C_CCC_EVENT_MR | +diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h +index 1cbf0baca65fe..f0aa4c549aa7f 100644 +--- a/include/linux/i3c/master.h ++++ b/include/linux/i3c/master.h +@@ -269,6 +269,20 @@ enum i3c_bus_mode { + I3C_BUS_MODE_MIXED_SLOW, + }; + ++/** ++ * enum i3c_open_drain_speed - I3C open-drain speed ++ * @I3C_OPEN_DRAIN_SLOW_SPEED: Slow open-drain speed for sending the first ++ * broadcast address. The first broadcast address at this speed ++ * will be visible to all devices on the I3C bus. I3C devices ++ * working in I2C mode will turn off their spike filter when ++ * switching into I3C mode. ++ * @I3C_OPEN_DRAIN_NORMAL_SPEED: Normal open-drain speed in I3C bus mode. ++ */ ++enum i3c_open_drain_speed { ++ I3C_OPEN_DRAIN_SLOW_SPEED, ++ I3C_OPEN_DRAIN_NORMAL_SPEED, ++}; ++ + /** + * enum i3c_addr_slot_status - I3C address slot status + * @I3C_ADDR_SLOT_FREE: address is free +@@ -428,6 +442,7 @@ struct i3c_bus { + * NULL. + * @enable_hotjoin: enable hot join event detect. + * @disable_hotjoin: disable hot join event detect. ++ * @set_speed: adjust I3C open drain mode timing. + */ + struct i3c_master_controller_ops { + int (*bus_init)(struct i3c_master_controller *master); +@@ -456,6 +471,7 @@ struct i3c_master_controller_ops { + struct i3c_ibi_slot *slot); + int (*enable_hotjoin)(struct i3c_master_controller *master); + int (*disable_hotjoin)(struct i3c_master_controller *master); ++ int (*set_speed)(struct i3c_master_controller *master, enum i3c_open_drain_speed speed); + }; + + /** +-- +2.43.0 + diff --git a/queue-6.6/i3c-master-svc-add-hot-join-support.patch b/queue-6.6/i3c-master-svc-add-hot-join-support.patch new file mode 100644 index 00000000000..eee164fbb0f --- /dev/null +++ b/queue-6.6/i3c-master-svc-add-hot-join-support.patch @@ -0,0 +1,165 @@ +From 0a946b7a1c1b94c3473ef41ff7e2582b451701da Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 1 Dec 2023 17:25:28 -0500 +Subject: i3c: master: svc: add hot join support + +From: Frank Li + +[ Upstream commit 05b26c31a4859af9e75b7de77458e99358364fe1 ] + +Add hot join support for svc master controller. Disable hot join by +default. +User can use sysfs entry to enable hot join. + +Signed-off-by: Frank Li +Link: https://lore.kernel.org/r/20231201222532.2431484-3-Frank.Li@nxp.com +Signed-off-by: Alexandre Belloni +Stable-dep-of: 25bc99be5fe5 ("i3c: master: svc: Modify enabled_events bit 7:0 to act as IBI enable counter") +Signed-off-by: Sasha Levin +--- + drivers/i3c/master/svc-i3c-master.c | 61 +++++++++++++++++++++++++++-- + 1 file changed, 57 insertions(+), 4 deletions(-) + +diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c +index dca266d9dd122..139b51a575366 100644 +--- a/drivers/i3c/master/svc-i3c-master.c ++++ b/drivers/i3c/master/svc-i3c-master.c +@@ -128,6 +128,9 @@ + /* This parameter depends on the implementation and may be tuned */ + #define SVC_I3C_FIFO_SIZE 16 + ++#define SVC_I3C_EVENT_IBI BIT(0) ++#define SVC_I3C_EVENT_HOTJOIN BIT(1) ++ + struct svc_i3c_cmd { + u8 addr; + bool rnw; +@@ -178,6 +181,7 @@ struct svc_i3c_regs_save { + * @ibi.tbq_slot: To be queued IBI slot + * @ibi.lock: IBI lock + * @lock: Transfer lock, protect between IBI work thread and callbacks from master ++ * @enabled_events: Bit masks for enable events (IBI, HotJoin). + */ + struct svc_i3c_master { + struct i3c_master_controller base; +@@ -207,6 +211,7 @@ struct svc_i3c_master { + spinlock_t lock; + } ibi; + struct mutex lock; ++ int enabled_events; + }; + + /** +@@ -221,6 +226,11 @@ struct svc_i3c_i2c_dev_data { + struct i3c_generic_ibi_pool *ibi_pool; + }; + ++static inline bool is_events_enabled(struct svc_i3c_master *master, u32 mask) ++{ ++ return !!(master->enabled_events & mask); ++} ++ + static bool svc_i3c_master_error(struct svc_i3c_master *master) + { + u32 mstatus, merrwarn; +@@ -440,13 +450,16 @@ static void svc_i3c_master_ibi_work(struct work_struct *work) + switch (ibitype) { + case SVC_I3C_MSTATUS_IBITYPE_IBI: + dev = svc_i3c_master_dev_from_addr(master, ibiaddr); +- if (!dev) ++ if (!dev || !is_events_enabled(master, SVC_I3C_EVENT_IBI)) + svc_i3c_master_nack_ibi(master); + else + svc_i3c_master_handle_ibi(master, dev); + break; + case SVC_I3C_MSTATUS_IBITYPE_HOT_JOIN: +- svc_i3c_master_ack_ibi(master, false); ++ if (is_events_enabled(master, SVC_I3C_EVENT_HOTJOIN)) ++ svc_i3c_master_ack_ibi(master, false); ++ else ++ svc_i3c_master_nack_ibi(master); + break; + case SVC_I3C_MSTATUS_IBITYPE_MASTER_REQUEST: + svc_i3c_master_nack_ibi(master); +@@ -483,7 +496,9 @@ static void svc_i3c_master_ibi_work(struct work_struct *work) + svc_i3c_master_emit_stop(master); + break; + case SVC_I3C_MSTATUS_IBITYPE_HOT_JOIN: +- queue_work(master->base.wq, &master->hj_work); ++ svc_i3c_master_emit_stop(master); ++ if (is_events_enabled(master, SVC_I3C_EVENT_HOTJOIN)) ++ queue_work(master->base.wq, &master->hj_work); + break; + case SVC_I3C_MSTATUS_IBITYPE_MASTER_REQUEST: + default: +@@ -1520,6 +1535,7 @@ static int svc_i3c_master_enable_ibi(struct i3c_dev_desc *dev) + return ret; + } + ++ master->enabled_events |= SVC_I3C_EVENT_IBI; + svc_i3c_master_enable_interrupts(master, SVC_I3C_MINT_SLVSTART); + + return i3c_master_enec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR); +@@ -1531,7 +1547,9 @@ static int svc_i3c_master_disable_ibi(struct i3c_dev_desc *dev) + struct svc_i3c_master *master = to_svc_i3c_master(m); + int ret; + +- svc_i3c_master_disable_interrupts(master); ++ master->enabled_events &= ~SVC_I3C_EVENT_IBI; ++ if (!master->enabled_events) ++ svc_i3c_master_disable_interrupts(master); + + ret = i3c_master_disec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR); + +@@ -1541,6 +1559,39 @@ static int svc_i3c_master_disable_ibi(struct i3c_dev_desc *dev) + return ret; + } + ++static int svc_i3c_master_enable_hotjoin(struct i3c_master_controller *m) ++{ ++ struct svc_i3c_master *master = to_svc_i3c_master(m); ++ int ret; ++ ++ ret = pm_runtime_resume_and_get(master->dev); ++ if (ret < 0) { ++ dev_err(master->dev, "<%s> Cannot get runtime PM.\n", __func__); ++ return ret; ++ } ++ ++ master->enabled_events |= SVC_I3C_EVENT_HOTJOIN; ++ ++ svc_i3c_master_enable_interrupts(master, SVC_I3C_MINT_SLVSTART); ++ ++ return 0; ++} ++ ++static int svc_i3c_master_disable_hotjoin(struct i3c_master_controller *m) ++{ ++ struct svc_i3c_master *master = to_svc_i3c_master(m); ++ ++ master->enabled_events &= ~SVC_I3C_EVENT_HOTJOIN; ++ ++ if (!master->enabled_events) ++ svc_i3c_master_disable_interrupts(master); ++ ++ pm_runtime_mark_last_busy(master->dev); ++ pm_runtime_put_autosuspend(master->dev); ++ ++ return 0; ++} ++ + static void svc_i3c_master_recycle_ibi_slot(struct i3c_dev_desc *dev, + struct i3c_ibi_slot *slot) + { +@@ -1567,6 +1618,8 @@ static const struct i3c_master_controller_ops svc_i3c_master_ops = { + .recycle_ibi_slot = svc_i3c_master_recycle_ibi_slot, + .enable_ibi = svc_i3c_master_enable_ibi, + .disable_ibi = svc_i3c_master_disable_ibi, ++ .enable_hotjoin = svc_i3c_master_enable_hotjoin, ++ .disable_hotjoin = svc_i3c_master_disable_hotjoin, + }; + + static int svc_i3c_master_prepare_clks(struct svc_i3c_master *master) +-- +2.43.0 + diff --git a/queue-6.6/i3c-master-svc-modify-enabled_events-bit-7-0-to-act-.patch b/queue-6.6/i3c-master-svc-modify-enabled_events-bit-7-0-to-act-.patch new file mode 100644 index 00000000000..c4de59d0983 --- /dev/null +++ b/queue-6.6/i3c-master-svc-modify-enabled_events-bit-7-0-to-act-.patch @@ -0,0 +1,71 @@ +From d8047b227b244170788bf808b11850c550b2687c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 1 Nov 2024 12:50:02 -0400 +Subject: i3c: master: svc: Modify enabled_events bit 7:0 to act as IBI enable + counter + +From: Frank Li + +[ Upstream commit 25bc99be5fe53853053ceeaa328068c49dc1e799 ] + +Fix issue where disabling IBI on one device disables the entire IBI +interrupt. Modify bit 7:0 of enabled_events to serve as an IBI enable +counter, ensuring that the system IBI interrupt is disabled only when all +I3C devices have IBI disabled. + +Cc: stable@kernel.org +Fixes: 7ff730ca458e ("i3c: master: svc: enable the interrupt in the enable ibi function") +Reviewed-by: Miquel Raynal +Signed-off-by: Frank Li +Link: https://lore.kernel.org/r/20241101165002.2479794-1-Frank.Li@nxp.com +Signed-off-by: Alexandre Belloni +Signed-off-by: Sasha Levin +--- + drivers/i3c/master/svc-i3c-master.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c +index 97d03d755a61f..77bc0db17fc6f 100644 +--- a/drivers/i3c/master/svc-i3c-master.c ++++ b/drivers/i3c/master/svc-i3c-master.c +@@ -128,8 +128,8 @@ + /* This parameter depends on the implementation and may be tuned */ + #define SVC_I3C_FIFO_SIZE 16 + +-#define SVC_I3C_EVENT_IBI BIT(0) +-#define SVC_I3C_EVENT_HOTJOIN BIT(1) ++#define SVC_I3C_EVENT_IBI GENMASK(7, 0) ++#define SVC_I3C_EVENT_HOTJOIN BIT(31) + + struct svc_i3c_cmd { + u8 addr; +@@ -212,7 +212,7 @@ struct svc_i3c_master { + spinlock_t lock; + } ibi; + struct mutex lock; +- int enabled_events; ++ u32 enabled_events; + u32 mctrl_config; + }; + +@@ -1586,7 +1586,7 @@ static int svc_i3c_master_enable_ibi(struct i3c_dev_desc *dev) + return ret; + } + +- master->enabled_events |= SVC_I3C_EVENT_IBI; ++ master->enabled_events++; + svc_i3c_master_enable_interrupts(master, SVC_I3C_MINT_SLVSTART); + + return i3c_master_enec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR); +@@ -1598,7 +1598,7 @@ static int svc_i3c_master_disable_ibi(struct i3c_dev_desc *dev) + struct svc_i3c_master *master = to_svc_i3c_master(m); + int ret; + +- master->enabled_events &= ~SVC_I3C_EVENT_IBI; ++ master->enabled_events--; + if (!master->enabled_events) + svc_i3c_master_disable_interrupts(master); + +-- +2.43.0 + diff --git a/queue-6.6/i3c-master-svc-use-slow-speed-for-first-broadcast-ad.patch b/queue-6.6/i3c-master-svc-use-slow-speed-for-first-broadcast-ad.patch new file mode 100644 index 00000000000..636145e35f0 --- /dev/null +++ b/queue-6.6/i3c-master-svc-use-slow-speed-for-first-broadcast-ad.patch @@ -0,0 +1,117 @@ +From 437724003fdaf6d9b0bf16895fc182f178249b67 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Sep 2024 13:16:26 +0800 +Subject: i3c: master: svc: use slow speed for first broadcast address + +From: Carlos Song + +[ Upstream commit 20ade67bb1645f5ce8f37fa79ddfebbc5b5b24ef ] + +I3C controller should support adjusting open drain timing for the first +broadcast address to make I3C device working as a i2c device can see slow +broadcast address to close its Spike Filter to change working at i3c mode. + +Signed-off-by: Carlos Song +Reviewed-by: Frank Li +Link: https://lore.kernel.org/r/20240910051626.4052552-2-carlos.song@nxp.com +Signed-off-by: Alexandre Belloni +Stable-dep-of: 25bc99be5fe5 ("i3c: master: svc: Modify enabled_events bit 7:0 to act as IBI enable counter") +Signed-off-by: Sasha Levin +--- + drivers/i3c/master/svc-i3c-master.c | 52 +++++++++++++++++++++++++++++ + 1 file changed, 52 insertions(+) + +diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c +index 139b51a575366..97d03d755a61f 100644 +--- a/drivers/i3c/master/svc-i3c-master.c ++++ b/drivers/i3c/master/svc-i3c-master.c +@@ -182,6 +182,7 @@ struct svc_i3c_regs_save { + * @ibi.lock: IBI lock + * @lock: Transfer lock, protect between IBI work thread and callbacks from master + * @enabled_events: Bit masks for enable events (IBI, HotJoin). ++ * @mctrl_config: Configuration value in SVC_I3C_MCTRL for setting speed back. + */ + struct svc_i3c_master { + struct i3c_master_controller base; +@@ -212,6 +213,7 @@ struct svc_i3c_master { + } ibi; + struct mutex lock; + int enabled_events; ++ u32 mctrl_config; + }; + + /** +@@ -529,6 +531,54 @@ static irqreturn_t svc_i3c_master_irq_handler(int irq, void *dev_id) + return IRQ_HANDLED; + } + ++static int svc_i3c_master_set_speed(struct i3c_master_controller *m, ++ enum i3c_open_drain_speed speed) ++{ ++ struct svc_i3c_master *master = to_svc_i3c_master(m); ++ struct i3c_bus *bus = i3c_master_get_bus(&master->base); ++ u32 ppbaud, odbaud, odhpp, mconfig; ++ unsigned long fclk_rate; ++ int ret; ++ ++ ret = pm_runtime_resume_and_get(master->dev); ++ if (ret < 0) { ++ dev_err(master->dev, "<%s> Cannot get runtime PM.\n", __func__); ++ return ret; ++ } ++ ++ switch (speed) { ++ case I3C_OPEN_DRAIN_SLOW_SPEED: ++ fclk_rate = clk_get_rate(master->fclk); ++ if (!fclk_rate) { ++ ret = -EINVAL; ++ goto rpm_out; ++ } ++ /* ++ * Set 50% duty-cycle I2C speed to I3C OPEN-DRAIN mode, so the first ++ * broadcast address is visible to all I2C/I3C devices on the I3C bus. ++ * I3C device working as a I2C device will turn off its 50ns Spike ++ * Filter to change to I3C mode. ++ */ ++ mconfig = master->mctrl_config; ++ ppbaud = FIELD_GET(GENMASK(11, 8), mconfig); ++ odhpp = 0; ++ odbaud = DIV_ROUND_UP(fclk_rate, bus->scl_rate.i2c * (2 + 2 * ppbaud)) - 1; ++ mconfig &= ~GENMASK(24, 16); ++ mconfig |= SVC_I3C_MCONFIG_ODBAUD(odbaud) | SVC_I3C_MCONFIG_ODHPP(odhpp); ++ writel(mconfig, master->regs + SVC_I3C_MCONFIG); ++ break; ++ case I3C_OPEN_DRAIN_NORMAL_SPEED: ++ writel(master->mctrl_config, master->regs + SVC_I3C_MCONFIG); ++ break; ++ } ++ ++rpm_out: ++ pm_runtime_mark_last_busy(master->dev); ++ pm_runtime_put_autosuspend(master->dev); ++ ++ return ret; ++} ++ + static int svc_i3c_master_bus_init(struct i3c_master_controller *m) + { + struct svc_i3c_master *master = to_svc_i3c_master(m); +@@ -611,6 +661,7 @@ static int svc_i3c_master_bus_init(struct i3c_master_controller *m) + SVC_I3C_MCONFIG_I2CBAUD(i2cbaud); + writel(reg, master->regs + SVC_I3C_MCONFIG); + ++ master->mctrl_config = reg; + /* Master core's registration */ + ret = i3c_master_get_free_addr(m, 0); + if (ret < 0) +@@ -1620,6 +1671,7 @@ static const struct i3c_master_controller_ops svc_i3c_master_ops = { + .disable_ibi = svc_i3c_master_disable_ibi, + .enable_hotjoin = svc_i3c_master_enable_hotjoin, + .disable_hotjoin = svc_i3c_master_disable_hotjoin, ++ .set_speed = svc_i3c_master_set_speed, + }; + + static int svc_i3c_master_prepare_clks(struct svc_i3c_master *master) +-- +2.43.0 + diff --git a/queue-6.6/igb-fix-potential-invalid-memory-access-in-igb_init_.patch b/queue-6.6/igb-fix-potential-invalid-memory-access-in-igb_init_.patch new file mode 100644 index 00000000000..5ae7ed62791 --- /dev/null +++ b/queue-6.6/igb-fix-potential-invalid-memory-access-in-igb_init_.patch @@ -0,0 +1,40 @@ +From 2e196081539e223a9d4f88fedb176bb00a1a1d31 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 23 Oct 2024 20:10:48 +0800 +Subject: igb: Fix potential invalid memory access in igb_init_module() + +From: Yuan Can + +[ Upstream commit 0566f83d206c7a864abcd741fe39d6e0ae5eef29 ] + +The pci_register_driver() can fail and when this happened, the dca_notifier +needs to be unregistered, otherwise the dca_notifier can be called when +igb fails to install, resulting to invalid memory access. + +Fixes: bbd98fe48a43 ("igb: Fix DCA errors and do not use context index for 82576") +Signed-off-by: Yuan Can +Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) +Signed-off-by: Tony Nguyen +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/igb/igb_main.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c +index 49b349fa22542..c38be2880efcf 100644 +--- a/drivers/net/ethernet/intel/igb/igb_main.c ++++ b/drivers/net/ethernet/intel/igb/igb_main.c +@@ -665,6 +665,10 @@ static int __init igb_init_module(void) + dca_register_notify(&dca_notifier); + #endif + ret = pci_register_driver(&igb_driver); ++#ifdef CONFIG_IGB_DCA ++ if (ret) ++ dca_unregister_notify(&dca_notifier); ++#endif + return ret; + } + +-- +2.43.0 + diff --git a/queue-6.6/iommu-add-iommu_ops-identity_domain.patch b/queue-6.6/iommu-add-iommu_ops-identity_domain.patch new file mode 100644 index 00000000000..a3a314747db --- /dev/null +++ b/queue-6.6/iommu-add-iommu_ops-identity_domain.patch @@ -0,0 +1,147 @@ +From b0a7b2647cf144cc009330beba9e75dbc2249a91 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 Sep 2023 10:43:34 -0300 +Subject: iommu: Add iommu_ops->identity_domain + +From: Jason Gunthorpe + +[ Upstream commit df31b298477e65a01deff0af352be3a61524d930 ] + +This allows a driver to set a global static to an IDENTITY domain and +the core code will automatically use it whenever an IDENTITY domain +is requested. + +By making it always available it means the IDENTITY can be used in error +handling paths to force the iommu driver into a known state. Devices +implementing global static identity domains should avoid failing their +attach_dev ops. + +To make global static domains simpler allow drivers to omit their free +function and update the iommufd selftest. + +Convert rockchip to use the new mechanism. + +Tested-by: Steven Price +Tested-by: Marek Szyprowski +Tested-by: Nicolin Chen +Reviewed-by: Lu Baolu +Reviewed-by: Jerry Snitselaar +Signed-off-by: Jason Gunthorpe +Link: https://lore.kernel.org/r/1-v8-81230027b2fa+9d-iommu_all_defdom_jgg@nvidia.com +Signed-off-by: Joerg Roedel +Stable-dep-of: 229e6ee43d2a ("iommu/arm-smmu: Defer probe of clients after smmu device bound") +Signed-off-by: Sasha Levin +--- + drivers/iommu/iommu.c | 6 +++++- + drivers/iommu/iommufd/selftest.c | 5 ----- + drivers/iommu/rockchip-iommu.c | 9 +-------- + include/linux/iommu.h | 3 +++ + 4 files changed, 9 insertions(+), 14 deletions(-) + +diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c +index 3f1029c0825e9..e97299987d43f 100644 +--- a/drivers/iommu/iommu.c ++++ b/drivers/iommu/iommu.c +@@ -1979,6 +1979,9 @@ static struct iommu_domain *__iommu_domain_alloc(const struct bus_type *bus, + if (bus == NULL || bus->iommu_ops == NULL) + return NULL; + ++ if (alloc_type == IOMMU_DOMAIN_IDENTITY && bus->iommu_ops->identity_domain) ++ return bus->iommu_ops->identity_domain; ++ + domain = bus->iommu_ops->domain_alloc(alloc_type); + if (!domain) + return NULL; +@@ -2012,7 +2015,8 @@ void iommu_domain_free(struct iommu_domain *domain) + if (domain->type == IOMMU_DOMAIN_SVA) + mmdrop(domain->mm); + iommu_put_dma_cookie(domain); +- domain->ops->free(domain); ++ if (domain->ops->free) ++ domain->ops->free(domain); + } + EXPORT_SYMBOL_GPL(iommu_domain_free); + +diff --git a/drivers/iommu/iommufd/selftest.c b/drivers/iommu/iommufd/selftest.c +index 00b794d74e03b..d29e438377405 100644 +--- a/drivers/iommu/iommufd/selftest.c ++++ b/drivers/iommu/iommufd/selftest.c +@@ -126,10 +126,6 @@ struct selftest_obj { + }; + }; + +-static void mock_domain_blocking_free(struct iommu_domain *domain) +-{ +-} +- + static int mock_domain_nop_attach(struct iommu_domain *domain, + struct device *dev) + { +@@ -137,7 +133,6 @@ static int mock_domain_nop_attach(struct iommu_domain *domain, + } + + static const struct iommu_domain_ops mock_blocking_ops = { +- .free = mock_domain_blocking_free, + .attach_dev = mock_domain_nop_attach, + }; + +diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c +index 8ff69fbf9f65d..033678f2f8b3a 100644 +--- a/drivers/iommu/rockchip-iommu.c ++++ b/drivers/iommu/rockchip-iommu.c +@@ -989,13 +989,8 @@ static int rk_iommu_identity_attach(struct iommu_domain *identity_domain, + return 0; + } + +-static void rk_iommu_identity_free(struct iommu_domain *domain) +-{ +-} +- + static struct iommu_domain_ops rk_identity_ops = { + .attach_dev = rk_iommu_identity_attach, +- .free = rk_iommu_identity_free, + }; + + static struct iommu_domain rk_identity_domain = { +@@ -1059,9 +1054,6 @@ static struct iommu_domain *rk_iommu_domain_alloc(unsigned type) + { + struct rk_iommu_domain *rk_domain; + +- if (type == IOMMU_DOMAIN_IDENTITY) +- return &rk_identity_domain; +- + if (type != IOMMU_DOMAIN_UNMANAGED && type != IOMMU_DOMAIN_DMA) + return NULL; + +@@ -1186,6 +1178,7 @@ static int rk_iommu_of_xlate(struct device *dev, + } + + static const struct iommu_ops rk_iommu_ops = { ++ .identity_domain = &rk_identity_domain, + .domain_alloc = rk_iommu_domain_alloc, + .probe_device = rk_iommu_probe_device, + .release_device = rk_iommu_release_device, +diff --git a/include/linux/iommu.h b/include/linux/iommu.h +index b6ef263e85c06..0274d12a48e1b 100644 +--- a/include/linux/iommu.h ++++ b/include/linux/iommu.h +@@ -260,6 +260,8 @@ struct iommu_iotlb_gather { + * will be blocked by the hardware. + * @pgsize_bitmap: bitmap of all possible supported page sizes + * @owner: Driver module providing these ops ++ * @identity_domain: An always available, always attachable identity ++ * translation. + */ + struct iommu_ops { + bool (*capable)(struct device *dev, enum iommu_cap); +@@ -294,6 +296,7 @@ struct iommu_ops { + const struct iommu_domain_ops *default_domain_ops; + unsigned long pgsize_bitmap; + struct module *owner; ++ struct iommu_domain *identity_domain; + }; + + /** +-- +2.43.0 + diff --git a/queue-6.6/iommu-arm-smmu-defer-probe-of-clients-after-smmu-dev.patch b/queue-6.6/iommu-arm-smmu-defer-probe-of-clients-after-smmu-dev.patch new file mode 100644 index 00000000000..03116ae48b2 --- /dev/null +++ b/queue-6.6/iommu-arm-smmu-defer-probe-of-clients-after-smmu-dev.patch @@ -0,0 +1,86 @@ +From 62dc845a353efab2254480df8ae7d06175627313 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 4 Oct 2024 14:34:28 +0530 +Subject: iommu/arm-smmu: Defer probe of clients after smmu device bound + +From: Pratyush Brahma + +[ Upstream commit 229e6ee43d2a160a1592b83aad620d6027084aad ] + +Null pointer dereference occurs due to a race between smmu +driver probe and client driver probe, when of_dma_configure() +for client is called after the iommu_device_register() for smmu driver +probe has executed but before the driver_bound() for smmu driver +has been called. + +Following is how the race occurs: + +T1:Smmu device probe T2: Client device probe + +really_probe() +arm_smmu_device_probe() +iommu_device_register() + really_probe() + platform_dma_configure() + of_dma_configure() + of_dma_configure_id() + of_iommu_configure() + iommu_probe_device() + iommu_init_device() + arm_smmu_probe_device() + arm_smmu_get_by_fwnode() + driver_find_device_by_fwnode() + driver_find_device() + next_device() + klist_next() + /* null ptr + assigned to smmu */ + /* null ptr dereference + while smmu->streamid_mask */ +driver_bound() + klist_add_tail() + +When this null smmu pointer is dereferenced later in +arm_smmu_probe_device, the device crashes. + +Fix this by deferring the probe of the client device +until the smmu device has bound to the arm smmu driver. + +Fixes: 021bb8420d44 ("iommu/arm-smmu: Wire up generic configuration support") +Cc: stable@vger.kernel.org +Co-developed-by: Prakash Gupta +Signed-off-by: Prakash Gupta +Signed-off-by: Pratyush Brahma +Link: https://lore.kernel.org/r/20241004090428.2035-1-quic_pbrahma@quicinc.com +[will: Add comment] +Signed-off-by: Will Deacon +Signed-off-by: Sasha Levin +--- + drivers/iommu/arm/arm-smmu/arm-smmu.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c b/drivers/iommu/arm/arm-smmu/arm-smmu.c +index 8203a06014d71..b40ffa1ec2db6 100644 +--- a/drivers/iommu/arm/arm-smmu/arm-smmu.c ++++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c +@@ -1354,6 +1354,17 @@ static struct iommu_device *arm_smmu_probe_device(struct device *dev) + goto out_free; + } else { + smmu = arm_smmu_get_by_fwnode(fwspec->iommu_fwnode); ++ ++ /* ++ * Defer probe if the relevant SMMU instance hasn't finished ++ * probing yet. This is a fragile hack and we'd ideally ++ * avoid this race in the core code. Until that's ironed ++ * out, however, this is the most pragmatic option on the ++ * table. ++ */ ++ if (!smmu) ++ return ERR_PTR(dev_err_probe(dev, -EPROBE_DEFER, ++ "smmu dev has not bound yet\n")); + } + + ret = -EINVAL; +-- +2.43.0 + diff --git a/queue-6.6/iommu-clean-up-open-coded-ownership-checks.patch b/queue-6.6/iommu-clean-up-open-coded-ownership-checks.patch new file mode 100644 index 00000000000..1903d6e823c --- /dev/null +++ b/queue-6.6/iommu-clean-up-open-coded-ownership-checks.patch @@ -0,0 +1,194 @@ +From 302639dd441533017096f8ebccb02440090fb09d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Nov 2023 18:04:03 +0000 +Subject: iommu: Clean up open-coded ownership checks + +From: Robin Murphy + +[ Upstream commit e7080665c977ea1aafb8547a9c7bd08b199311d6 ] + +Some drivers already implement their own defence against the possibility +of being given someone else's device. Since this is now taken care of by +the core code (and via a slightly different path from the original +fwspec-based idea), let's clean them up. + +Acked-by: Will Deacon +Reviewed-by: Jason Gunthorpe +Reviewed-by: Jerry Snitselaar +Signed-off-by: Robin Murphy +Link: https://lore.kernel.org/r/58a9879ce3f03562bb061e6714fe6efb554c3907.1700589539.git.robin.murphy@arm.com +Signed-off-by: Joerg Roedel +Stable-dep-of: 229e6ee43d2a ("iommu/arm-smmu: Defer probe of clients after smmu device bound") +Signed-off-by: Sasha Levin +--- + drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 3 --- + drivers/iommu/arm/arm-smmu/arm-smmu.c | 9 +-------- + drivers/iommu/arm/arm-smmu/qcom_iommu.c | 16 +++------------- + drivers/iommu/mtk_iommu.c | 7 +------ + drivers/iommu/mtk_iommu_v1.c | 3 --- + drivers/iommu/sprd-iommu.c | 8 +------- + drivers/iommu/virtio-iommu.c | 3 --- + 7 files changed, 6 insertions(+), 43 deletions(-) + +diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +index 68b81f9c2f4b1..c24584754d252 100644 +--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c ++++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +@@ -2658,9 +2658,6 @@ static struct iommu_device *arm_smmu_probe_device(struct device *dev) + struct arm_smmu_master *master; + struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev); + +- if (!fwspec || fwspec->ops != &arm_smmu_ops) +- return ERR_PTR(-ENODEV); +- + if (WARN_ON_ONCE(dev_iommu_priv_get(dev))) + return ERR_PTR(-EBUSY); + +diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c b/drivers/iommu/arm/arm-smmu/arm-smmu.c +index d6d1a2a55cc06..8203a06014d71 100644 +--- a/drivers/iommu/arm/arm-smmu/arm-smmu.c ++++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c +@@ -1116,11 +1116,6 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) + struct arm_smmu_device *smmu; + int ret; + +- if (!fwspec || fwspec->ops != &arm_smmu_ops) { +- dev_err(dev, "cannot attach to SMMU, is it on the same bus?\n"); +- return -ENXIO; +- } +- + /* + * FIXME: The arch/arm DMA API code tries to attach devices to its own + * domains between of_xlate() and probe_device() - we have no way to cope +@@ -1357,10 +1352,8 @@ static struct iommu_device *arm_smmu_probe_device(struct device *dev) + fwspec = dev_iommu_fwspec_get(dev); + if (ret) + goto out_free; +- } else if (fwspec && fwspec->ops == &arm_smmu_ops) { +- smmu = arm_smmu_get_by_fwnode(fwspec->iommu_fwnode); + } else { +- return ERR_PTR(-ENODEV); ++ smmu = arm_smmu_get_by_fwnode(fwspec->iommu_fwnode); + } + + ret = -EINVAL; +diff --git a/drivers/iommu/arm/arm-smmu/qcom_iommu.c b/drivers/iommu/arm/arm-smmu/qcom_iommu.c +index bc45d18f350cb..3b8c4b33842d1 100644 +--- a/drivers/iommu/arm/arm-smmu/qcom_iommu.c ++++ b/drivers/iommu/arm/arm-smmu/qcom_iommu.c +@@ -79,16 +79,6 @@ static struct qcom_iommu_domain *to_qcom_iommu_domain(struct iommu_domain *dom) + + static const struct iommu_ops qcom_iommu_ops; + +-static struct qcom_iommu_dev * to_iommu(struct device *dev) +-{ +- struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev); +- +- if (!fwspec || fwspec->ops != &qcom_iommu_ops) +- return NULL; +- +- return dev_iommu_priv_get(dev); +-} +- + static struct qcom_iommu_ctx * to_ctx(struct qcom_iommu_domain *d, unsigned asid) + { + struct qcom_iommu_dev *qcom_iommu = d->iommu; +@@ -374,7 +364,7 @@ static void qcom_iommu_domain_free(struct iommu_domain *domain) + + static int qcom_iommu_attach_dev(struct iommu_domain *domain, struct device *dev) + { +- struct qcom_iommu_dev *qcom_iommu = to_iommu(dev); ++ struct qcom_iommu_dev *qcom_iommu = dev_iommu_priv_get(dev); + struct qcom_iommu_domain *qcom_domain = to_qcom_iommu_domain(domain); + int ret; + +@@ -406,7 +396,7 @@ static int qcom_iommu_identity_attach(struct iommu_domain *identity_domain, + struct iommu_domain *domain = iommu_get_domain_for_dev(dev); + struct qcom_iommu_domain *qcom_domain; + struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev); +- struct qcom_iommu_dev *qcom_iommu = to_iommu(dev); ++ struct qcom_iommu_dev *qcom_iommu = dev_iommu_priv_get(dev); + unsigned int i; + + if (domain == identity_domain || !domain) +@@ -537,7 +527,7 @@ static bool qcom_iommu_capable(struct device *dev, enum iommu_cap cap) + + static struct iommu_device *qcom_iommu_probe_device(struct device *dev) + { +- struct qcom_iommu_dev *qcom_iommu = to_iommu(dev); ++ struct qcom_iommu_dev *qcom_iommu = dev_iommu_priv_get(dev); + struct device_link *link; + + if (!qcom_iommu) +diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c +index de698463e94ad..23c7eec46fff6 100644 +--- a/drivers/iommu/mtk_iommu.c ++++ b/drivers/iommu/mtk_iommu.c +@@ -843,16 +843,11 @@ static phys_addr_t mtk_iommu_iova_to_phys(struct iommu_domain *domain, + static struct iommu_device *mtk_iommu_probe_device(struct device *dev) + { + struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev); +- struct mtk_iommu_data *data; ++ struct mtk_iommu_data *data = dev_iommu_priv_get(dev); + struct device_link *link; + struct device *larbdev; + unsigned int larbid, larbidx, i; + +- if (!fwspec || fwspec->ops != &mtk_iommu_ops) +- return ERR_PTR(-ENODEV); /* Not a iommu client device */ +- +- data = dev_iommu_priv_get(dev); +- + if (!MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_MM)) + return &data->iommu; + +diff --git a/drivers/iommu/mtk_iommu_v1.c b/drivers/iommu/mtk_iommu_v1.c +index f1754efcfe74e..027b2ff7f33ef 100644 +--- a/drivers/iommu/mtk_iommu_v1.c ++++ b/drivers/iommu/mtk_iommu_v1.c +@@ -478,9 +478,6 @@ static struct iommu_device *mtk_iommu_v1_probe_device(struct device *dev) + idx++; + } + +- if (!fwspec || fwspec->ops != &mtk_iommu_v1_ops) +- return ERR_PTR(-ENODEV); /* Not a iommu client device */ +- + data = dev_iommu_priv_get(dev); + + /* Link the consumer device with the smi-larb device(supplier) */ +diff --git a/drivers/iommu/sprd-iommu.c b/drivers/iommu/sprd-iommu.c +index c8e79a2d8b4c6..b5570ef887023 100644 +--- a/drivers/iommu/sprd-iommu.c ++++ b/drivers/iommu/sprd-iommu.c +@@ -388,13 +388,7 @@ static phys_addr_t sprd_iommu_iova_to_phys(struct iommu_domain *domain, + + static struct iommu_device *sprd_iommu_probe_device(struct device *dev) + { +- struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev); +- struct sprd_iommu_device *sdev; +- +- if (!fwspec || fwspec->ops != &sprd_iommu_ops) +- return ERR_PTR(-ENODEV); +- +- sdev = dev_iommu_priv_get(dev); ++ struct sprd_iommu_device *sdev = dev_iommu_priv_get(dev); + + return &sdev->iommu; + } +diff --git a/drivers/iommu/virtio-iommu.c b/drivers/iommu/virtio-iommu.c +index 17dcd826f5c20..bb2e795a80d0f 100644 +--- a/drivers/iommu/virtio-iommu.c ++++ b/drivers/iommu/virtio-iommu.c +@@ -969,9 +969,6 @@ static struct iommu_device *viommu_probe_device(struct device *dev) + struct viommu_dev *viommu = NULL; + struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev); + +- if (!fwspec || fwspec->ops != &viommu_ops) +- return ERR_PTR(-ENODEV); +- + viommu = viommu_get_by_fwnode(fwspec->iommu_fwnode); + if (!viommu) + return ERR_PTR(-ENODEV); +-- +2.43.0 + diff --git a/queue-6.6/iommu-qcom_iommu-add-an-iommu_identitiy_domain.patch b/queue-6.6/iommu-qcom_iommu-add-an-iommu_identitiy_domain.patch new file mode 100644 index 00000000000..cd1b55633c4 --- /dev/null +++ b/queue-6.6/iommu-qcom_iommu-add-an-iommu_identitiy_domain.patch @@ -0,0 +1,84 @@ +From f13d79171ee3a3c2f8da7c45dd3d8f6fb25bbf81 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 Sep 2023 10:43:49 -0300 +Subject: iommu/qcom_iommu: Add an IOMMU_IDENTITIY_DOMAIN + +From: Jason Gunthorpe + +[ Upstream commit 786478a90294ea5b149ed1156a43e82d63ea61ff ] + +This brings back the ops->detach_dev() code that commit +1b932ceddd19 ("iommu: Remove detach_dev callbacks") deleted and turns it +into an IDENTITY domain. + +Reviewed-by: Lu Baolu +Reviewed-by: Jerry Snitselaar +Signed-off-by: Jason Gunthorpe +Link: https://lore.kernel.org/r/16-v8-81230027b2fa+9d-iommu_all_defdom_jgg@nvidia.com +Signed-off-by: Joerg Roedel +Stable-dep-of: 229e6ee43d2a ("iommu/arm-smmu: Defer probe of clients after smmu device bound") +Signed-off-by: Sasha Levin +--- + drivers/iommu/arm/arm-smmu/qcom_iommu.c | 39 +++++++++++++++++++++++++ + 1 file changed, 39 insertions(+) + +diff --git a/drivers/iommu/arm/arm-smmu/qcom_iommu.c b/drivers/iommu/arm/arm-smmu/qcom_iommu.c +index 775a3cbaff4ed..bc45d18f350cb 100644 +--- a/drivers/iommu/arm/arm-smmu/qcom_iommu.c ++++ b/drivers/iommu/arm/arm-smmu/qcom_iommu.c +@@ -400,6 +400,44 @@ static int qcom_iommu_attach_dev(struct iommu_domain *domain, struct device *dev + return 0; + } + ++static int qcom_iommu_identity_attach(struct iommu_domain *identity_domain, ++ struct device *dev) ++{ ++ struct iommu_domain *domain = iommu_get_domain_for_dev(dev); ++ struct qcom_iommu_domain *qcom_domain; ++ struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev); ++ struct qcom_iommu_dev *qcom_iommu = to_iommu(dev); ++ unsigned int i; ++ ++ if (domain == identity_domain || !domain) ++ return 0; ++ ++ qcom_domain = to_qcom_iommu_domain(domain); ++ if (WARN_ON(!qcom_domain->iommu)) ++ return -EINVAL; ++ ++ pm_runtime_get_sync(qcom_iommu->dev); ++ for (i = 0; i < fwspec->num_ids; i++) { ++ struct qcom_iommu_ctx *ctx = to_ctx(qcom_domain, fwspec->ids[i]); ++ ++ /* Disable the context bank: */ ++ iommu_writel(ctx, ARM_SMMU_CB_SCTLR, 0); ++ ++ ctx->domain = NULL; ++ } ++ pm_runtime_put_sync(qcom_iommu->dev); ++ return 0; ++} ++ ++static struct iommu_domain_ops qcom_iommu_identity_ops = { ++ .attach_dev = qcom_iommu_identity_attach, ++}; ++ ++static struct iommu_domain qcom_iommu_identity_domain = { ++ .type = IOMMU_DOMAIN_IDENTITY, ++ .ops = &qcom_iommu_identity_ops, ++}; ++ + static int qcom_iommu_map(struct iommu_domain *domain, unsigned long iova, + phys_addr_t paddr, size_t pgsize, size_t pgcount, + int prot, gfp_t gfp, size_t *mapped) +@@ -565,6 +603,7 @@ static int qcom_iommu_of_xlate(struct device *dev, struct of_phandle_args *args) + } + + static const struct iommu_ops qcom_iommu_ops = { ++ .identity_domain = &qcom_iommu_identity_domain, + .capable = qcom_iommu_capable, + .domain_alloc = qcom_iommu_domain_alloc, + .probe_device = qcom_iommu_probe_device, +-- +2.43.0 + diff --git a/queue-6.6/ipv6-introduce-dst_rt6_info-helper.patch b/queue-6.6/ipv6-introduce-dst_rt6_info-helper.patch new file mode 100644 index 00000000000..c99290e1344 --- /dev/null +++ b/queue-6.6/ipv6-introduce-dst_rt6_info-helper.patch @@ -0,0 +1,841 @@ +From 8b69e72dcc554a2fddf7d8ef33cad7057c1c922b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Apr 2024 15:19:52 +0000 +Subject: ipv6: introduce dst_rt6_info() helper + +From: Eric Dumazet + +[ Upstream commit e8dfd42c17faf183415323db1ef0c977be0d6489 ] + +Instead of (struct rt6_info *)dst casts, we can use : + + #define dst_rt6_info(_ptr) \ + container_of_const(_ptr, struct rt6_info, dst) + +Some places needed missing const qualifiers : + +ip6_confirm_neigh(), ipv6_anycast_destination(), +ipv6_unicast_destination(), has_gateway() + +v2: added missing parts (David Ahern) + +Signed-off-by: Eric Dumazet +Reviewed-by: David Ahern +Signed-off-by: David S. Miller +Stable-dep-of: 3301ab7d5aeb ("net/ipv6: release expired exception dst cached in socket") +Signed-off-by: Sasha Levin +--- + drivers/infiniband/core/addr.c | 6 ++-- + .../ethernet/mellanox/mlxsw/spectrum_span.c | 2 +- + drivers/net/vrf.c | 2 +- + drivers/net/vxlan/vxlan_core.c | 2 +- + drivers/s390/net/qeth_core.h | 4 +-- + include/net/ip6_fib.h | 6 ++-- + include/net/ip6_route.h | 11 ++++---- + net/bluetooth/6lowpan.c | 2 +- + net/core/dst_cache.c | 2 +- + net/core/filter.c | 2 +- + net/ipv4/ip_tunnel.c | 2 +- + net/ipv6/icmp.c | 8 +++--- + net/ipv6/ila/ila_lwt.c | 4 +-- + net/ipv6/ip6_output.c | 18 ++++++------ + net/ipv6/ip6mr.c | 2 +- + net/ipv6/ndisc.c | 2 +- + net/ipv6/ping.c | 2 +- + net/ipv6/raw.c | 4 +-- + net/ipv6/route.c | 28 +++++++++---------- + net/ipv6/tcp_ipv6.c | 4 +-- + net/ipv6/udp.c | 11 +++----- + net/ipv6/xfrm6_policy.c | 2 +- + net/l2tp/l2tp_ip6.c | 2 +- + net/mpls/mpls_iptunnel.c | 2 +- + net/netfilter/ipvs/ip_vs_xmit.c | 14 +++++----- + net/netfilter/nf_flow_table_core.c | 8 ++---- + net/netfilter/nf_flow_table_ip.c | 4 +-- + net/netfilter/nft_rt.c | 2 +- + net/sctp/ipv6.c | 2 +- + net/xfrm/xfrm_policy.c | 3 +- + 30 files changed, 77 insertions(+), 86 deletions(-) + +diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c +index f253295795f0a..f20dfe70fa0e4 100644 +--- a/drivers/infiniband/core/addr.c ++++ b/drivers/infiniband/core/addr.c +@@ -348,15 +348,15 @@ static int dst_fetch_ha(const struct dst_entry *dst, + + static bool has_gateway(const struct dst_entry *dst, sa_family_t family) + { +- struct rtable *rt; +- struct rt6_info *rt6; ++ const struct rtable *rt; ++ const struct rt6_info *rt6; + + if (family == AF_INET) { + rt = container_of(dst, struct rtable, dst); + return rt->rt_uses_gateway; + } + +- rt6 = container_of(dst, struct rt6_info, dst); ++ rt6 = dst_rt6_info(dst); + return rt6->rt6i_flags & RTF_GATEWAY; + } + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c +index b3472fb946177..dcd198104141f 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c +@@ -539,7 +539,7 @@ mlxsw_sp_span_gretap6_route(const struct net_device *to_dev, + if (!dst || dst->error) + goto out; + +- rt6 = container_of(dst, struct rt6_info, dst); ++ rt6 = dst_rt6_info(dst); + + dev = dst->dev; + *saddrp = fl6.saddr; +diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c +index 27761a884dc62..5968a3ab81770 100644 +--- a/drivers/net/vrf.c ++++ b/drivers/net/vrf.c +@@ -655,7 +655,7 @@ static int vrf_finish_output6(struct net *net, struct sock *sk, + skb->dev = dev; + + rcu_read_lock(); +- nexthop = rt6_nexthop((struct rt6_info *)dst, &ipv6_hdr(skb)->daddr); ++ nexthop = rt6_nexthop(dst_rt6_info(dst), &ipv6_hdr(skb)->daddr); + neigh = __ipv6_neigh_lookup_noref(dst->dev, nexthop); + if (unlikely(!neigh)) + neigh = __neigh_create(&nd_tbl, nexthop, dst->dev, false); +diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c +index c114c91b558bd..ee02a92338da1 100644 +--- a/drivers/net/vxlan/vxlan_core.c ++++ b/drivers/net/vxlan/vxlan_core.c +@@ -2629,7 +2629,7 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, + } + + if (!info) { +- u32 rt6i_flags = ((struct rt6_info *)ndst)->rt6i_flags; ++ u32 rt6i_flags = dst_rt6_info(ndst)->rt6i_flags; + + err = encap_bypass_if_local(skb, dev, vxlan, dst, + dst_port, ifindex, vni, +diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h +index 613eab7297046..5f17a2a5d0e33 100644 +--- a/drivers/s390/net/qeth_core.h ++++ b/drivers/s390/net/qeth_core.h +@@ -956,7 +956,7 @@ static inline struct dst_entry *qeth_dst_check_rcu(struct sk_buff *skb, + struct dst_entry *dst = skb_dst(skb); + struct rt6_info *rt; + +- rt = (struct rt6_info *) dst; ++ rt = dst_rt6_info(dst); + if (dst) { + if (proto == htons(ETH_P_IPV6)) + dst = dst_check(dst, rt6_get_cookie(rt)); +@@ -978,7 +978,7 @@ static inline __be32 qeth_next_hop_v4_rcu(struct sk_buff *skb, + static inline struct in6_addr *qeth_next_hop_v6_rcu(struct sk_buff *skb, + struct dst_entry *dst) + { +- struct rt6_info *rt = (struct rt6_info *) dst; ++ struct rt6_info *rt = dst_rt6_info(dst); + + if (rt && !ipv6_addr_any(&rt->rt6i_gateway)) + return &rt->rt6i_gateway; +diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h +index 9ba6413fd2e3e..1121d614942c8 100644 +--- a/include/net/ip6_fib.h ++++ b/include/net/ip6_fib.h +@@ -237,9 +237,11 @@ struct fib6_result { + for (rt = (w)->leaf; rt; \ + rt = rcu_dereference_protected(rt->fib6_next, 1)) + +-static inline struct inet6_dev *ip6_dst_idev(struct dst_entry *dst) ++#define dst_rt6_info(_ptr) container_of_const(_ptr, struct rt6_info, dst) ++ ++static inline struct inet6_dev *ip6_dst_idev(const struct dst_entry *dst) + { +- return ((struct rt6_info *)dst)->rt6i_idev; ++ return dst_rt6_info(dst)->rt6i_idev; + } + + static inline bool fib6_requires_src(const struct fib6_info *rt) +diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h +index 61cfc8891f820..392232fcd703c 100644 +--- a/include/net/ip6_route.h ++++ b/include/net/ip6_route.h +@@ -218,12 +218,11 @@ void rt6_uncached_list_del(struct rt6_info *rt); + static inline const struct rt6_info *skb_rt6_info(const struct sk_buff *skb) + { + const struct dst_entry *dst = skb_dst(skb); +- const struct rt6_info *rt6 = NULL; + + if (dst) +- rt6 = container_of(dst, struct rt6_info, dst); ++ return dst_rt6_info(dst); + +- return rt6; ++ return NULL; + } + + /* +@@ -235,7 +234,7 @@ static inline void ip6_dst_store(struct sock *sk, struct dst_entry *dst, + { + struct ipv6_pinfo *np = inet6_sk(sk); + +- np->dst_cookie = rt6_get_cookie((struct rt6_info *)dst); ++ np->dst_cookie = rt6_get_cookie(dst_rt6_info(dst)); + sk_setup_caps(sk, dst); + np->daddr_cache = daddr; + #ifdef CONFIG_IPV6_SUBTREES +@@ -248,7 +247,7 @@ void ip6_sk_dst_store_flow(struct sock *sk, struct dst_entry *dst, + + static inline bool ipv6_unicast_destination(const struct sk_buff *skb) + { +- struct rt6_info *rt = (struct rt6_info *) skb_dst(skb); ++ const struct rt6_info *rt = dst_rt6_info(skb_dst(skb)); + + return rt->rt6i_flags & RTF_LOCAL; + } +@@ -256,7 +255,7 @@ static inline bool ipv6_unicast_destination(const struct sk_buff *skb) + static inline bool ipv6_anycast_destination(const struct dst_entry *dst, + const struct in6_addr *daddr) + { +- struct rt6_info *rt = (struct rt6_info *)dst; ++ const struct rt6_info *rt = dst_rt6_info(dst); + + return rt->rt6i_flags & RTF_ANYCAST || + (rt->rt6i_dst.plen < 127 && +diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c +index 4eb1b3ced0d27..3bcc15c9415fc 100644 +--- a/net/bluetooth/6lowpan.c ++++ b/net/bluetooth/6lowpan.c +@@ -133,7 +133,7 @@ static inline struct lowpan_peer *peer_lookup_dst(struct lowpan_btle_dev *dev, + struct in6_addr *daddr, + struct sk_buff *skb) + { +- struct rt6_info *rt = (struct rt6_info *)skb_dst(skb); ++ struct rt6_info *rt = dst_rt6_info(skb_dst(skb)); + int count = atomic_read(&dev->peer_count); + const struct in6_addr *nexthop; + struct lowpan_peer *peer; +diff --git a/net/core/dst_cache.c b/net/core/dst_cache.c +index 0ccfd5fa5cb9b..b17171345d649 100644 +--- a/net/core/dst_cache.c ++++ b/net/core/dst_cache.c +@@ -112,7 +112,7 @@ void dst_cache_set_ip6(struct dst_cache *dst_cache, struct dst_entry *dst, + + idst = this_cpu_ptr(dst_cache->cache); + dst_cache_per_cpu_dst_set(this_cpu_ptr(dst_cache->cache), dst, +- rt6_get_cookie((struct rt6_info *)dst)); ++ rt6_get_cookie(dst_rt6_info(dst))); + idst->in6_saddr = *saddr; + } + EXPORT_SYMBOL_GPL(dst_cache_set_ip6); +diff --git a/net/core/filter.c b/net/core/filter.c +index b64e7139eae19..bc52ab3374f3a 100644 +--- a/net/core/filter.c ++++ b/net/core/filter.c +@@ -2215,7 +2215,7 @@ static int bpf_out_neigh_v6(struct net *net, struct sk_buff *skb, + rcu_read_lock(); + if (!nh) { + dst = skb_dst(skb); +- nexthop = rt6_nexthop(container_of(dst, struct rt6_info, dst), ++ nexthop = rt6_nexthop(dst_rt6_info(dst), + &ipv6_hdr(skb)->daddr); + } else { + nexthop = &nh->ipv6_nh; +diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c +index acf93f34a8213..72b2d68ef4da5 100644 +--- a/net/ipv4/ip_tunnel.c ++++ b/net/ipv4/ip_tunnel.c +@@ -544,7 +544,7 @@ static int tnl_update_pmtu(struct net_device *dev, struct sk_buff *skb, + struct rt6_info *rt6; + __be32 daddr; + +- rt6 = skb_valid_dst(skb) ? (struct rt6_info *)skb_dst(skb) : ++ rt6 = skb_valid_dst(skb) ? dst_rt6_info(skb_dst(skb)) : + NULL; + daddr = md ? dst : tunnel->parms.iph.daddr; + +diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c +index a790294d31048..25a3a726fa117 100644 +--- a/net/ipv6/icmp.c ++++ b/net/ipv6/icmp.c +@@ -214,7 +214,7 @@ static bool icmpv6_xrlim_allow(struct sock *sk, u8 type, + } else if (dst->dev && (dst->dev->flags&IFF_LOOPBACK)) { + res = true; + } else { +- struct rt6_info *rt = (struct rt6_info *)dst; ++ struct rt6_info *rt = dst_rt6_info(dst); + int tmo = net->ipv6.sysctl.icmpv6_time; + struct inet_peer *peer; + +@@ -245,7 +245,7 @@ static bool icmpv6_rt_has_prefsrc(struct sock *sk, u8 type, + + dst = ip6_route_output(net, sk, fl6); + if (!dst->error) { +- struct rt6_info *rt = (struct rt6_info *)dst; ++ struct rt6_info *rt = dst_rt6_info(dst); + struct in6_addr prefsrc; + + rt6_get_prefsrc(rt, &prefsrc); +@@ -622,7 +622,7 @@ void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info, + if (ip6_append_data(sk, icmpv6_getfrag, &msg, + len + sizeof(struct icmp6hdr), + sizeof(struct icmp6hdr), +- &ipc6, &fl6, (struct rt6_info *)dst, ++ &ipc6, &fl6, dst_rt6_info(dst), + MSG_DONTWAIT)) { + ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTERRORS); + ip6_flush_pending_frames(sk); +@@ -811,7 +811,7 @@ static enum skb_drop_reason icmpv6_echo_reply(struct sk_buff *skb) + if (ip6_append_data(sk, icmpv6_getfrag, &msg, + skb->len + sizeof(struct icmp6hdr), + sizeof(struct icmp6hdr), &ipc6, &fl6, +- (struct rt6_info *)dst, MSG_DONTWAIT)) { ++ dst_rt6_info(dst), MSG_DONTWAIT)) { + __ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTERRORS); + ip6_flush_pending_frames(sk); + } else { +diff --git a/net/ipv6/ila/ila_lwt.c b/net/ipv6/ila/ila_lwt.c +index 9d37f7164e732..ff7e734e335b0 100644 +--- a/net/ipv6/ila/ila_lwt.c ++++ b/net/ipv6/ila/ila_lwt.c +@@ -38,7 +38,7 @@ static inline struct ila_params *ila_params_lwtunnel( + static int ila_output(struct net *net, struct sock *sk, struct sk_buff *skb) + { + struct dst_entry *orig_dst = skb_dst(skb); +- struct rt6_info *rt = (struct rt6_info *)orig_dst; ++ struct rt6_info *rt = dst_rt6_info(orig_dst); + struct ila_lwt *ilwt = ila_lwt_lwtunnel(orig_dst->lwtstate); + struct dst_entry *dst; + int err = -EINVAL; +@@ -72,7 +72,7 @@ static int ila_output(struct net *net, struct sock *sk, struct sk_buff *skb) + memset(&fl6, 0, sizeof(fl6)); + fl6.flowi6_oif = orig_dst->dev->ifindex; + fl6.flowi6_iif = LOOPBACK_IFINDEX; +- fl6.daddr = *rt6_nexthop((struct rt6_info *)orig_dst, ++ fl6.daddr = *rt6_nexthop(dst_rt6_info(orig_dst), + &ip6h->daddr); + + dst = ip6_route_output(net, NULL, &fl6); +diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c +index 65e2f19814358..2341a4373bb94 100644 +--- a/net/ipv6/ip6_output.c ++++ b/net/ipv6/ip6_output.c +@@ -124,7 +124,7 @@ static int ip6_finish_output2(struct net *net, struct sock *sk, struct sk_buff * + IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len); + + rcu_read_lock(); +- nexthop = rt6_nexthop((struct rt6_info *)dst, daddr); ++ nexthop = rt6_nexthop(dst_rt6_info(dst), daddr); + neigh = __ipv6_neigh_lookup_noref(dev, nexthop); + + if (unlikely(IS_ERR_OR_NULL(neigh))) { +@@ -606,7 +606,7 @@ int ip6_forward(struct sk_buff *skb) + * send a redirect. + */ + +- rt = (struct rt6_info *) dst; ++ rt = dst_rt6_info(dst); + if (rt->rt6i_flags & RTF_GATEWAY) + target = &rt->rt6i_gateway; + else +@@ -861,7 +861,7 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, + int (*output)(struct net *, struct sock *, struct sk_buff *)) + { + struct sk_buff *frag; +- struct rt6_info *rt = (struct rt6_info *)skb_dst(skb); ++ struct rt6_info *rt = dst_rt6_info(skb_dst(skb)); + struct ipv6_pinfo *np = skb->sk && !dev_recursion_level() ? + inet6_sk(skb->sk) : NULL; + bool mono_delivery_time = skb->mono_delivery_time; +@@ -1069,7 +1069,7 @@ static struct dst_entry *ip6_sk_dst_check(struct sock *sk, + return NULL; + } + +- rt = (struct rt6_info *)dst; ++ rt = dst_rt6_info(dst); + /* Yes, checking route validity in not connected + * case is not very simple. Take into account, + * that we do not support routing by source, TOS, +@@ -1124,7 +1124,7 @@ static int ip6_dst_lookup_tail(struct net *net, const struct sock *sk, + struct rt6_info *rt; + + *dst = ip6_route_output(net, sk, fl6); +- rt = (*dst)->error ? NULL : (struct rt6_info *)*dst; ++ rt = (*dst)->error ? NULL : dst_rt6_info(*dst); + + rcu_read_lock(); + from = rt ? rcu_dereference(rt->from) : NULL; +@@ -1166,7 +1166,7 @@ static int ip6_dst_lookup_tail(struct net *net, const struct sock *sk, + * dst entry and replace it instead with the + * dst entry of the nexthop router + */ +- rt = (struct rt6_info *) *dst; ++ rt = dst_rt6_info(*dst); + rcu_read_lock(); + n = __ipv6_neigh_lookup_noref(rt->dst.dev, + rt6_nexthop(rt, &fl6->daddr)); +@@ -1500,7 +1500,7 @@ static int __ip6_append_data(struct sock *sk, + int offset = 0; + bool zc = false; + u32 tskey = 0; +- struct rt6_info *rt = (struct rt6_info *)cork->dst; ++ struct rt6_info *rt = dst_rt6_info(cork->dst); + bool paged, hold_tskey, extra_uref = false; + struct ipv6_txoptions *opt = v6_cork->opt; + int csummode = CHECKSUM_NONE; +@@ -1959,7 +1959,7 @@ struct sk_buff *__ip6_make_skb(struct sock *sk, + struct net *net = sock_net(sk); + struct ipv6hdr *hdr; + struct ipv6_txoptions *opt = v6_cork->opt; +- struct rt6_info *rt = (struct rt6_info *)cork->base.dst; ++ struct rt6_info *rt = dst_rt6_info(cork->base.dst); + struct flowi6 *fl6 = &cork->fl.u.ip6; + unsigned char proto = fl6->flowi6_proto; + +@@ -2031,7 +2031,7 @@ struct sk_buff *__ip6_make_skb(struct sock *sk, + int ip6_send_skb(struct sk_buff *skb) + { + struct net *net = sock_net(skb->sk); +- struct rt6_info *rt = (struct rt6_info *)skb_dst(skb); ++ struct rt6_info *rt = dst_rt6_info(skb_dst(skb)); + int err; + + rcu_read_lock(); +diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c +index e24fa0843c7d1..1571e85a3531e 100644 +--- a/net/ipv6/ip6mr.c ++++ b/net/ipv6/ip6mr.c +@@ -2290,7 +2290,7 @@ int ip6mr_get_route(struct net *net, struct sk_buff *skb, struct rtmsg *rtm, + int err; + struct mr_table *mrt; + struct mfc6_cache *cache; +- struct rt6_info *rt = (struct rt6_info *)skb_dst(skb); ++ struct rt6_info *rt = dst_rt6_info(skb_dst(skb)); + + rcu_read_lock(); + mrt = __ip6mr_get_table(net, RT6_TABLE_DFLT); +diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c +index 2062ab94721e3..23b46b5705c53 100644 +--- a/net/ipv6/ndisc.c ++++ b/net/ipv6/ndisc.c +@@ -1710,7 +1710,7 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) + if (IS_ERR(dst)) + return; + +- rt = (struct rt6_info *) dst; ++ rt = dst_rt6_info(dst); + + if (rt->rt6i_flags & RTF_GATEWAY) { + ND_PRINTK(2, warn, +diff --git a/net/ipv6/ping.c b/net/ipv6/ping.c +index 25243737fbc42..878ed02b299d7 100644 +--- a/net/ipv6/ping.c ++++ b/net/ipv6/ping.c +@@ -154,7 +154,7 @@ static int ping_v6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) + dst = ip6_sk_dst_lookup_flow(sk, &fl6, daddr, false); + if (IS_ERR(dst)) + return PTR_ERR(dst); +- rt = (struct rt6_info *) dst; ++ rt = dst_rt6_info(dst); + + if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) + fl6.flowi6_oif = np->mcast_oif; +diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c +index 0a3e12502b05a..4f526606bc894 100644 +--- a/net/ipv6/raw.c ++++ b/net/ipv6/raw.c +@@ -592,7 +592,7 @@ static int rawv6_send_hdrinc(struct sock *sk, struct msghdr *msg, int length, + struct ipv6hdr *iph; + struct sk_buff *skb; + int err; +- struct rt6_info *rt = (struct rt6_info *)*dstp; ++ struct rt6_info *rt = dst_rt6_info(*dstp); + int hlen = LL_RESERVED_SPACE(rt->dst.dev); + int tlen = rt->dst.dev->needed_tailroom; + +@@ -911,7 +911,7 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) + ipc6.opt = opt; + lock_sock(sk); + err = ip6_append_data(sk, raw6_getfrag, &rfv, +- len, 0, &ipc6, &fl6, (struct rt6_info *)dst, ++ len, 0, &ipc6, &fl6, dst_rt6_info(dst), + msg->msg_flags); + + if (err) +diff --git a/net/ipv6/route.c b/net/ipv6/route.c +index e320dfa7fe7fc..0fdd062d4b05b 100644 +--- a/net/ipv6/route.c ++++ b/net/ipv6/route.c +@@ -227,7 +227,7 @@ static struct neighbour *ip6_dst_neigh_lookup(const struct dst_entry *dst, + struct sk_buff *skb, + const void *daddr) + { +- const struct rt6_info *rt = container_of(dst, struct rt6_info, dst); ++ const struct rt6_info *rt = dst_rt6_info(dst); + + return ip6_neigh_lookup(rt6_nexthop(rt, &in6addr_any), + dst->dev, skb, daddr); +@@ -235,8 +235,8 @@ static struct neighbour *ip6_dst_neigh_lookup(const struct dst_entry *dst, + + static void ip6_confirm_neigh(const struct dst_entry *dst, const void *daddr) + { ++ const struct rt6_info *rt = dst_rt6_info(dst); + struct net_device *dev = dst->dev; +- struct rt6_info *rt = (struct rt6_info *)dst; + + daddr = choose_neigh_daddr(rt6_nexthop(rt, &in6addr_any), NULL, daddr); + if (!daddr) +@@ -355,7 +355,7 @@ EXPORT_SYMBOL(ip6_dst_alloc); + + static void ip6_dst_destroy(struct dst_entry *dst) + { +- struct rt6_info *rt = (struct rt6_info *)dst; ++ struct rt6_info *rt = dst_rt6_info(dst); + struct fib6_info *from; + struct inet6_dev *idev; + +@@ -374,7 +374,7 @@ static void ip6_dst_destroy(struct dst_entry *dst) + + static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev) + { +- struct rt6_info *rt = (struct rt6_info *)dst; ++ struct rt6_info *rt = dst_rt6_info(dst); + struct inet6_dev *idev = rt->rt6i_idev; + struct fib6_info *from; + +@@ -1284,7 +1284,7 @@ struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr, + + dst = fib6_rule_lookup(net, &fl6, skb, flags, ip6_pol_route_lookup); + if (dst->error == 0) +- return (struct rt6_info *) dst; ++ return dst_rt6_info(dst); + + dst_release(dst); + +@@ -2641,7 +2641,7 @@ struct dst_entry *ip6_route_output_flags(struct net *net, + + rcu_read_lock(); + dst = ip6_route_output_flags_noref(net, sk, fl6, flags); +- rt6 = (struct rt6_info *)dst; ++ rt6 = dst_rt6_info(dst); + /* For dst cached in uncached_list, refcnt is already taken. */ + if (list_empty(&rt6->dst.rt_uncached) && !dst_hold_safe(dst)) { + dst = &net->ipv6.ip6_null_entry->dst; +@@ -2655,7 +2655,7 @@ EXPORT_SYMBOL_GPL(ip6_route_output_flags); + + struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig) + { +- struct rt6_info *rt, *ort = (struct rt6_info *) dst_orig; ++ struct rt6_info *rt, *ort = dst_rt6_info(dst_orig); + struct net_device *loopback_dev = net->loopback_dev; + struct dst_entry *new = NULL; + +@@ -2738,7 +2738,7 @@ INDIRECT_CALLABLE_SCOPE struct dst_entry *ip6_dst_check(struct dst_entry *dst, + struct fib6_info *from; + struct rt6_info *rt; + +- rt = container_of(dst, struct rt6_info, dst); ++ rt = dst_rt6_info(dst); + + if (rt->sernum) + return rt6_is_valid(rt) ? dst : NULL; +@@ -2767,7 +2767,7 @@ EXPORT_INDIRECT_CALLABLE(ip6_dst_check); + static void ip6_negative_advice(struct sock *sk, + struct dst_entry *dst) + { +- struct rt6_info *rt = (struct rt6_info *) dst; ++ struct rt6_info *rt = dst_rt6_info(dst); + + if (rt->rt6i_flags & RTF_CACHE) { + rcu_read_lock(); +@@ -2790,7 +2790,7 @@ static void ip6_link_failure(struct sk_buff *skb) + + icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0); + +- rt = (struct rt6_info *) skb_dst(skb); ++ rt = dst_rt6_info(skb_dst(skb)); + if (rt) { + rcu_read_lock(); + if (rt->rt6i_flags & RTF_CACHE) { +@@ -2846,7 +2846,7 @@ static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk, + bool confirm_neigh) + { + const struct in6_addr *daddr, *saddr; +- struct rt6_info *rt6 = (struct rt6_info *)dst; ++ struct rt6_info *rt6 = dst_rt6_info(dst); + + /* Note: do *NOT* check dst_metric_locked(dst, RTAX_MTU) + * IPv6 pmtu discovery isn't optional, so 'mtu lock' cannot disable it. +@@ -4169,7 +4169,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu + } + } + +- rt = (struct rt6_info *) dst; ++ rt = dst_rt6_info(dst); + if (rt->rt6i_flags & RTF_REJECT) { + net_dbg_ratelimited("rt6_redirect: source isn't a valid nexthop for redirect target\n"); + return; +@@ -5604,7 +5604,7 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb, + int iif, int type, u32 portid, u32 seq, + unsigned int flags) + { +- struct rt6_info *rt6 = (struct rt6_info *)dst; ++ struct rt6_info *rt6 = dst_rt6_info(dst); + struct rt6key *rt6_dst, *rt6_src; + u32 *pmetrics, table, rt6_flags; + unsigned char nh_flags = 0; +@@ -6107,7 +6107,7 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, + } + + +- rt = container_of(dst, struct rt6_info, dst); ++ rt = dst_rt6_info(dst); + if (rt->dst.error) { + err = rt->dst.error; + ip6_rt_put(rt); +diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c +index 83b48dc2b3ee2..64bdb6d978eed 100644 +--- a/net/ipv6/tcp_ipv6.c ++++ b/net/ipv6/tcp_ipv6.c +@@ -101,11 +101,9 @@ static void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb) + struct dst_entry *dst = skb_dst(skb); + + if (dst && dst_hold_safe(dst)) { +- const struct rt6_info *rt = (const struct rt6_info *)dst; +- + rcu_assign_pointer(sk->sk_rx_dst, dst); + sk->sk_rx_dst_ifindex = skb->skb_iif; +- sk->sk_rx_dst_cookie = rt6_get_cookie(rt); ++ sk->sk_rx_dst_cookie = rt6_get_cookie(dst_rt6_info(dst)); + } + } + +diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c +index c77ee9a3cde24..954afe6ba883e 100644 +--- a/net/ipv6/udp.c ++++ b/net/ipv6/udp.c +@@ -913,11 +913,8 @@ static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb, + + static void udp6_sk_rx_dst_set(struct sock *sk, struct dst_entry *dst) + { +- if (udp_sk_rx_dst_set(sk, dst)) { +- const struct rt6_info *rt = (const struct rt6_info *)dst; +- +- sk->sk_rx_dst_cookie = rt6_get_cookie(rt); +- } ++ if (udp_sk_rx_dst_set(sk, dst)) ++ sk->sk_rx_dst_cookie = rt6_get_cookie(dst_rt6_info(dst)); + } + + /* wrapper for udp_queue_rcv_skb tacking care of csum conversion and +@@ -1587,7 +1584,7 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) + + skb = ip6_make_skb(sk, getfrag, msg, ulen, + sizeof(struct udphdr), &ipc6, +- (struct rt6_info *)dst, ++ dst_rt6_info(dst), + msg->msg_flags, &cork); + err = PTR_ERR(skb); + if (!IS_ERR_OR_NULL(skb)) +@@ -1614,7 +1611,7 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) + ipc6.dontfrag = np->dontfrag; + up->len += ulen; + err = ip6_append_data(sk, getfrag, msg, ulen, sizeof(struct udphdr), +- &ipc6, fl6, (struct rt6_info *)dst, ++ &ipc6, fl6, dst_rt6_info(dst), + corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); + if (err) + udp_v6_flush_pending_frames(sk); +diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c +index 4cd625af91e6c..f24faa78ee82d 100644 +--- a/net/ipv6/xfrm6_policy.c ++++ b/net/ipv6/xfrm6_policy.c +@@ -77,7 +77,7 @@ static int xfrm6_get_saddr(xfrm_address_t *saddr, + static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, + const struct flowi *fl) + { +- struct rt6_info *rt = (struct rt6_info *)xdst->route; ++ struct rt6_info *rt = dst_rt6_info(xdst->route); + + xdst->u.dst.dev = dev; + netdev_hold(dev, &xdst->u.dst.dev_tracker, GFP_ATOMIC); +diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c +index db4971d52802b..1b7a7b4f7273a 100644 +--- a/net/l2tp/l2tp_ip6.c ++++ b/net/l2tp/l2tp_ip6.c +@@ -630,7 +630,7 @@ static int l2tp_ip6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) + ulen = len + (skb_queue_empty(&sk->sk_write_queue) ? transhdrlen : 0); + err = ip6_append_data(sk, ip_generic_getfrag, msg, + ulen, transhdrlen, &ipc6, +- &fl6, (struct rt6_info *)dst, ++ &fl6, dst_rt6_info(dst), + msg->msg_flags); + if (err) + ip6_flush_pending_frames(sk); +diff --git a/net/mpls/mpls_iptunnel.c b/net/mpls/mpls_iptunnel.c +index ef59e25dc4827..8985abcb7a058 100644 +--- a/net/mpls/mpls_iptunnel.c ++++ b/net/mpls/mpls_iptunnel.c +@@ -92,7 +92,7 @@ static int mpls_xmit(struct sk_buff *skb) + ttl = net->mpls.default_ttl; + else + ttl = ipv6_hdr(skb)->hop_limit; +- rt6 = (struct rt6_info *)dst; ++ rt6 = dst_rt6_info(dst); + } else { + goto drop; + } +diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c +index 65e0259178da4..5cd511162bc03 100644 +--- a/net/netfilter/ipvs/ip_vs_xmit.c ++++ b/net/netfilter/ipvs/ip_vs_xmit.c +@@ -180,7 +180,7 @@ static inline bool crosses_local_route_boundary(int skb_af, struct sk_buff *skb, + (!skb->dev || skb->dev->flags & IFF_LOOPBACK) && + (addr_type & IPV6_ADDR_LOOPBACK); + old_rt_is_local = __ip_vs_is_local_route6( +- (struct rt6_info *)skb_dst(skb)); ++ dst_rt6_info(skb_dst(skb))); + } else + #endif + { +@@ -481,7 +481,7 @@ __ip_vs_get_out_rt_v6(struct netns_ipvs *ipvs, int skb_af, struct sk_buff *skb, + if (dest) { + dest_dst = __ip_vs_dst_check(dest); + if (likely(dest_dst)) +- rt = (struct rt6_info *) dest_dst->dst_cache; ++ rt = dst_rt6_info(dest_dst->dst_cache); + else { + u32 cookie; + +@@ -501,7 +501,7 @@ __ip_vs_get_out_rt_v6(struct netns_ipvs *ipvs, int skb_af, struct sk_buff *skb, + ip_vs_dest_dst_free(dest_dst); + goto err_unreach; + } +- rt = (struct rt6_info *) dst; ++ rt = dst_rt6_info(dst); + cookie = rt6_get_cookie(rt); + __ip_vs_dst_set(dest, dest_dst, &rt->dst, cookie); + spin_unlock_bh(&dest->dst_lock); +@@ -517,7 +517,7 @@ __ip_vs_get_out_rt_v6(struct netns_ipvs *ipvs, int skb_af, struct sk_buff *skb, + rt_mode); + if (!dst) + goto err_unreach; +- rt = (struct rt6_info *) dst; ++ rt = dst_rt6_info(dst); + } + + local = __ip_vs_is_local_route6(rt); +@@ -862,7 +862,7 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, + IP_VS_RT_MODE_RDR); + if (local < 0) + goto tx_error; +- rt = (struct rt6_info *) skb_dst(skb); ++ rt = dst_rt6_info(skb_dst(skb)); + /* + * Avoid duplicate tuple in reply direction for NAT traffic + * to local address when connection is sync-ed +@@ -1288,7 +1288,7 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, + if (local) + return ip_vs_send_or_cont(NFPROTO_IPV6, skb, cp, 1); + +- rt = (struct rt6_info *) skb_dst(skb); ++ rt = dst_rt6_info(skb_dst(skb)); + tdev = rt->dst.dev; + + /* +@@ -1590,7 +1590,7 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, + &cp->daddr.in6, NULL, ipvsh, 0, rt_mode); + if (local < 0) + goto tx_error; +- rt = (struct rt6_info *) skb_dst(skb); ++ rt = dst_rt6_info(skb_dst(skb)); + /* + * Avoid duplicate tuple in reply direction for NAT traffic + * to local address when connection is sync-ed +diff --git a/net/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c +index a0571339239c4..5c1ff07eaee0b 100644 +--- a/net/netfilter/nf_flow_table_core.c ++++ b/net/netfilter/nf_flow_table_core.c +@@ -77,12 +77,8 @@ EXPORT_SYMBOL_GPL(flow_offload_alloc); + + static u32 flow_offload_dst_cookie(struct flow_offload_tuple *flow_tuple) + { +- const struct rt6_info *rt; +- +- if (flow_tuple->l3proto == NFPROTO_IPV6) { +- rt = (const struct rt6_info *)flow_tuple->dst_cache; +- return rt6_get_cookie(rt); +- } ++ if (flow_tuple->l3proto == NFPROTO_IPV6) ++ return rt6_get_cookie(dst_rt6_info(flow_tuple->dst_cache)); + + return 0; + } +diff --git a/net/netfilter/nf_flow_table_ip.c b/net/netfilter/nf_flow_table_ip.c +index 846fa2ad7c858..20dd4eeac78b1 100644 +--- a/net/netfilter/nf_flow_table_ip.c ++++ b/net/netfilter/nf_flow_table_ip.c +@@ -732,7 +732,7 @@ nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb, + return NF_ACCEPT; + + if (unlikely(tuplehash->tuple.xmit_type == FLOW_OFFLOAD_XMIT_XFRM)) { +- rt = (struct rt6_info *)tuplehash->tuple.dst_cache; ++ rt = dst_rt6_info(tuplehash->tuple.dst_cache); + memset(skb->cb, 0, sizeof(struct inet6_skb_parm)); + IP6CB(skb)->iif = skb->dev->ifindex; + IP6CB(skb)->flags = IP6SKB_FORWARDED; +@@ -744,7 +744,7 @@ nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb, + + switch (tuplehash->tuple.xmit_type) { + case FLOW_OFFLOAD_XMIT_NEIGH: +- rt = (struct rt6_info *)tuplehash->tuple.dst_cache; ++ rt = dst_rt6_info(tuplehash->tuple.dst_cache); + outdev = rt->dst.dev; + skb->dev = outdev; + nexthop = rt6_nexthop(rt, &flow->tuplehash[!dir].tuple.src_v6); +diff --git a/net/netfilter/nft_rt.c b/net/netfilter/nft_rt.c +index 24d9771385729..2434c624aafde 100644 +--- a/net/netfilter/nft_rt.c ++++ b/net/netfilter/nft_rt.c +@@ -80,7 +80,7 @@ void nft_rt_get_eval(const struct nft_expr *expr, + if (nft_pf(pkt) != NFPROTO_IPV6) + goto err; + +- memcpy(dest, rt6_nexthop((struct rt6_info *)dst, ++ memcpy(dest, rt6_nexthop(dst_rt6_info(dst), + &ipv6_hdr(skb)->daddr), + sizeof(struct in6_addr)); + break; +diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c +index 08acda9ecdf56..717828e531621 100644 +--- a/net/sctp/ipv6.c ++++ b/net/sctp/ipv6.c +@@ -416,7 +416,7 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr, + if (!IS_ERR_OR_NULL(dst)) { + struct rt6_info *rt; + +- rt = (struct rt6_info *)dst; ++ rt = dst_rt6_info(dst); + t->dst_cookie = rt6_get_cookie(rt); + pr_debug("rt6_dst:%pI6/%d rt6_src:%pI6\n", + &rt->rt6i_dst.addr, rt->rt6i_dst.plen, +diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c +index d788baffbf104..68b3f9e7edffd 100644 +--- a/net/xfrm/xfrm_policy.c ++++ b/net/xfrm/xfrm_policy.c +@@ -2607,8 +2607,7 @@ static void xfrm_init_path(struct xfrm_dst *path, struct dst_entry *dst, + int nfheader_len) + { + if (dst->ops->family == AF_INET6) { +- struct rt6_info *rt = (struct rt6_info *)dst; +- path->path_cookie = rt6_get_cookie(rt); ++ path->path_cookie = rt6_get_cookie(dst_rt6_info(dst)); + path->u.rt6.rt6i_nfheader_len = nfheader_len; + } + } +-- +2.43.0 + diff --git a/queue-6.6/ipvs-fix-ub-due-to-uninitialized-stack-access-in-ip_.patch b/queue-6.6/ipvs-fix-ub-due-to-uninitialized-stack-access-in-ip_.patch new file mode 100644 index 00000000000..9b6c886ec80 --- /dev/null +++ b/queue-6.6/ipvs-fix-ub-due-to-uninitialized-stack-access-in-ip_.patch @@ -0,0 +1,117 @@ +From 35d591d95d07e560d6dad89a64c2eaee6af8f0d1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 23 Nov 2024 03:42:56 -0600 +Subject: ipvs: fix UB due to uninitialized stack access in + ip_vs_protocol_init() + +From: Jinghao Jia + +[ Upstream commit 146b6f1112eb30a19776d6c323c994e9d67790db ] + +Under certain kernel configurations when building with Clang/LLVM, the +compiler does not generate a return or jump as the terminator +instruction for ip_vs_protocol_init(), triggering the following objtool +warning during build time: + + vmlinux.o: warning: objtool: ip_vs_protocol_init() falls through to next function __initstub__kmod_ip_vs_rr__935_123_ip_vs_rr_init6() + +At runtime, this either causes an oops when trying to load the ipvs +module or a boot-time panic if ipvs is built-in. This same issue has +been reported by the Intel kernel test robot previously. + +Digging deeper into both LLVM and the kernel code reveals this to be a +undefined behavior problem. ip_vs_protocol_init() uses a on-stack buffer +of 64 chars to store the registered protocol names and leaves it +uninitialized after definition. The function calls strnlen() when +concatenating protocol names into the buffer. With CONFIG_FORTIFY_SOURCE +strnlen() performs an extra step to check whether the last byte of the +input char buffer is a null character (commit 3009f891bb9f ("fortify: +Allow strlen() and strnlen() to pass compile-time known lengths")). +This, together with possibly other configurations, cause the following +IR to be generated: + + define hidden i32 @ip_vs_protocol_init() local_unnamed_addr #5 section ".init.text" align 16 !kcfi_type !29 { + %1 = alloca [64 x i8], align 16 + ... + + 14: ; preds = %11 + %15 = getelementptr inbounds i8, ptr %1, i64 63 + %16 = load i8, ptr %15, align 1 + %17 = tail call i1 @llvm.is.constant.i8(i8 %16) + %18 = icmp eq i8 %16, 0 + %19 = select i1 %17, i1 %18, i1 false + br i1 %19, label %20, label %23 + + 20: ; preds = %14 + %21 = call i64 @strlen(ptr noundef nonnull dereferenceable(1) %1) #23 + ... + + 23: ; preds = %14, %11, %20 + %24 = call i64 @strnlen(ptr noundef nonnull dereferenceable(1) %1, i64 noundef 64) #24 + ... + } + +The above code calculates the address of the last char in the buffer +(value %15) and then loads from it (value %16). Because the buffer is +never initialized, the LLVM GVN pass marks value %16 as undefined: + + %13 = getelementptr inbounds i8, ptr %1, i64 63 + br i1 undef, label %14, label %17 + +This gives later passes (SCCP, in particular) more DCE opportunities by +propagating the undef value further, and eventually removes everything +after the load on the uninitialized stack location: + + define hidden i32 @ip_vs_protocol_init() local_unnamed_addr #0 section ".init.text" align 16 !kcfi_type !11 { + %1 = alloca [64 x i8], align 16 + ... + + 12: ; preds = %11 + %13 = getelementptr inbounds i8, ptr %1, i64 63 + unreachable + } + +In this way, the generated native code will just fall through to the +next function, as LLVM does not generate any code for the unreachable IR +instruction and leaves the function without a terminator. + +Zero the on-stack buffer to avoid this possible UB. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202402100205.PWXIz1ZK-lkp@intel.com/ +Co-developed-by: Ruowen Qin +Signed-off-by: Ruowen Qin +Signed-off-by: Jinghao Jia +Acked-by: Julian Anastasov +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/ipvs/ip_vs_proto.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/net/netfilter/ipvs/ip_vs_proto.c b/net/netfilter/ipvs/ip_vs_proto.c +index f100da4ba3bc3..a9fd1d3fc2cbf 100644 +--- a/net/netfilter/ipvs/ip_vs_proto.c ++++ b/net/netfilter/ipvs/ip_vs_proto.c +@@ -340,7 +340,7 @@ void __net_exit ip_vs_protocol_net_cleanup(struct netns_ipvs *ipvs) + + int __init ip_vs_protocol_init(void) + { +- char protocols[64]; ++ char protocols[64] = { 0 }; + #define REGISTER_PROTOCOL(p) \ + do { \ + register_ip_vs_protocol(p); \ +@@ -348,8 +348,6 @@ int __init ip_vs_protocol_init(void) + strcat(protocols, (p)->name); \ + } while (0) + +- protocols[0] = '\0'; +- protocols[2] = '\0'; + #ifdef CONFIG_IP_VS_PROTO_TCP + REGISTER_PROTOCOL(&ip_vs_protocol_tcp); + #endif +-- +2.43.0 + diff --git a/queue-6.6/itco_wdt-mask-nmi_now-bit-for-update_no_reboot_bit-c.patch b/queue-6.6/itco_wdt-mask-nmi_now-bit-for-update_no_reboot_bit-c.patch new file mode 100644 index 00000000000..493cd8be028 --- /dev/null +++ b/queue-6.6/itco_wdt-mask-nmi_now-bit-for-update_no_reboot_bit-c.patch @@ -0,0 +1,85 @@ +From 603e805f2b7d442fbe463e84b3683a9765d87cd1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Sep 2024 12:14:03 -0700 +Subject: iTCO_wdt: mask NMI_NOW bit for update_no_reboot_bit() call + +From: Oleksandr Ocheretnyi + +[ Upstream commit daa814d784ac034c62ab3fb0ef83daeafef527e2 ] + +Commit da23b6faa8bf ("watchdog: iTCO: Add support for Cannon Lake +PCH iTCO") does not mask NMI_NOW bit during TCO1_CNT register's +value comparison for update_no_reboot_bit() call causing following +failure: + + ... + iTCO_vendor_support: vendor-support=0 + iTCO_wdt iTCO_wdt: unable to reset NO_REBOOT flag, device + disabled by hardware/BIOS + ... + +and this can lead to unexpected NMIs later during regular +crashkernel's workflow because of watchdog probe call failures. + +This change masks NMI_NOW bit for TCO1_CNT register values to +avoid unexpected NMI_NOW bit inversions. + +Fixes: da23b6faa8bf ("watchdog: iTCO: Add support for Cannon Lake PCH iTCO") +Signed-off-by: Oleksandr Ocheretnyi +Reviewed-by: Guenter Roeck +Reviewed-by: Mika Westerberg +Link: https://lore.kernel.org/r/20240913191403.2560805-1-oocheret@cisco.com +Signed-off-by: Guenter Roeck +Signed-off-by: Wim Van Sebroeck +Signed-off-by: Sasha Levin +--- + drivers/watchdog/iTCO_wdt.c | 21 +++++++++++++++++++-- + 1 file changed, 19 insertions(+), 2 deletions(-) + +diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c +index 264857d314da8..dd297dcd524c9 100644 +--- a/drivers/watchdog/iTCO_wdt.c ++++ b/drivers/watchdog/iTCO_wdt.c +@@ -82,6 +82,13 @@ + #define TCO2_CNT(p) (TCOBASE(p) + 0x0a) /* TCO2 Control Register */ + #define TCOv2_TMR(p) (TCOBASE(p) + 0x12) /* TCOv2 Timer Initial Value*/ + ++/* ++ * NMI_NOW is bit 8 of TCO1_CNT register ++ * Read/Write ++ * This bit is implemented as RW but has no effect on HW. ++ */ ++#define NMI_NOW BIT(8) ++ + /* internal variables */ + struct iTCO_wdt_private { + struct watchdog_device wddev; +@@ -219,13 +226,23 @@ static int update_no_reboot_bit_cnt(void *priv, bool set) + struct iTCO_wdt_private *p = priv; + u16 val, newval; + +- val = inw(TCO1_CNT(p)); ++ /* ++ * writing back 1b1 to NMI_NOW of TCO1_CNT register ++ * causes NMI_NOW bit inversion what consequently does ++ * not allow to perform the register's value comparison ++ * properly. ++ * ++ * NMI_NOW bit masking for TCO1_CNT register values ++ * helps to avoid possible NMI_NOW bit inversions on ++ * following write operation. ++ */ ++ val = inw(TCO1_CNT(p)) & ~NMI_NOW; + if (set) + val |= BIT(0); + else + val &= ~BIT(0); + outw(val, TCO1_CNT(p)); +- newval = inw(TCO1_CNT(p)); ++ newval = inw(TCO1_CNT(p)) & ~NMI_NOW; + + /* make sure the update is successful */ + return val != newval ? -EIO : 0; +-- +2.43.0 + diff --git a/queue-6.6/ixgbe-downgrade-logging-of-unsupported-vf-api-versio.patch b/queue-6.6/ixgbe-downgrade-logging-of-unsupported-vf-api-versio.patch new file mode 100644 index 00000000000..1ffc3ea47da --- /dev/null +++ b/queue-6.6/ixgbe-downgrade-logging-of-unsupported-vf-api-versio.patch @@ -0,0 +1,73 @@ +From 6e992882c7323b610206f7d2027de1d8e91de68a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 1 Nov 2024 16:05:43 -0700 +Subject: ixgbe: downgrade logging of unsupported VF API version to debug + +From: Jacob Keller + +[ Upstream commit 15915b43a7fb938934bb7fc4290127218859d795 ] + +The ixgbe PF driver logs an info message when a VF attempts to negotiate an +API version which it does not support: + + VF 0 requested invalid api version 6 + +The ixgbevf driver attempts to load with mailbox API v1.5, which is +required for best compatibility with other hosts such as the ESX VMWare PF. + +The Linux PF only supports API v1.4, and does not currently have support +for the v1.5 API. + +The logged message can confuse users, as the v1.5 API is valid, but just +happens to not currently be supported by the Linux PF. + +Downgrade the info message to a debug message, and fix the language to +use 'unsupported' instead of 'invalid' to improve message clarity. + +Long term, we should investigate whether the improvements in the v1.5 API +make sense for the Linux PF, and if so implement them properly. This may +require yet another API version to resolve issues with negotiating IPSEC +offload support. + +Fixes: 339f28964147 ("ixgbevf: Add support for new mailbox communication between PF and VF") +Reported-by: Yifei Liu +Link: https://lore.kernel.org/intel-wired-lan/20240301235837.3741422-1-yifei.l.liu@oracle.com/ +Signed-off-by: Jacob Keller +Reviewed-by: Przemek Kitszel +Tested-by: Rafal Romanowski +Signed-off-by: Tony Nguyen +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ixgbe/ixgbe_common.h | 2 ++ + drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c | 2 +- + 2 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h +index 34761e691d52d..efdc222e183d1 100644 +--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h ++++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h +@@ -194,6 +194,8 @@ u32 ixgbe_read_reg(struct ixgbe_hw *hw, u32 reg); + dev_err(&adapter->pdev->dev, format, ## arg) + #define e_dev_notice(format, arg...) \ + dev_notice(&adapter->pdev->dev, format, ## arg) ++#define e_dbg(msglvl, format, arg...) \ ++ netif_dbg(adapter, msglvl, adapter->netdev, format, ## arg) + #define e_info(msglvl, format, arg...) \ + netif_info(adapter, msglvl, adapter->netdev, format, ## arg) + #define e_err(msglvl, format, arg...) \ +diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c +index d0a6c220a12ac..9c89a87e35e01 100644 +--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c ++++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c +@@ -1049,7 +1049,7 @@ static int ixgbe_negotiate_vf_api(struct ixgbe_adapter *adapter, + break; + } + +- e_info(drv, "VF %d requested invalid api version %u\n", vf, api); ++ e_dbg(drv, "VF %d requested unsupported api version %u\n", vf, api); + + return -1; + } +-- +2.43.0 + diff --git a/queue-6.6/ixgbevf-stop-attempting-ipsec-offload-on-mailbox-api.patch b/queue-6.6/ixgbevf-stop-attempting-ipsec-offload-on-mailbox-api.patch new file mode 100644 index 00000000000..bfb57110814 --- /dev/null +++ b/queue-6.6/ixgbevf-stop-attempting-ipsec-offload-on-mailbox-api.patch @@ -0,0 +1,58 @@ +From 2aadf25fb599476a45e709672afc4e8875a9d448 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 1 Nov 2024 16:05:42 -0700 +Subject: ixgbevf: stop attempting IPSEC offload on Mailbox API 1.5 + +From: Jacob Keller + +[ Upstream commit d0725312adf5a803de8f621bd1b12ba7a6464a29 ] + +Commit 339f28964147 ("ixgbevf: Add support for new mailbox communication +between PF and VF") added support for v1.5 of the PF to VF mailbox +communication API. This commit mistakenly enabled IPSEC offload for API +v1.5. + +No implementation of the v1.5 API has support for IPSEC offload. This +offload is only supported by the Linux PF as mailbox API v1.4. In fact, the +v1.5 API is not implemented in any Linux PF. + +Attempting to enable IPSEC offload on a PF which supports v1.5 API will not +work. Only the Linux upstream ixgbe and ixgbevf support IPSEC offload, and +only as part of the v1.4 API. + +Fix the ixgbevf Linux driver to stop attempting IPSEC offload when +the mailbox API does not support it. + +The existing API design choice makes it difficult to support future API +versions, as other non-Linux hosts do not implement IPSEC offload. If we +add support for v1.5 to the Linux PF, then we lose support for IPSEC +offload. + +A full solution likely requires a new mailbox API with a proper negotiation +to check that IPSEC is actually supported by the host. + +Fixes: 339f28964147 ("ixgbevf: Add support for new mailbox communication between PF and VF") +Signed-off-by: Jacob Keller +Reviewed-by: Przemek Kitszel +Tested-by: Rafal Romanowski +Signed-off-by: Tony Nguyen +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/ixgbevf/ipsec.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/net/ethernet/intel/ixgbevf/ipsec.c b/drivers/net/ethernet/intel/ixgbevf/ipsec.c +index 66cf17f194082..f804b35d79c72 100644 +--- a/drivers/net/ethernet/intel/ixgbevf/ipsec.c ++++ b/drivers/net/ethernet/intel/ixgbevf/ipsec.c +@@ -629,7 +629,6 @@ void ixgbevf_init_ipsec_offload(struct ixgbevf_adapter *adapter) + + switch (adapter->hw.api_version) { + case ixgbe_mbox_api_14: +- case ixgbe_mbox_api_15: + break; + default: + return; +-- +2.43.0 + diff --git a/queue-6.6/kvm-arm64-change-kvm_handle_mmio_return-return-polar.patch b/queue-6.6/kvm-arm64-change-kvm_handle_mmio_return-return-polar.patch new file mode 100644 index 00000000000..e71e77d9bec --- /dev/null +++ b/queue-6.6/kvm-arm64-change-kvm_handle_mmio_return-return-polar.patch @@ -0,0 +1,66 @@ +From ce0990dfeedc1119319c45710975ce08a745f787 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 23 Apr 2024 16:05:22 +0100 +Subject: KVM: arm64: Change kvm_handle_mmio_return() return polarity + +From: Fuad Tabba + +[ Upstream commit cc81b6dfc3bc82c3a2600eefbd3823bdb2190197 ] + +Most exit handlers return <= 0 to indicate that the host needs to +handle the exit. Make kvm_handle_mmio_return() consistent with +the exit handlers in handle_exit(). This makes the code easier to +reason about, and makes it easier to add other handlers in future +patches. + +No functional change intended. + +Signed-off-by: Fuad Tabba +Acked-by: Oliver Upton +Link: https://lore.kernel.org/r/20240423150538.2103045-15-tabba@google.com +Signed-off-by: Marc Zyngier +Stable-dep-of: e735a5da6442 ("KVM: arm64: Don't retire aborted MMIO instruction") +Signed-off-by: Sasha Levin +--- + arch/arm64/kvm/arm.c | 2 +- + arch/arm64/kvm/mmio.c | 4 ++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c +index 4742e6c5ea7a0..ffdc2c4d07ee8 100644 +--- a/arch/arm64/kvm/arm.c ++++ b/arch/arm64/kvm/arm.c +@@ -900,7 +900,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) + + if (run->exit_reason == KVM_EXIT_MMIO) { + ret = kvm_handle_mmio_return(vcpu); +- if (ret) ++ if (ret <= 0) + return ret; + } + +diff --git a/arch/arm64/kvm/mmio.c b/arch/arm64/kvm/mmio.c +index 3dd38a151d2a6..886ef30e12196 100644 +--- a/arch/arm64/kvm/mmio.c ++++ b/arch/arm64/kvm/mmio.c +@@ -86,7 +86,7 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu) + + /* Detect an already handled MMIO return */ + if (unlikely(!vcpu->mmio_needed)) +- return 0; ++ return 1; + + vcpu->mmio_needed = 0; + +@@ -117,7 +117,7 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu) + */ + kvm_incr_pc(vcpu); + +- return 0; ++ return 1; + } + + int io_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa) +-- +2.43.0 + diff --git a/queue-6.6/kvm-arm64-don-t-retire-aborted-mmio-instruction.patch b/queue-6.6/kvm-arm64-don-t-retire-aborted-mmio-instruction.patch new file mode 100644 index 00000000000..39f88c6ff47 --- /dev/null +++ b/queue-6.6/kvm-arm64-don-t-retire-aborted-mmio-instruction.patch @@ -0,0 +1,106 @@ +From e47b4a47b2f51b393a4cbd8b55210a915a74f5a4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 25 Oct 2024 20:31:03 +0000 +Subject: KVM: arm64: Don't retire aborted MMIO instruction + +From: Oliver Upton + +[ Upstream commit e735a5da64420a86be370b216c269b5dd8e830e2 ] + +Returning an abort to the guest for an unsupported MMIO access is a +documented feature of the KVM UAPI. Nevertheless, it's clear that this +plumbing has seen limited testing, since userspace can trivially cause a +WARN in the MMIO return: + + WARNING: CPU: 0 PID: 30558 at arch/arm64/include/asm/kvm_emulate.h:536 kvm_handle_mmio_return+0x46c/0x5c4 arch/arm64/include/asm/kvm_emulate.h:536 + Call trace: + kvm_handle_mmio_return+0x46c/0x5c4 arch/arm64/include/asm/kvm_emulate.h:536 + kvm_arch_vcpu_ioctl_run+0x98/0x15b4 arch/arm64/kvm/arm.c:1133 + kvm_vcpu_ioctl+0x75c/0xa78 virt/kvm/kvm_main.c:4487 + __do_sys_ioctl fs/ioctl.c:51 [inline] + __se_sys_ioctl fs/ioctl.c:893 [inline] + __arm64_sys_ioctl+0x14c/0x1c8 fs/ioctl.c:893 + __invoke_syscall arch/arm64/kernel/syscall.c:35 [inline] + invoke_syscall+0x98/0x2b8 arch/arm64/kernel/syscall.c:49 + el0_svc_common+0x1e0/0x23c arch/arm64/kernel/syscall.c:132 + do_el0_svc+0x48/0x58 arch/arm64/kernel/syscall.c:151 + el0_svc+0x38/0x68 arch/arm64/kernel/entry-common.c:712 + el0t_64_sync_handler+0x90/0xfc arch/arm64/kernel/entry-common.c:730 + el0t_64_sync+0x190/0x194 arch/arm64/kernel/entry.S:598 + +The splat is complaining that KVM is advancing PC while an exception is +pending, i.e. that KVM is retiring the MMIO instruction despite a +pending synchronous external abort. Womp womp. + +Fix the glaring UAPI bug by skipping over all the MMIO emulation in +case there is a pending synchronous exception. Note that while userspace +is capable of pending an asynchronous exception (SError, IRQ, or FIQ), +it is still safe to retire the MMIO instruction in this case as (1) they +are by definition asynchronous, and (2) KVM relies on hardware support +for pending/delivering these exceptions instead of the software state +machine for advancing PC. + +Cc: stable@vger.kernel.org +Fixes: da345174ceca ("KVM: arm/arm64: Allow user injection of external data aborts") +Reported-by: Alexander Potapenko +Reviewed-by: Marc Zyngier +Link: https://lore.kernel.org/r/20241025203106.3529261-2-oliver.upton@linux.dev +Signed-off-by: Oliver Upton +Signed-off-by: Sasha Levin +--- + arch/arm64/kvm/mmio.c | 32 ++++++++++++++++++++++++++++++-- + 1 file changed, 30 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/kvm/mmio.c b/arch/arm64/kvm/mmio.c +index 886ef30e12196..2aa503ff742ee 100644 +--- a/arch/arm64/kvm/mmio.c ++++ b/arch/arm64/kvm/mmio.c +@@ -72,6 +72,31 @@ unsigned long kvm_mmio_read_buf(const void *buf, unsigned int len) + return data; + } + ++static bool kvm_pending_sync_exception(struct kvm_vcpu *vcpu) ++{ ++ if (!vcpu_get_flag(vcpu, PENDING_EXCEPTION)) ++ return false; ++ ++ if (vcpu_el1_is_32bit(vcpu)) { ++ switch (vcpu_get_flag(vcpu, EXCEPT_MASK)) { ++ case unpack_vcpu_flag(EXCEPT_AA32_UND): ++ case unpack_vcpu_flag(EXCEPT_AA32_IABT): ++ case unpack_vcpu_flag(EXCEPT_AA32_DABT): ++ return true; ++ default: ++ return false; ++ } ++ } else { ++ switch (vcpu_get_flag(vcpu, EXCEPT_MASK)) { ++ case unpack_vcpu_flag(EXCEPT_AA64_EL1_SYNC): ++ case unpack_vcpu_flag(EXCEPT_AA64_EL2_SYNC): ++ return true; ++ default: ++ return false; ++ } ++ } ++} ++ + /** + * kvm_handle_mmio_return -- Handle MMIO loads after user space emulation + * or in-kernel IO emulation +@@ -84,8 +109,11 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu) + unsigned int len; + int mask; + +- /* Detect an already handled MMIO return */ +- if (unlikely(!vcpu->mmio_needed)) ++ /* ++ * Detect if the MMIO return was already handled or if userspace aborted ++ * the MMIO access. ++ */ ++ if (unlikely(!vcpu->mmio_needed || kvm_pending_sync_exception(vcpu))) + return 1; + + vcpu->mmio_needed = 0; +-- +2.43.0 + diff --git a/queue-6.6/mlxsw-add-ipv4_5-flex-key.patch b/queue-6.6/mlxsw-add-ipv4_5-flex-key.patch new file mode 100644 index 00000000000..e554ab04fa7 --- /dev/null +++ b/queue-6.6/mlxsw-add-ipv4_5-flex-key.patch @@ -0,0 +1,142 @@ +From 10a5b6500a678710c1540ca568ae242f3c89786f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 Sep 2023 17:42:54 +0200 +Subject: mlxsw: Add 'ipv4_5' flex key + +From: Amit Cohen + +[ Upstream commit c2f3e10ac4ebf23e177226b9b4d297bfe2fb6b20 ] + +Currently virtual router ID element is broken to two sub-elements - +'VIRT_ROUTER_LSB' and 'VIRT_ROUTER_MSB'. It was broken as this field is +broken in 'ipv4_4' flex key which is used for IPv4 in Spectrum < 4. +For Spectrum-4, we use 'ipv4_4b' flex key which contains one field for +virtual router, this key is not supported in older ASICs. + +Add 'ipv4_5' flex key which is supported in all ASICs and contains one +field for virtual router. Then there is no reason to use 'VIRT_ROUTER_LSB' +and 'VIRT_ROUTER_MSB', remove them and add one element 'VIRT_ROUTER' for +this field. + +The motivation is to get rid of 'ipv4_4' flex key, as it might be chosen +for IPv6 multicast forwarding region. This will not allow the improvement +in a following patch. See more details in the cover letter and in a +following patch. + +Signed-off-by: Amit Cohen +Reviewed-by: Ido Schimmel +Signed-off-by: Petr Machata +Signed-off-by: David S. Miller +Stable-dep-of: 217bbf156f93 ("mlxsw: spectrum_acl_flex_keys: Use correct key block on Spectrum-4") +Signed-off-by: Sasha Levin +--- + .../ethernet/mellanox/mlxsw/core_acl_flex_keys.c | 3 +-- + .../ethernet/mellanox/mlxsw/core_acl_flex_keys.h | 3 +-- + .../net/ethernet/mellanox/mlxsw/spectrum2_mr_tcam.c | 13 ++++--------- + .../mellanox/mlxsw/spectrum_acl_flex_keys.c | 10 ++++------ + 4 files changed, 10 insertions(+), 19 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c +index bf140e7416e19..5fa3800940c89 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c +@@ -33,8 +33,7 @@ static const struct mlxsw_afk_element_info mlxsw_afk_element_infos[] = { + MLXSW_AFK_ELEMENT_INFO_U32(IP_TTL_, 0x18, 0, 8), + MLXSW_AFK_ELEMENT_INFO_U32(IP_ECN, 0x18, 9, 2), + MLXSW_AFK_ELEMENT_INFO_U32(IP_DSCP, 0x18, 11, 6), +- MLXSW_AFK_ELEMENT_INFO_U32(VIRT_ROUTER_MSB, 0x18, 17, 4), +- MLXSW_AFK_ELEMENT_INFO_U32(VIRT_ROUTER_LSB, 0x18, 21, 8), ++ MLXSW_AFK_ELEMENT_INFO_U32(VIRT_ROUTER, 0x18, 17, 12), + MLXSW_AFK_ELEMENT_INFO_BUF(SRC_IP_96_127, 0x20, 4), + MLXSW_AFK_ELEMENT_INFO_BUF(SRC_IP_64_95, 0x24, 4), + MLXSW_AFK_ELEMENT_INFO_BUF(SRC_IP_32_63, 0x28, 4), +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h +index 2eac7582c31a8..75e9bbc361701 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h +@@ -33,8 +33,7 @@ enum mlxsw_afk_element { + MLXSW_AFK_ELEMENT_IP_TTL_, + MLXSW_AFK_ELEMENT_IP_ECN, + MLXSW_AFK_ELEMENT_IP_DSCP, +- MLXSW_AFK_ELEMENT_VIRT_ROUTER_MSB, +- MLXSW_AFK_ELEMENT_VIRT_ROUTER_LSB, ++ MLXSW_AFK_ELEMENT_VIRT_ROUTER, + MLXSW_AFK_ELEMENT_FDB_MISS, + MLXSW_AFK_ELEMENT_L4_PORT_RANGE, + MLXSW_AFK_ELEMENT_MAX, +diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum2_mr_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum2_mr_tcam.c +index b1178b7a7f51a..2efcc9372d4e6 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum2_mr_tcam.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum2_mr_tcam.c +@@ -45,8 +45,7 @@ static int mlxsw_sp2_mr_tcam_bind_group(struct mlxsw_sp *mlxsw_sp, + } + + static const enum mlxsw_afk_element mlxsw_sp2_mr_tcam_usage_ipv4[] = { +- MLXSW_AFK_ELEMENT_VIRT_ROUTER_MSB, +- MLXSW_AFK_ELEMENT_VIRT_ROUTER_LSB, ++ MLXSW_AFK_ELEMENT_VIRT_ROUTER, + MLXSW_AFK_ELEMENT_SRC_IP_0_31, + MLXSW_AFK_ELEMENT_DST_IP_0_31, + }; +@@ -89,8 +88,7 @@ static void mlxsw_sp2_mr_tcam_ipv4_fini(struct mlxsw_sp2_mr_tcam *mr_tcam) + } + + static const enum mlxsw_afk_element mlxsw_sp2_mr_tcam_usage_ipv6[] = { +- MLXSW_AFK_ELEMENT_VIRT_ROUTER_MSB, +- MLXSW_AFK_ELEMENT_VIRT_ROUTER_LSB, ++ MLXSW_AFK_ELEMENT_VIRT_ROUTER, + MLXSW_AFK_ELEMENT_SRC_IP_96_127, + MLXSW_AFK_ELEMENT_SRC_IP_64_95, + MLXSW_AFK_ELEMENT_SRC_IP_32_63, +@@ -189,11 +187,8 @@ mlxsw_sp2_mr_tcam_rule_parse(struct mlxsw_sp_acl_rule *rule, + + rulei = mlxsw_sp_acl_rule_rulei(rule); + rulei->priority = priority; +- mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_VIRT_ROUTER_LSB, +- key->vrid, GENMASK(7, 0)); +- mlxsw_sp_acl_rulei_keymask_u32(rulei, +- MLXSW_AFK_ELEMENT_VIRT_ROUTER_MSB, +- key->vrid >> 8, GENMASK(3, 0)); ++ mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_VIRT_ROUTER, ++ key->vrid, GENMASK(11, 0)); + switch (key->proto) { + case MLXSW_SP_L3_PROTO_IPV4: + return mlxsw_sp2_mr_tcam_rule_parse4(rulei, key); +diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c +index cb746a43b24b3..cc00c8d69eb77 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c +@@ -171,9 +171,8 @@ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_2[] = { + MLXSW_AFK_ELEMENT_INST_U32(IP_PROTO, 0x04, 16, 8), + }; + +-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_4[] = { +- MLXSW_AFK_ELEMENT_INST_U32(VIRT_ROUTER_LSB, 0x04, 24, 8), +- MLXSW_AFK_ELEMENT_INST_EXT_U32(VIRT_ROUTER_MSB, 0x00, 0, 3, 0, true), ++static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_5[] = { ++ MLXSW_AFK_ELEMENT_INST_EXT_U32(VIRT_ROUTER, 0x04, 20, 11, 0, true), + }; + + static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_0[] = { +@@ -220,7 +219,7 @@ static const struct mlxsw_afk_block mlxsw_sp2_afk_blocks[] = { + MLXSW_AFK_BLOCK(0x38, mlxsw_sp_afk_element_info_ipv4_0), + MLXSW_AFK_BLOCK(0x39, mlxsw_sp_afk_element_info_ipv4_1), + MLXSW_AFK_BLOCK(0x3A, mlxsw_sp_afk_element_info_ipv4_2), +- MLXSW_AFK_BLOCK(0x3C, mlxsw_sp_afk_element_info_ipv4_4), ++ MLXSW_AFK_BLOCK(0x3D, mlxsw_sp_afk_element_info_ipv4_5), + MLXSW_AFK_BLOCK(0x40, mlxsw_sp_afk_element_info_ipv6_0), + MLXSW_AFK_BLOCK(0x41, mlxsw_sp_afk_element_info_ipv6_1), + MLXSW_AFK_BLOCK(0x42, mlxsw_sp_afk_element_info_ipv6_2), +@@ -323,8 +322,7 @@ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_5b[] = { + }; + + static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_4b[] = { +- MLXSW_AFK_ELEMENT_INST_U32(VIRT_ROUTER_LSB, 0x04, 13, 8), +- MLXSW_AFK_ELEMENT_INST_U32(VIRT_ROUTER_MSB, 0x04, 21, 4), ++ MLXSW_AFK_ELEMENT_INST_U32(VIRT_ROUTER, 0x04, 13, 12), + }; + + static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_2b[] = { +-- +2.43.0 + diff --git a/queue-6.6/mlxsw-edit-ipv6-key-blocks-to-use-one-less-block-for.patch b/queue-6.6/mlxsw-edit-ipv6-key-blocks-to-use-one-less-block-for.patch new file mode 100644 index 00000000000..de47e5d8c7d --- /dev/null +++ b/queue-6.6/mlxsw-edit-ipv6-key-blocks-to-use-one-less-block-for.patch @@ -0,0 +1,172 @@ +From a288b3d342fe307ffd9140160e95249b86d03744 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 Sep 2023 17:42:56 +0200 +Subject: mlxsw: Edit IPv6 key blocks to use one less block for multicast + forwarding + +From: Amit Cohen + +[ Upstream commit 92953e7aab013719aa8974805614c0bc11361026 ] + +Two ACL regions that are configured by the driver during initialization are +the ones used for IPv4 and IPv6 multicast forwarding. Entries residing +in these two regions match on the {SIP, DIP, VRID} key elements. + +Currently for IPv6 region, 9 key blocks are used: +* 4 for SIP - 'ipv4_1', 'ipv6_{3,4,5}' +* 4 for DIP - 'ipv4_0', 'ipv6_{0,1,2/2b}' +* 1 for VRID - 'ipv4_4b' + +This can be improved by reducing the amount key blocks needed for +the IPv6 region to 8. It is possible to use key blocks that mix subsets of +the VRID element with subsets of the DIP element. +The following key blocks can be used: +* 4 for SIP - 'ipv4_1', 'ipv6_{3,4,5}' +* 1 for subset of DIP - 'ipv4_0' +* 3 for the rest of DIP and subsets of VRID - 'ipv6_{0,1,2/2b}' + +To make this happen, add VRID sub-elements as part of existing keys - +'ipv6_{0,1,2/2b}'. Note that one of the sub-elements is called +VRID_ROUTER_MSB and does not contain bit numbers like the rest, as for +Spectrum < 4 this element represents bits 8-10 and for Spectrum-4 it +represents bits 8-11. + +Breaking VRID into 3 sub-elements makes the driver use one less block in +IPv6 region for multicast forwarding. The sub-elements can be filled in +blocks that are used for destination IP. + +The algorithm in the driver that chooses which key blocks will be used is +lazy and not the optimal one. It searches the block that contains the most +elements that are required, chooses it, removes the elements that appear +in the chosen block and starts again searching the block that contains the +most elements. + +When key block 'ipv4_4' is defined, the algorithm might choose it, as it +contains 2 sub-elements of VRID, then 8 blocks must be chosen for SIP and +DIP and we get 9 blocks to match on {SIP, DIP, VRID}. That is why we had to +remove key block 'ipv4_4' in a previous patch and use key block that +contains one field for VRID. + +This improvement was tested and indeed 8 blocks are used instead of 9. + +Signed-off-by: Amit Cohen +Reviewed-by: Ido Schimmel +Signed-off-by: Petr Machata +Signed-off-by: David S. Miller +Stable-dep-of: 217bbf156f93 ("mlxsw: spectrum_acl_flex_keys: Use correct key block on Spectrum-4") +Signed-off-by: Sasha Levin +--- + .../ethernet/mellanox/mlxsw/core_acl_flex_keys.c | 3 +++ + .../ethernet/mellanox/mlxsw/core_acl_flex_keys.h | 3 +++ + .../ethernet/mellanox/mlxsw/spectrum2_mr_tcam.c | 15 ++++++++++++--- + .../mellanox/mlxsw/spectrum_acl_flex_keys.c | 4 ++++ + 4 files changed, 22 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c +index 5fa3800940c89..654dafc9b54d3 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c +@@ -44,6 +44,9 @@ static const struct mlxsw_afk_element_info mlxsw_afk_element_infos[] = { + MLXSW_AFK_ELEMENT_INFO_BUF(DST_IP_0_31, 0x3C, 4), + MLXSW_AFK_ELEMENT_INFO_U32(FDB_MISS, 0x40, 0, 1), + MLXSW_AFK_ELEMENT_INFO_U32(L4_PORT_RANGE, 0x40, 1, 16), ++ MLXSW_AFK_ELEMENT_INFO_U32(VIRT_ROUTER_0_3, 0x40, 17, 4), ++ MLXSW_AFK_ELEMENT_INFO_U32(VIRT_ROUTER_4_7, 0x40, 21, 4), ++ MLXSW_AFK_ELEMENT_INFO_U32(VIRT_ROUTER_MSB, 0x40, 25, 4), + }; + + struct mlxsw_afk { +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h +index 75e9bbc361701..1c76aa3ffab72 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h +@@ -36,6 +36,9 @@ enum mlxsw_afk_element { + MLXSW_AFK_ELEMENT_VIRT_ROUTER, + MLXSW_AFK_ELEMENT_FDB_MISS, + MLXSW_AFK_ELEMENT_L4_PORT_RANGE, ++ MLXSW_AFK_ELEMENT_VIRT_ROUTER_0_3, ++ MLXSW_AFK_ELEMENT_VIRT_ROUTER_4_7, ++ MLXSW_AFK_ELEMENT_VIRT_ROUTER_MSB, + MLXSW_AFK_ELEMENT_MAX, + }; + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum2_mr_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum2_mr_tcam.c +index 2efcc9372d4e6..99eeafdc8d1e4 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum2_mr_tcam.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum2_mr_tcam.c +@@ -88,7 +88,9 @@ static void mlxsw_sp2_mr_tcam_ipv4_fini(struct mlxsw_sp2_mr_tcam *mr_tcam) + } + + static const enum mlxsw_afk_element mlxsw_sp2_mr_tcam_usage_ipv6[] = { +- MLXSW_AFK_ELEMENT_VIRT_ROUTER, ++ MLXSW_AFK_ELEMENT_VIRT_ROUTER_0_3, ++ MLXSW_AFK_ELEMENT_VIRT_ROUTER_4_7, ++ MLXSW_AFK_ELEMENT_VIRT_ROUTER_MSB, + MLXSW_AFK_ELEMENT_SRC_IP_96_127, + MLXSW_AFK_ELEMENT_SRC_IP_64_95, + MLXSW_AFK_ELEMENT_SRC_IP_32_63, +@@ -140,6 +142,8 @@ static void + mlxsw_sp2_mr_tcam_rule_parse4(struct mlxsw_sp_acl_rule_info *rulei, + struct mlxsw_sp_mr_route_key *key) + { ++ mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_VIRT_ROUTER, ++ key->vrid, GENMASK(11, 0)); + mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_0_31, + (char *) &key->source.addr4, + (char *) &key->source_mask.addr4, 4); +@@ -152,6 +156,13 @@ static void + mlxsw_sp2_mr_tcam_rule_parse6(struct mlxsw_sp_acl_rule_info *rulei, + struct mlxsw_sp_mr_route_key *key) + { ++ mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_VIRT_ROUTER_0_3, ++ key->vrid, GENMASK(3, 0)); ++ mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_VIRT_ROUTER_4_7, ++ key->vrid >> 4, GENMASK(3, 0)); ++ mlxsw_sp_acl_rulei_keymask_u32(rulei, ++ MLXSW_AFK_ELEMENT_VIRT_ROUTER_MSB, ++ key->vrid >> 8, GENMASK(3, 0)); + mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_96_127, + &key->source.addr6.s6_addr[0x0], + &key->source_mask.addr6.s6_addr[0x0], 4); +@@ -187,8 +198,6 @@ mlxsw_sp2_mr_tcam_rule_parse(struct mlxsw_sp_acl_rule *rule, + + rulei = mlxsw_sp_acl_rule_rulei(rule); + rulei->priority = priority; +- mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_VIRT_ROUTER, +- key->vrid, GENMASK(11, 0)); + switch (key->proto) { + case MLXSW_SP_L3_PROTO_IPV4: + return mlxsw_sp2_mr_tcam_rule_parse4(rulei, key); +diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c +index 7d66c4f2deeaa..4b3564f5fd652 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c +@@ -176,14 +176,17 @@ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_5[] = { + }; + + static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_0[] = { ++ MLXSW_AFK_ELEMENT_INST_U32(VIRT_ROUTER_0_3, 0x00, 0, 4), + MLXSW_AFK_ELEMENT_INST_BUF(DST_IP_32_63, 0x04, 4), + }; + + static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_1[] = { ++ MLXSW_AFK_ELEMENT_INST_U32(VIRT_ROUTER_4_7, 0x00, 0, 4), + MLXSW_AFK_ELEMENT_INST_BUF(DST_IP_64_95, 0x04, 4), + }; + + static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_2[] = { ++ MLXSW_AFK_ELEMENT_INST_EXT_U32(VIRT_ROUTER_MSB, 0x00, 0, 3, 0, true), + MLXSW_AFK_ELEMENT_INST_BUF(DST_IP_96_127, 0x04, 4), + }; + +@@ -326,6 +329,7 @@ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_5b[] = { + }; + + static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_2b[] = { ++ MLXSW_AFK_ELEMENT_INST_U32(VIRT_ROUTER_MSB, 0x00, 0, 4), + MLXSW_AFK_ELEMENT_INST_BUF(DST_IP_96_127, 0x04, 4), + }; + +-- +2.43.0 + diff --git a/queue-6.6/mlxsw-mark-high-entropy-key-blocks.patch b/queue-6.6/mlxsw-mark-high-entropy-key-blocks.patch new file mode 100644 index 00000000000..cd31b2ea779 --- /dev/null +++ b/queue-6.6/mlxsw-mark-high-entropy-key-blocks.patch @@ -0,0 +1,100 @@ +From 654d26c2edfba386e4aac9a80e8da447cd36318b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Oct 2023 13:25:26 +0200 +Subject: mlxsw: Mark high entropy key blocks + +From: Amit Cohen + +[ Upstream commit cad6431b867507779c41b00baaf18382467ef0a0 ] + +For 12 key blocks in the A-TCAM, rules are split into two records, which +constitute two lookups. The two records are linked using a +"large entry key ID". + +Due to a Spectrum-4 hardware issue, KVD entries that correspond to key +blocks 0 to 5 of 12 key blocks A-TCAM entries will be placed in the same +KVD pipe if they only differ in their "large entry key ID", as it is +ignored. This results in a reduced scale. To reduce the probability of this +issue, we can place key blocks with high entropy in blocks 0 to 5. The idea +is to place blocks that are changed often in blocks 0 to 5, for +example, key blocks that match on IPv4 addresses or the LSBs of IPv6 +addresses. Such placement will reduce the probability of these blocks to be +same. + +Mark several blocks with 'high_entropy' flag, so later we will take into +account this flag and place them in blocks 0 to 5. + +Signed-off-by: Amit Cohen +Reviewed-by: Ido Schimmel +Signed-off-by: Petr Machata +Signed-off-by: David S. Miller +Stable-dep-of: 217bbf156f93 ("mlxsw: spectrum_acl_flex_keys: Use correct key block on Spectrum-4") +Signed-off-by: Sasha Levin +--- + .../net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h | 9 +++++++++ + .../ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c | 12 ++++++------ + 2 files changed, 15 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h +index 1c76aa3ffab72..98a05598178b3 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h +@@ -119,6 +119,7 @@ struct mlxsw_afk_block { + u16 encoding; /* block ID */ + struct mlxsw_afk_element_inst *instances; + unsigned int instances_count; ++ bool high_entropy; + }; + + #define MLXSW_AFK_BLOCK(_encoding, _instances) \ +@@ -128,6 +129,14 @@ struct mlxsw_afk_block { + .instances_count = ARRAY_SIZE(_instances), \ + } + ++#define MLXSW_AFK_BLOCK_HIGH_ENTROPY(_encoding, _instances) \ ++ { \ ++ .encoding = _encoding, \ ++ .instances = _instances, \ ++ .instances_count = ARRAY_SIZE(_instances), \ ++ .high_entropy = true, \ ++ } ++ + struct mlxsw_afk_element_usage { + DECLARE_BITMAP(usage, MLXSW_AFK_ELEMENT_MAX); + }; +diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c +index 4b3564f5fd652..eaad786056027 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c +@@ -334,14 +334,14 @@ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_2b[] = { + }; + + static const struct mlxsw_afk_block mlxsw_sp4_afk_blocks[] = { +- MLXSW_AFK_BLOCK(0x10, mlxsw_sp_afk_element_info_mac_0), +- MLXSW_AFK_BLOCK(0x11, mlxsw_sp_afk_element_info_mac_1), ++ MLXSW_AFK_BLOCK_HIGH_ENTROPY(0x10, mlxsw_sp_afk_element_info_mac_0), ++ MLXSW_AFK_BLOCK_HIGH_ENTROPY(0x11, mlxsw_sp_afk_element_info_mac_1), + MLXSW_AFK_BLOCK(0x12, mlxsw_sp_afk_element_info_mac_2), + MLXSW_AFK_BLOCK(0x13, mlxsw_sp_afk_element_info_mac_3), + MLXSW_AFK_BLOCK(0x14, mlxsw_sp_afk_element_info_mac_4), +- MLXSW_AFK_BLOCK(0x1A, mlxsw_sp_afk_element_info_mac_5b), +- MLXSW_AFK_BLOCK(0x38, mlxsw_sp_afk_element_info_ipv4_0), +- MLXSW_AFK_BLOCK(0x39, mlxsw_sp_afk_element_info_ipv4_1), ++ MLXSW_AFK_BLOCK_HIGH_ENTROPY(0x1A, mlxsw_sp_afk_element_info_mac_5b), ++ MLXSW_AFK_BLOCK_HIGH_ENTROPY(0x38, mlxsw_sp_afk_element_info_ipv4_0), ++ MLXSW_AFK_BLOCK_HIGH_ENTROPY(0x39, mlxsw_sp_afk_element_info_ipv4_1), + MLXSW_AFK_BLOCK(0x3A, mlxsw_sp_afk_element_info_ipv4_2), + MLXSW_AFK_BLOCK(0x36, mlxsw_sp_afk_element_info_ipv4_5b), + MLXSW_AFK_BLOCK(0x40, mlxsw_sp_afk_element_info_ipv6_0), +@@ -350,7 +350,7 @@ static const struct mlxsw_afk_block mlxsw_sp4_afk_blocks[] = { + MLXSW_AFK_BLOCK(0x43, mlxsw_sp_afk_element_info_ipv6_3), + MLXSW_AFK_BLOCK(0x44, mlxsw_sp_afk_element_info_ipv6_4), + MLXSW_AFK_BLOCK(0x45, mlxsw_sp_afk_element_info_ipv6_5), +- MLXSW_AFK_BLOCK(0x90, mlxsw_sp_afk_element_info_l4_0), ++ MLXSW_AFK_BLOCK_HIGH_ENTROPY(0x90, mlxsw_sp_afk_element_info_l4_0), + MLXSW_AFK_BLOCK(0x92, mlxsw_sp_afk_element_info_l4_2), + }; + +-- +2.43.0 + diff --git a/queue-6.6/mlxsw-spectrum_acl_flex_keys-add-ipv4_5b-flex-key.patch b/queue-6.6/mlxsw-spectrum_acl_flex_keys-add-ipv4_5b-flex-key.patch new file mode 100644 index 00000000000..607094bf65a --- /dev/null +++ b/queue-6.6/mlxsw-spectrum_acl_flex_keys-add-ipv4_5b-flex-key.patch @@ -0,0 +1,50 @@ +From f70f6d644ac9cbc987903d09817dc596eeb16ea7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 Sep 2023 17:42:55 +0200 +Subject: mlxsw: spectrum_acl_flex_keys: Add 'ipv4_5b' flex key + +From: Amit Cohen + +[ Upstream commit c6caabdf3e0cc50ba4a44bebc82cda5551d81d4f ] + +The previous patch replaced the key block 'ipv4_4' with 'ipv4_5'. The +corresponding block for Spectrum-4 is 'ipv4_4b'. To be consistent, replace +key block 'ipv4_4b' with 'ipv4_5b'. + +Signed-off-by: Amit Cohen +Reviewed-by: Ido Schimmel +Signed-off-by: Petr Machata +Signed-off-by: David S. Miller +Stable-dep-of: 217bbf156f93 ("mlxsw: spectrum_acl_flex_keys: Use correct key block on Spectrum-4") +Signed-off-by: Sasha Levin +--- + .../net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c +index cc00c8d69eb77..7d66c4f2deeaa 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c +@@ -321,8 +321,8 @@ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_5b[] = { + MLXSW_AFK_ELEMENT_INST_EXT_U32(SRC_SYS_PORT, 0x04, 0, 9, -1, true), /* RX_ACL_SYSTEM_PORT */ + }; + +-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_4b[] = { +- MLXSW_AFK_ELEMENT_INST_U32(VIRT_ROUTER, 0x04, 13, 12), ++static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_5b[] = { ++ MLXSW_AFK_ELEMENT_INST_U32(VIRT_ROUTER, 0x04, 20, 12), + }; + + static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_2b[] = { +@@ -339,7 +339,7 @@ static const struct mlxsw_afk_block mlxsw_sp4_afk_blocks[] = { + MLXSW_AFK_BLOCK(0x38, mlxsw_sp_afk_element_info_ipv4_0), + MLXSW_AFK_BLOCK(0x39, mlxsw_sp_afk_element_info_ipv4_1), + MLXSW_AFK_BLOCK(0x3A, mlxsw_sp_afk_element_info_ipv4_2), +- MLXSW_AFK_BLOCK(0x35, mlxsw_sp_afk_element_info_ipv4_4b), ++ MLXSW_AFK_BLOCK(0x36, mlxsw_sp_afk_element_info_ipv4_5b), + MLXSW_AFK_BLOCK(0x40, mlxsw_sp_afk_element_info_ipv6_0), + MLXSW_AFK_BLOCK(0x41, mlxsw_sp_afk_element_info_ipv6_1), + MLXSW_AFK_BLOCK(0x47, mlxsw_sp_afk_element_info_ipv6_2b), +-- +2.43.0 + diff --git a/queue-6.6/mlxsw-spectrum_acl_flex_keys-constify-struct-mlxsw_a.patch b/queue-6.6/mlxsw-spectrum_acl_flex_keys-constify-struct-mlxsw_a.patch new file mode 100644 index 00000000000..c0dc341bfcd --- /dev/null +++ b/queue-6.6/mlxsw-spectrum_acl_flex_keys-constify-struct-mlxsw_a.patch @@ -0,0 +1,312 @@ +From 181ff20aab66e26df125138b1f4ff3e7cabd1ac2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 4 Oct 2024 07:26:05 +0200 +Subject: mlxsw: spectrum_acl_flex_keys: Constify struct mlxsw_afk_element_inst + +From: Christophe JAILLET + +[ Upstream commit bec2a32145d5cc066df29182fa0e5b0d4329b1a1 ] + +'struct mlxsw_afk_element_inst' are not modified in these drivers. + +Constifying these structures moves some data to a read-only section, so +increases overall security. + +Update a few functions and struct mlxsw_afk_block accordingly. + +On a x86_64, with allmodconfig, as an example: +Before: +====== + text data bss dec hex filename + 4278 4032 0 8310 2076 drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.o + +After: +===== + text data bss dec hex filename + 7934 352 0 8286 205e drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.o + +Signed-off-by: Christophe JAILLET +Reviewed-by: Simon Horman +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/8ccfc7bfb2365dcee5b03c81ebe061a927d6da2e.1727541677.git.christophe.jaillet@wanadoo.fr +Signed-off-by: Jakub Kicinski +Stable-dep-of: 217bbf156f93 ("mlxsw: spectrum_acl_flex_keys: Use correct key block on Spectrum-4") +Signed-off-by: Sasha Levin +--- + .../mellanox/mlxsw/core_acl_flex_keys.c | 6 +- + .../mellanox/mlxsw/core_acl_flex_keys.h | 2 +- + .../mellanox/mlxsw/spectrum_acl_flex_keys.c | 66 +++++++++---------- + 3 files changed, 37 insertions(+), 37 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c +index 654dafc9b54d3..57a1a55856a51 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c +@@ -67,7 +67,7 @@ static bool mlxsw_afk_blocks_check(struct mlxsw_afk *mlxsw_afk) + + for (j = 0; j < block->instances_count; j++) { + const struct mlxsw_afk_element_info *elinfo; +- struct mlxsw_afk_element_inst *elinst; ++ const struct mlxsw_afk_element_inst *elinst; + + elinst = &block->instances[j]; + elinfo = &mlxsw_afk_element_infos[elinst->element]; +@@ -153,7 +153,7 @@ static void mlxsw_afk_picker_count_hits(struct mlxsw_afk *mlxsw_afk, + const struct mlxsw_afk_block *block = &mlxsw_afk->blocks[i]; + + for (j = 0; j < block->instances_count; j++) { +- struct mlxsw_afk_element_inst *elinst; ++ const struct mlxsw_afk_element_inst *elinst; + + elinst = &block->instances[j]; + if (elinst->element == element) { +@@ -336,7 +336,7 @@ mlxsw_afk_block_elinst_get(const struct mlxsw_afk_block *block, + int i; + + for (i = 0; i < block->instances_count; i++) { +- struct mlxsw_afk_element_inst *elinst; ++ const struct mlxsw_afk_element_inst *elinst; + + elinst = &block->instances[i]; + if (elinst->element == element) +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h +index 98a05598178b3..5aa1afb3f2ca8 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h +@@ -117,7 +117,7 @@ struct mlxsw_afk_element_inst { /* element instance in actual block */ + + struct mlxsw_afk_block { + u16 encoding; /* block ID */ +- struct mlxsw_afk_element_inst *instances; ++ const struct mlxsw_afk_element_inst *instances; + unsigned int instances_count; + bool high_entropy; + }; +diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c +index eaad786056027..6fe185ea6732c 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c +@@ -7,7 +7,7 @@ + #include "item.h" + #include "core_acl_flex_keys.h" + +-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l2_dmac[] = { ++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l2_dmac[] = { + MLXSW_AFK_ELEMENT_INST_BUF(DMAC_32_47, 0x00, 2), + MLXSW_AFK_ELEMENT_INST_BUF(DMAC_0_31, 0x02, 4), + MLXSW_AFK_ELEMENT_INST_U32(PCP, 0x08, 13, 3), +@@ -15,7 +15,7 @@ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l2_dmac[] = { + MLXSW_AFK_ELEMENT_INST_U32(SRC_SYS_PORT, 0x0C, 0, 16), + }; + +-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l2_smac[] = { ++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l2_smac[] = { + MLXSW_AFK_ELEMENT_INST_BUF(SMAC_32_47, 0x00, 2), + MLXSW_AFK_ELEMENT_INST_BUF(SMAC_0_31, 0x02, 4), + MLXSW_AFK_ELEMENT_INST_U32(PCP, 0x08, 13, 3), +@@ -23,27 +23,27 @@ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l2_smac[] = { + MLXSW_AFK_ELEMENT_INST_U32(SRC_SYS_PORT, 0x0C, 0, 16), + }; + +-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l2_smac_ex[] = { ++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l2_smac_ex[] = { + MLXSW_AFK_ELEMENT_INST_BUF(SMAC_32_47, 0x02, 2), + MLXSW_AFK_ELEMENT_INST_BUF(SMAC_0_31, 0x04, 4), + MLXSW_AFK_ELEMENT_INST_U32(ETHERTYPE, 0x0C, 0, 16), + }; + +-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_sip[] = { ++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_sip[] = { + MLXSW_AFK_ELEMENT_INST_BUF(SRC_IP_0_31, 0x00, 4), + MLXSW_AFK_ELEMENT_INST_U32(L4_PORT_RANGE, 0x04, 16, 16), + MLXSW_AFK_ELEMENT_INST_U32(IP_PROTO, 0x08, 0, 8), + MLXSW_AFK_ELEMENT_INST_U32(SRC_SYS_PORT, 0x0C, 0, 16), + }; + +-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_dip[] = { ++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_dip[] = { + MLXSW_AFK_ELEMENT_INST_BUF(DST_IP_0_31, 0x00, 4), + MLXSW_AFK_ELEMENT_INST_U32(L4_PORT_RANGE, 0x04, 16, 16), + MLXSW_AFK_ELEMENT_INST_U32(IP_PROTO, 0x08, 0, 8), + MLXSW_AFK_ELEMENT_INST_U32(SRC_SYS_PORT, 0x0C, 0, 16), + }; + +-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4[] = { ++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4[] = { + MLXSW_AFK_ELEMENT_INST_BUF(SRC_IP_0_31, 0x00, 4), + MLXSW_AFK_ELEMENT_INST_U32(IP_ECN, 0x04, 4, 2), + MLXSW_AFK_ELEMENT_INST_U32(IP_TTL_, 0x04, 24, 8), +@@ -51,35 +51,35 @@ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4[] = { + MLXSW_AFK_ELEMENT_INST_U32(TCP_FLAGS, 0x08, 8, 9), /* TCP_CONTROL+TCP_ECN */ + }; + +-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_ex[] = { ++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_ex[] = { + MLXSW_AFK_ELEMENT_INST_U32(VID, 0x00, 0, 12), + MLXSW_AFK_ELEMENT_INST_U32(PCP, 0x08, 29, 3), + MLXSW_AFK_ELEMENT_INST_U32(SRC_L4_PORT, 0x08, 0, 16), + MLXSW_AFK_ELEMENT_INST_U32(DST_L4_PORT, 0x0C, 0, 16), + }; + +-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_dip[] = { ++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_dip[] = { + MLXSW_AFK_ELEMENT_INST_BUF(DST_IP_32_63, 0x00, 4), + MLXSW_AFK_ELEMENT_INST_BUF(DST_IP_0_31, 0x04, 4), + }; + +-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_ex1[] = { ++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_ex1[] = { + MLXSW_AFK_ELEMENT_INST_BUF(DST_IP_96_127, 0x00, 4), + MLXSW_AFK_ELEMENT_INST_BUF(DST_IP_64_95, 0x04, 4), + MLXSW_AFK_ELEMENT_INST_U32(IP_PROTO, 0x08, 0, 8), + }; + +-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_sip[] = { ++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_sip[] = { + MLXSW_AFK_ELEMENT_INST_BUF(SRC_IP_32_63, 0x00, 4), + MLXSW_AFK_ELEMENT_INST_BUF(SRC_IP_0_31, 0x04, 4), + }; + +-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_sip_ex[] = { ++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_sip_ex[] = { + MLXSW_AFK_ELEMENT_INST_BUF(SRC_IP_96_127, 0x00, 4), + MLXSW_AFK_ELEMENT_INST_BUF(SRC_IP_64_95, 0x04, 4), + }; + +-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_packet_type[] = { ++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_packet_type[] = { + MLXSW_AFK_ELEMENT_INST_U32(ETHERTYPE, 0x00, 0, 16), + }; + +@@ -124,90 +124,90 @@ const struct mlxsw_afk_ops mlxsw_sp1_afk_ops = { + .clear_block = mlxsw_sp1_afk_clear_block, + }; + +-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_0[] = { ++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_0[] = { + MLXSW_AFK_ELEMENT_INST_U32(FDB_MISS, 0x00, 3, 1), + MLXSW_AFK_ELEMENT_INST_BUF(DMAC_0_31, 0x04, 4), + }; + +-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_1[] = { ++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_1[] = { + MLXSW_AFK_ELEMENT_INST_U32(FDB_MISS, 0x00, 3, 1), + MLXSW_AFK_ELEMENT_INST_BUF(SMAC_0_31, 0x04, 4), + }; + +-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_2[] = { ++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_2[] = { + MLXSW_AFK_ELEMENT_INST_BUF(SMAC_32_47, 0x04, 2), + MLXSW_AFK_ELEMENT_INST_BUF(DMAC_32_47, 0x06, 2), + }; + +-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_3[] = { ++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_3[] = { + MLXSW_AFK_ELEMENT_INST_U32(PCP, 0x00, 0, 3), + MLXSW_AFK_ELEMENT_INST_U32(VID, 0x04, 16, 12), + MLXSW_AFK_ELEMENT_INST_BUF(DMAC_32_47, 0x06, 2), + }; + +-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_4[] = { ++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_4[] = { + MLXSW_AFK_ELEMENT_INST_U32(PCP, 0x00, 0, 3), + MLXSW_AFK_ELEMENT_INST_U32(VID, 0x04, 16, 12), + MLXSW_AFK_ELEMENT_INST_U32(ETHERTYPE, 0x04, 0, 16), + }; + +-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_5[] = { ++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_5[] = { + MLXSW_AFK_ELEMENT_INST_U32(VID, 0x04, 16, 12), + MLXSW_AFK_ELEMENT_INST_EXT_U32(SRC_SYS_PORT, 0x04, 0, 8, -1, true), /* RX_ACL_SYSTEM_PORT */ + }; + +-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_0[] = { ++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_0[] = { + MLXSW_AFK_ELEMENT_INST_BUF(DST_IP_0_31, 0x04, 4), + }; + +-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_1[] = { ++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_1[] = { + MLXSW_AFK_ELEMENT_INST_BUF(SRC_IP_0_31, 0x04, 4), + }; + +-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_2[] = { ++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_2[] = { + MLXSW_AFK_ELEMENT_INST_U32(IP_DSCP, 0x04, 0, 6), + MLXSW_AFK_ELEMENT_INST_U32(IP_ECN, 0x04, 6, 2), + MLXSW_AFK_ELEMENT_INST_U32(IP_TTL_, 0x04, 8, 8), + MLXSW_AFK_ELEMENT_INST_U32(IP_PROTO, 0x04, 16, 8), + }; + +-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_5[] = { ++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_5[] = { + MLXSW_AFK_ELEMENT_INST_EXT_U32(VIRT_ROUTER, 0x04, 20, 11, 0, true), + }; + +-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_0[] = { ++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_0[] = { + MLXSW_AFK_ELEMENT_INST_U32(VIRT_ROUTER_0_3, 0x00, 0, 4), + MLXSW_AFK_ELEMENT_INST_BUF(DST_IP_32_63, 0x04, 4), + }; + +-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_1[] = { ++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_1[] = { + MLXSW_AFK_ELEMENT_INST_U32(VIRT_ROUTER_4_7, 0x00, 0, 4), + MLXSW_AFK_ELEMENT_INST_BUF(DST_IP_64_95, 0x04, 4), + }; + +-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_2[] = { ++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_2[] = { + MLXSW_AFK_ELEMENT_INST_EXT_U32(VIRT_ROUTER_MSB, 0x00, 0, 3, 0, true), + MLXSW_AFK_ELEMENT_INST_BUF(DST_IP_96_127, 0x04, 4), + }; + +-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_3[] = { ++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_3[] = { + MLXSW_AFK_ELEMENT_INST_BUF(SRC_IP_32_63, 0x04, 4), + }; + +-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_4[] = { ++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_4[] = { + MLXSW_AFK_ELEMENT_INST_BUF(SRC_IP_64_95, 0x04, 4), + }; + +-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_5[] = { ++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_5[] = { + MLXSW_AFK_ELEMENT_INST_BUF(SRC_IP_96_127, 0x04, 4), + }; + +-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l4_0[] = { ++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l4_0[] = { + MLXSW_AFK_ELEMENT_INST_U32(SRC_L4_PORT, 0x04, 16, 16), + MLXSW_AFK_ELEMENT_INST_U32(DST_L4_PORT, 0x04, 0, 16), + }; + +-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l4_2[] = { ++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l4_2[] = { + MLXSW_AFK_ELEMENT_INST_U32(TCP_FLAGS, 0x04, 16, 9), /* TCP_CONTROL + TCP_ECN */ + MLXSW_AFK_ELEMENT_INST_U32(L4_PORT_RANGE, 0x04, 0, 16), + }; +@@ -319,16 +319,16 @@ const struct mlxsw_afk_ops mlxsw_sp2_afk_ops = { + .clear_block = mlxsw_sp2_afk_clear_block, + }; + +-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_5b[] = { ++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_5b[] = { + MLXSW_AFK_ELEMENT_INST_U32(VID, 0x04, 18, 12), + MLXSW_AFK_ELEMENT_INST_EXT_U32(SRC_SYS_PORT, 0x04, 0, 9, -1, true), /* RX_ACL_SYSTEM_PORT */ + }; + +-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_5b[] = { ++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_5b[] = { + MLXSW_AFK_ELEMENT_INST_U32(VIRT_ROUTER, 0x04, 20, 12), + }; + +-static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_2b[] = { ++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_2b[] = { + MLXSW_AFK_ELEMENT_INST_U32(VIRT_ROUTER_MSB, 0x00, 0, 4), + MLXSW_AFK_ELEMENT_INST_BUF(DST_IP_96_127, 0x04, 4), + }; +-- +2.43.0 + diff --git a/queue-6.6/mlxsw-spectrum_acl_flex_keys-use-correct-key-block-o.patch b/queue-6.6/mlxsw-spectrum_acl_flex_keys-use-correct-key-block-o.patch new file mode 100644 index 00000000000..2d84e1f9399 --- /dev/null +++ b/queue-6.6/mlxsw-spectrum_acl_flex_keys-use-correct-key-block-o.patch @@ -0,0 +1,58 @@ +From 15c1e15da8ca17eb7e5af14c90cddfd968cf4061 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Dec 2024 16:16:05 +0100 +Subject: mlxsw: spectrum_acl_flex_keys: Use correct key block on Spectrum-4 + +From: Ido Schimmel + +[ Upstream commit 217bbf156f93ada86b91617489e7ba8a0904233c ] + +The driver is currently using an ACL key block that is not supported by +Spectrum-4. This works because the driver is only using a single field +from this key block which is located in the same offset in the +equivalent Spectrum-4 key block. + +The issue was discovered when the firmware started rejecting the use of +the unsupported key block. The change has been reverted to avoid +breaking users that only update their firmware. + +Nonetheless, fix the issue by using the correct key block. + +Fixes: 07ff135958dd ("mlxsw: Introduce flex key elements for Spectrum-4") +Signed-off-by: Ido Schimmel +Reviewed-by: Petr Machata +Signed-off-by: Petr Machata +Link: https://patch.msgid.link/35e72c97bdd3bc414fb8e4d747e5fb5d26c29658.1733237440.git.petrm@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c +index 6fe185ea6732c..1850a975b3804 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c +@@ -324,6 +324,10 @@ static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_5b[] = + MLXSW_AFK_ELEMENT_INST_EXT_U32(SRC_SYS_PORT, 0x04, 0, 9, -1, true), /* RX_ACL_SYSTEM_PORT */ + }; + ++static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_1b[] = { ++ MLXSW_AFK_ELEMENT_INST_BUF(SRC_IP_0_31, 0x04, 4), ++}; ++ + static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_5b[] = { + MLXSW_AFK_ELEMENT_INST_U32(VIRT_ROUTER, 0x04, 20, 12), + }; +@@ -341,7 +345,7 @@ static const struct mlxsw_afk_block mlxsw_sp4_afk_blocks[] = { + MLXSW_AFK_BLOCK(0x14, mlxsw_sp_afk_element_info_mac_4), + MLXSW_AFK_BLOCK_HIGH_ENTROPY(0x1A, mlxsw_sp_afk_element_info_mac_5b), + MLXSW_AFK_BLOCK_HIGH_ENTROPY(0x38, mlxsw_sp_afk_element_info_ipv4_0), +- MLXSW_AFK_BLOCK_HIGH_ENTROPY(0x39, mlxsw_sp_afk_element_info_ipv4_1), ++ MLXSW_AFK_BLOCK_HIGH_ENTROPY(0x3F, mlxsw_sp_afk_element_info_ipv4_1b), + MLXSW_AFK_BLOCK(0x3A, mlxsw_sp_afk_element_info_ipv4_2), + MLXSW_AFK_BLOCK(0x36, mlxsw_sp_afk_element_info_ipv4_5b), + MLXSW_AFK_BLOCK(0x40, mlxsw_sp_afk_element_info_ipv6_0), +-- +2.43.0 + diff --git a/queue-6.6/mmc-mtk-sd-fix-devm_clk_get_optional-usage.patch b/queue-6.6/mmc-mtk-sd-fix-devm_clk_get_optional-usage.patch new file mode 100644 index 00000000000..d555a3fe32f --- /dev/null +++ b/queue-6.6/mmc-mtk-sd-fix-devm_clk_get_optional-usage.patch @@ -0,0 +1,40 @@ +From 5303e9ecc70c27ade30475bab0be414db2576057 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Sep 2024 15:49:19 -0700 +Subject: mmc: mtk-sd: fix devm_clk_get_optional usage + +From: Rosen Penev + +[ Upstream commit ed299eda8fbb37cb0e05c7001ab6a6b2627ec087 ] + +This already returns NULL when not found. However, it can return +EPROBE_DEFER and should thus return here. + +Signed-off-by: Rosen Penev +Link: https://lore.kernel.org/r/20240930224919.355359-4-rosenp@gmail.com +Signed-off-by: Ulf Hansson +Stable-dep-of: 2508925fb346 ("mmc: mtk-sd: Fix MMC_CAP2_CRYPTO flag setting") +Signed-off-by: Sasha Levin +--- + drivers/mmc/host/mtk-sd.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c +index a97034388cdff..c5e96a2c079e5 100644 +--- a/drivers/mmc/host/mtk-sd.c ++++ b/drivers/mmc/host/mtk-sd.c +@@ -2711,9 +2711,8 @@ static int msdc_drv_probe(struct platform_device *pdev) + if (!(mmc->caps2 & MMC_CAP2_NO_MMC)) { + host->crypto_clk = devm_clk_get_optional(&pdev->dev, "crypto"); + if (IS_ERR(host->crypto_clk)) +- host->crypto_clk = NULL; +- else +- mmc->caps2 |= MMC_CAP2_CRYPTO; ++ return PTR_ERR(host->crypto_clk); ++ mmc->caps2 |= MMC_CAP2_CRYPTO; + } + + host->irq = platform_get_irq(pdev, 0); +-- +2.43.0 + diff --git a/queue-6.6/mmc-mtk-sd-fix-error-handle-of-probe-function.patch b/queue-6.6/mmc-mtk-sd-fix-error-handle-of-probe-function.patch new file mode 100644 index 00000000000..9b326bb3eca --- /dev/null +++ b/queue-6.6/mmc-mtk-sd-fix-error-handle-of-probe-function.patch @@ -0,0 +1,86 @@ +From 61788dcf2b34924a0af024bf09b4d506d3d16e7b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 7 Nov 2024 20:11:21 +0800 +Subject: mmc: mtk-sd: Fix error handle of probe function + +From: Andy-ld Lu + +[ Upstream commit 291220451c775a054cedc4fab4578a1419eb6256 ] + +In the probe function, it goes to 'release_mem' label and returns after +some procedure failure. But if the clocks (partial or all) have been +enabled previously, they would not be disabled in msdc_runtime_suspend, +since runtime PM is not yet enabled for this case. + +That cause mmc related clocks always on during system suspend and block +suspend flow. Below log is from a SDCard issue of MT8196 chromebook, it +returns -ETIMEOUT while polling clock stable in the msdc_ungate_clock() +and probe failed, but the enabled clocks could not be disabled anyway. + +[ 129.059253] clk_chk_dev_pm_suspend() +[ 129.350119] suspend warning: msdcpll is on +[ 129.354494] [ck_msdc30_1_sel : enabled, 1, 1, 191999939, ck_msdcpll_d2] +[ 129.362787] [ck_msdcpll_d2 : enabled, 1, 1, 191999939, msdcpll] +[ 129.371041] [ck_msdc30_1_ck : enabled, 1, 1, 191999939, ck_msdc30_1_sel] +[ 129.379295] [msdcpll : enabled, 1, 1, 383999878, clk26m] + +Add a new 'release_clk' label and reorder the error handle functions to +make sure the clocks be disabled after probe failure. + +Fixes: ffaea6ebfe9c ("mmc: mtk-sd: Use readl_poll_timeout instead of open-coded polling") +Fixes: 7a2fa8eed936 ("mmc: mtk-sd: use devm_mmc_alloc_host") +Signed-off-by: Andy-ld Lu +Reviewed-by: AngeloGioacchino Del Regno +Cc: stable@vger.kernel.org +Message-ID: <20241107121215.5201-1-andy-ld.lu@mediatek.com> +Signed-off-by: Ulf Hansson +Signed-off-by: Sasha Levin +--- + drivers/mmc/host/mtk-sd.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c +index 9ebf5aa5d9b18..a97034388cdff 100644 +--- a/drivers/mmc/host/mtk-sd.c ++++ b/drivers/mmc/host/mtk-sd.c +@@ -2813,7 +2813,7 @@ static int msdc_drv_probe(struct platform_device *pdev) + ret = msdc_ungate_clock(host); + if (ret) { + dev_err(&pdev->dev, "Cannot ungate clocks!\n"); +- goto release_mem; ++ goto release_clk; + } + msdc_init_hw(host); + +@@ -2823,14 +2823,14 @@ static int msdc_drv_probe(struct platform_device *pdev) + GFP_KERNEL); + if (!host->cq_host) { + ret = -ENOMEM; +- goto release_mem; ++ goto release; + } + host->cq_host->caps |= CQHCI_TASK_DESC_SZ_128; + host->cq_host->mmio = host->base + 0x800; + host->cq_host->ops = &msdc_cmdq_ops; + ret = cqhci_init(host->cq_host, mmc, true); + if (ret) +- goto release_mem; ++ goto release; + mmc->max_segs = 128; + /* cqhci 16bit length */ + /* 0 size, means 65536 so we don't have to -1 here */ +@@ -2857,9 +2857,10 @@ static int msdc_drv_probe(struct platform_device *pdev) + end: + pm_runtime_disable(host->dev); + release: +- platform_set_drvdata(pdev, NULL); + msdc_deinit_hw(host); ++release_clk: + msdc_gate_clock(host); ++ platform_set_drvdata(pdev, NULL); + release_mem: + if (host->dma.gpd) + dma_free_coherent(&pdev->dev, +-- +2.43.0 + diff --git a/queue-6.6/mmc-mtk-sd-fix-mmc_cap2_crypto-flag-setting.patch b/queue-6.6/mmc-mtk-sd-fix-mmc_cap2_crypto-flag-setting.patch new file mode 100644 index 00000000000..8b33204cdfe --- /dev/null +++ b/queue-6.6/mmc-mtk-sd-fix-mmc_cap2_crypto-flag-setting.patch @@ -0,0 +1,45 @@ +From dafce777b6fcd2cd94772bff5136d37b26006622 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 Nov 2024 16:49:31 +0800 +Subject: mmc: mtk-sd: Fix MMC_CAP2_CRYPTO flag setting + +From: Andy-ld Lu + +[ Upstream commit 2508925fb346661bad9f50b497d7ac7d0b6085d0 ] + +Currently, the MMC_CAP2_CRYPTO flag is set by default for eMMC hosts. +However, this flag should not be set for hosts that do not support inline +encryption. + +The 'crypto' clock, as described in the documentation, is used for data +encryption and decryption. Therefore, only hosts that are configured with +this 'crypto' clock should have the MMC_CAP2_CRYPTO flag set. + +Fixes: 7b438d0377fb ("mmc: mtk-sd: add Inline Crypto Engine clock control") +Fixes: ed299eda8fbb ("mmc: mtk-sd: fix devm_clk_get_optional usage") +Signed-off-by: Andy-ld Lu +Cc: stable@vger.kernel.org +Message-ID: <20241111085039.26527-1-andy-ld.lu@mediatek.com> +Signed-off-by: Ulf Hansson +Signed-off-by: Sasha Levin +--- + drivers/mmc/host/mtk-sd.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c +index c5e96a2c079e5..1896bf6746071 100644 +--- a/drivers/mmc/host/mtk-sd.c ++++ b/drivers/mmc/host/mtk-sd.c +@@ -2712,7 +2712,8 @@ static int msdc_drv_probe(struct platform_device *pdev) + host->crypto_clk = devm_clk_get_optional(&pdev->dev, "crypto"); + if (IS_ERR(host->crypto_clk)) + return PTR_ERR(host->crypto_clk); +- mmc->caps2 |= MMC_CAP2_CRYPTO; ++ else if (host->crypto_clk) ++ mmc->caps2 |= MMC_CAP2_CRYPTO; + } + + host->irq = platform_get_irq(pdev, 0); +-- +2.43.0 + diff --git a/queue-6.6/mmc-mtk-sd-use-devm_mmc_alloc_host.patch b/queue-6.6/mmc-mtk-sd-use-devm_mmc_alloc_host.patch new file mode 100644 index 00000000000..030dd45e90a --- /dev/null +++ b/queue-6.6/mmc-mtk-sd-use-devm_mmc_alloc_host.patch @@ -0,0 +1,159 @@ +From 28cc86983c09769725400af9458287a9c121acf8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Sep 2024 15:49:17 -0700 +Subject: mmc: mtk-sd: use devm_mmc_alloc_host + +From: Rosen Penev + +[ Upstream commit 7a2fa8eed936b33b22e49b1d2349cd7d02f22710 ] + +Allows removing several gotos. + +Also fixed some wrong ones. + +Added dev_err_probe where EPROBE_DEFER is possible. + +Signed-off-by: Rosen Penev +Link: https://lore.kernel.org/r/20240930224919.355359-2-rosenp@gmail.com +Signed-off-by: Ulf Hansson +Stable-dep-of: 291220451c77 ("mmc: mtk-sd: Fix error handle of probe function") +Signed-off-by: Sasha Levin +--- + drivers/mmc/host/mtk-sd.c | 55 ++++++++++++++------------------------- + 1 file changed, 20 insertions(+), 35 deletions(-) + +diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c +index 8b755f1627325..9ebf5aa5d9b18 100644 +--- a/drivers/mmc/host/mtk-sd.c ++++ b/drivers/mmc/host/mtk-sd.c +@@ -2674,20 +2674,18 @@ static int msdc_drv_probe(struct platform_device *pdev) + } + + /* Allocate MMC host for this device */ +- mmc = mmc_alloc_host(sizeof(struct msdc_host), &pdev->dev); ++ mmc = devm_mmc_alloc_host(&pdev->dev, sizeof(struct msdc_host)); + if (!mmc) + return -ENOMEM; + + host = mmc_priv(mmc); + ret = mmc_of_parse(mmc); + if (ret) +- goto host_free; ++ return ret; + + host->base = devm_platform_ioremap_resource(pdev, 0); +- if (IS_ERR(host->base)) { +- ret = PTR_ERR(host->base); +- goto host_free; +- } ++ if (IS_ERR(host->base)) ++ return PTR_ERR(host->base); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (res) { +@@ -2698,18 +2696,16 @@ static int msdc_drv_probe(struct platform_device *pdev) + + ret = mmc_regulator_get_supply(mmc); + if (ret) +- goto host_free; ++ return ret; + + ret = msdc_of_clock_parse(pdev, host); + if (ret) +- goto host_free; ++ return ret; + + host->reset = devm_reset_control_get_optional_exclusive(&pdev->dev, + "hrst"); +- if (IS_ERR(host->reset)) { +- ret = PTR_ERR(host->reset); +- goto host_free; +- } ++ if (IS_ERR(host->reset)) ++ return PTR_ERR(host->reset); + + /* only eMMC has crypto property */ + if (!(mmc->caps2 & MMC_CAP2_NO_MMC)) { +@@ -2721,30 +2717,24 @@ static int msdc_drv_probe(struct platform_device *pdev) + } + + host->irq = platform_get_irq(pdev, 0); +- if (host->irq < 0) { +- ret = host->irq; +- goto host_free; +- } ++ if (host->irq < 0) ++ return host->irq; + + host->pinctrl = devm_pinctrl_get(&pdev->dev); +- if (IS_ERR(host->pinctrl)) { +- ret = PTR_ERR(host->pinctrl); +- dev_err(&pdev->dev, "Cannot find pinctrl!\n"); +- goto host_free; +- } ++ if (IS_ERR(host->pinctrl)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(host->pinctrl), ++ "Cannot find pinctrl"); + + host->pins_default = pinctrl_lookup_state(host->pinctrl, "default"); + if (IS_ERR(host->pins_default)) { +- ret = PTR_ERR(host->pins_default); + dev_err(&pdev->dev, "Cannot find pinctrl default!\n"); +- goto host_free; ++ return PTR_ERR(host->pins_default); + } + + host->pins_uhs = pinctrl_lookup_state(host->pinctrl, "state_uhs"); + if (IS_ERR(host->pins_uhs)) { +- ret = PTR_ERR(host->pins_uhs); + dev_err(&pdev->dev, "Cannot find pinctrl uhs!\n"); +- goto host_free; ++ return PTR_ERR(host->pins_uhs); + } + + /* Support for SDIO eint irq ? */ +@@ -2833,14 +2823,14 @@ static int msdc_drv_probe(struct platform_device *pdev) + GFP_KERNEL); + if (!host->cq_host) { + ret = -ENOMEM; +- goto host_free; ++ goto release_mem; + } + host->cq_host->caps |= CQHCI_TASK_DESC_SZ_128; + host->cq_host->mmio = host->base + 0x800; + host->cq_host->ops = &msdc_cmdq_ops; + ret = cqhci_init(host->cq_host, mmc, true); + if (ret) +- goto host_free; ++ goto release_mem; + mmc->max_segs = 128; + /* cqhci 16bit length */ + /* 0 size, means 65536 so we don't have to -1 here */ +@@ -2877,11 +2867,8 @@ static int msdc_drv_probe(struct platform_device *pdev) + host->dma.gpd, host->dma.gpd_addr); + if (host->dma.bd) + dma_free_coherent(&pdev->dev, +- MAX_BD_NUM * sizeof(struct mt_bdma_desc), +- host->dma.bd, host->dma.bd_addr); +-host_free: +- mmc_free_host(mmc); +- ++ MAX_BD_NUM * sizeof(struct mt_bdma_desc), ++ host->dma.bd, host->dma.bd_addr); + return ret; + } + +@@ -2906,9 +2893,7 @@ static void msdc_drv_remove(struct platform_device *pdev) + 2 * sizeof(struct mt_gpdma_desc), + host->dma.gpd, host->dma.gpd_addr); + dma_free_coherent(&pdev->dev, MAX_BD_NUM * sizeof(struct mt_bdma_desc), +- host->dma.bd, host->dma.bd_addr); +- +- mmc_free_host(mmc); ++ host->dma.bd, host->dma.bd_addr); + } + + static void msdc_save_reg(struct msdc_host *host) +-- +2.43.0 + diff --git a/queue-6.6/net-avoid-potential-uaf-in-default_operstate.patch b/queue-6.6/net-avoid-potential-uaf-in-default_operstate.patch new file mode 100644 index 00000000000..f0e7c19461f --- /dev/null +++ b/queue-6.6/net-avoid-potential-uaf-in-default_operstate.patch @@ -0,0 +1,226 @@ +From 0b4530e8f42410c919b118b5510811a1e74311dd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Dec 2024 17:09:33 +0000 +Subject: net: avoid potential UAF in default_operstate() + +From: Eric Dumazet + +[ Upstream commit 750e51603395e755537da08f745864c93e3ce741 ] + +syzbot reported an UAF in default_operstate() [1] + +Issue is a race between device and netns dismantles. + +After calling __rtnl_unlock() from netdev_run_todo(), +we can not assume the netns of each device is still alive. + +Make sure the device is not in NETREG_UNREGISTERED state, +and add an ASSERT_RTNL() before the call to +__dev_get_by_index(). + +We might move this ASSERT_RTNL() in __dev_get_by_index() +in the future. + +[1] + +BUG: KASAN: slab-use-after-free in __dev_get_by_index+0x5d/0x110 net/core/dev.c:852 +Read of size 8 at addr ffff888043eba1b0 by task syz.0.0/5339 + +CPU: 0 UID: 0 PID: 5339 Comm: syz.0.0 Not tainted 6.12.0-syzkaller-10296-gaaf20f870da0 #0 +Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2~bpo12+1 04/01/2014 +Call Trace: + + __dump_stack lib/dump_stack.c:94 [inline] + dump_stack_lvl+0x241/0x360 lib/dump_stack.c:120 + print_address_description mm/kasan/report.c:378 [inline] + print_report+0x169/0x550 mm/kasan/report.c:489 + kasan_report+0x143/0x180 mm/kasan/report.c:602 + __dev_get_by_index+0x5d/0x110 net/core/dev.c:852 + default_operstate net/core/link_watch.c:51 [inline] + rfc2863_policy+0x224/0x300 net/core/link_watch.c:67 + linkwatch_do_dev+0x3e/0x170 net/core/link_watch.c:170 + netdev_run_todo+0x461/0x1000 net/core/dev.c:10894 + rtnl_unlock net/core/rtnetlink.c:152 [inline] + rtnl_net_unlock include/linux/rtnetlink.h:133 [inline] + rtnl_dellink+0x760/0x8d0 net/core/rtnetlink.c:3520 + rtnetlink_rcv_msg+0x791/0xcf0 net/core/rtnetlink.c:6911 + netlink_rcv_skb+0x1e3/0x430 net/netlink/af_netlink.c:2541 + netlink_unicast_kernel net/netlink/af_netlink.c:1321 [inline] + netlink_unicast+0x7f6/0x990 net/netlink/af_netlink.c:1347 + netlink_sendmsg+0x8e4/0xcb0 net/netlink/af_netlink.c:1891 + sock_sendmsg_nosec net/socket.c:711 [inline] + __sock_sendmsg+0x221/0x270 net/socket.c:726 + ____sys_sendmsg+0x52a/0x7e0 net/socket.c:2583 + ___sys_sendmsg net/socket.c:2637 [inline] + __sys_sendmsg+0x269/0x350 net/socket.c:2669 + do_syscall_x64 arch/x86/entry/common.c:52 [inline] + do_syscall_64+0xf3/0x230 arch/x86/entry/common.c:83 + entry_SYSCALL_64_after_hwframe+0x77/0x7f +RIP: 0033:0x7f2a3cb80809 +Code: ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 a8 ff ff ff f7 d8 64 89 01 48 +RSP: 002b:00007f2a3d9cd058 EFLAGS: 00000246 ORIG_RAX: 000000000000002e +RAX: ffffffffffffffda RBX: 00007f2a3cd45fa0 RCX: 00007f2a3cb80809 +RDX: 0000000000000000 RSI: 0000000020000000 RDI: 0000000000000008 +RBP: 00007f2a3cbf393e R08: 0000000000000000 R09: 0000000000000000 +R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000 +R13: 0000000000000000 R14: 00007f2a3cd45fa0 R15: 00007ffd03bc65c8 + + +Allocated by task 5339: + kasan_save_stack mm/kasan/common.c:47 [inline] + kasan_save_track+0x3f/0x80 mm/kasan/common.c:68 + poison_kmalloc_redzone mm/kasan/common.c:377 [inline] + __kasan_kmalloc+0x98/0xb0 mm/kasan/common.c:394 + kasan_kmalloc include/linux/kasan.h:260 [inline] + __kmalloc_cache_noprof+0x243/0x390 mm/slub.c:4314 + kmalloc_noprof include/linux/slab.h:901 [inline] + kmalloc_array_noprof include/linux/slab.h:945 [inline] + netdev_create_hash net/core/dev.c:11870 [inline] + netdev_init+0x10c/0x250 net/core/dev.c:11890 + ops_init+0x31e/0x590 net/core/net_namespace.c:138 + setup_net+0x287/0x9e0 net/core/net_namespace.c:362 + copy_net_ns+0x33f/0x570 net/core/net_namespace.c:500 + create_new_namespaces+0x425/0x7b0 kernel/nsproxy.c:110 + unshare_nsproxy_namespaces+0x124/0x180 kernel/nsproxy.c:228 + ksys_unshare+0x57d/0xa70 kernel/fork.c:3314 + __do_sys_unshare kernel/fork.c:3385 [inline] + __se_sys_unshare kernel/fork.c:3383 [inline] + __x64_sys_unshare+0x38/0x40 kernel/fork.c:3383 + do_syscall_x64 arch/x86/entry/common.c:52 [inline] + do_syscall_64+0xf3/0x230 arch/x86/entry/common.c:83 + entry_SYSCALL_64_after_hwframe+0x77/0x7f + +Freed by task 12: + kasan_save_stack mm/kasan/common.c:47 [inline] + kasan_save_track+0x3f/0x80 mm/kasan/common.c:68 + kasan_save_free_info+0x40/0x50 mm/kasan/generic.c:582 + poison_slab_object mm/kasan/common.c:247 [inline] + __kasan_slab_free+0x59/0x70 mm/kasan/common.c:264 + kasan_slab_free include/linux/kasan.h:233 [inline] + slab_free_hook mm/slub.c:2338 [inline] + slab_free mm/slub.c:4598 [inline] + kfree+0x196/0x420 mm/slub.c:4746 + netdev_exit+0x65/0xd0 net/core/dev.c:11992 + ops_exit_list net/core/net_namespace.c:172 [inline] + cleanup_net+0x802/0xcc0 net/core/net_namespace.c:632 + process_one_work kernel/workqueue.c:3229 [inline] + process_scheduled_works+0xa63/0x1850 kernel/workqueue.c:3310 + worker_thread+0x870/0xd30 kernel/workqueue.c:3391 + kthread+0x2f0/0x390 kernel/kthread.c:389 + ret_from_fork+0x4b/0x80 arch/x86/kernel/process.c:147 + ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:244 + +The buggy address belongs to the object at ffff888043eba000 + which belongs to the cache kmalloc-2k of size 2048 +The buggy address is located 432 bytes inside of + freed 2048-byte region [ffff888043eba000, ffff888043eba800) + +The buggy address belongs to the physical page: +page: refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x43eb8 +head: order:3 mapcount:0 entire_mapcount:0 nr_pages_mapped:0 pincount:0 +flags: 0x4fff00000000040(head|node=1|zone=1|lastcpupid=0x7ff) +page_type: f5(slab) +raw: 04fff00000000040 ffff88801ac42000 dead000000000122 0000000000000000 +raw: 0000000000000000 0000000000080008 00000001f5000000 0000000000000000 +head: 04fff00000000040 ffff88801ac42000 dead000000000122 0000000000000000 +head: 0000000000000000 0000000000080008 00000001f5000000 0000000000000000 +head: 04fff00000000003 ffffea00010fae01 ffffffffffffffff 0000000000000000 +head: 0000000000000008 0000000000000000 00000000ffffffff 0000000000000000 +page dumped because: kasan: bad access detected +page_owner tracks the page as allocated +page last allocated via order 3, migratetype Unmovable, gfp_mask 0xd20c0(__GFP_IO|__GFP_FS|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP|__GFP_NOMEMALLOC), pid 5339, tgid 5338 (syz.0.0), ts 69674195892, free_ts 69663220888 + set_page_owner include/linux/page_owner.h:32 [inline] + post_alloc_hook+0x1f3/0x230 mm/page_alloc.c:1556 + prep_new_page mm/page_alloc.c:1564 [inline] + get_page_from_freelist+0x3649/0x3790 mm/page_alloc.c:3474 + __alloc_pages_noprof+0x292/0x710 mm/page_alloc.c:4751 + alloc_pages_mpol_noprof+0x3e8/0x680 mm/mempolicy.c:2265 + alloc_slab_page+0x6a/0x140 mm/slub.c:2408 + allocate_slab+0x5a/0x2f0 mm/slub.c:2574 + new_slab mm/slub.c:2627 [inline] + ___slab_alloc+0xcd1/0x14b0 mm/slub.c:3815 + __slab_alloc+0x58/0xa0 mm/slub.c:3905 + __slab_alloc_node mm/slub.c:3980 [inline] + slab_alloc_node mm/slub.c:4141 [inline] + __do_kmalloc_node mm/slub.c:4282 [inline] + __kmalloc_noprof+0x2e6/0x4c0 mm/slub.c:4295 + kmalloc_noprof include/linux/slab.h:905 [inline] + sk_prot_alloc+0xe0/0x210 net/core/sock.c:2165 + sk_alloc+0x38/0x370 net/core/sock.c:2218 + __netlink_create+0x65/0x260 net/netlink/af_netlink.c:629 + __netlink_kernel_create+0x174/0x6f0 net/netlink/af_netlink.c:2015 + netlink_kernel_create include/linux/netlink.h:62 [inline] + uevent_net_init+0xed/0x2d0 lib/kobject_uevent.c:783 + ops_init+0x31e/0x590 net/core/net_namespace.c:138 + setup_net+0x287/0x9e0 net/core/net_namespace.c:362 +page last free pid 1032 tgid 1032 stack trace: + reset_page_owner include/linux/page_owner.h:25 [inline] + free_pages_prepare mm/page_alloc.c:1127 [inline] + free_unref_page+0xdf9/0x1140 mm/page_alloc.c:2657 + __slab_free+0x31b/0x3d0 mm/slub.c:4509 + qlink_free mm/kasan/quarantine.c:163 [inline] + qlist_free_all+0x9a/0x140 mm/kasan/quarantine.c:179 + kasan_quarantine_reduce+0x14f/0x170 mm/kasan/quarantine.c:286 + __kasan_slab_alloc+0x23/0x80 mm/kasan/common.c:329 + kasan_slab_alloc include/linux/kasan.h:250 [inline] + slab_post_alloc_hook mm/slub.c:4104 [inline] + slab_alloc_node mm/slub.c:4153 [inline] + kmem_cache_alloc_node_noprof+0x1d9/0x380 mm/slub.c:4205 + __alloc_skb+0x1c3/0x440 net/core/skbuff.c:668 + alloc_skb include/linux/skbuff.h:1323 [inline] + alloc_skb_with_frags+0xc3/0x820 net/core/skbuff.c:6612 + sock_alloc_send_pskb+0x91a/0xa60 net/core/sock.c:2881 + sock_alloc_send_skb include/net/sock.h:1797 [inline] + mld_newpack+0x1c3/0xaf0 net/ipv6/mcast.c:1747 + add_grhead net/ipv6/mcast.c:1850 [inline] + add_grec+0x1492/0x19a0 net/ipv6/mcast.c:1988 + mld_send_initial_cr+0x228/0x4b0 net/ipv6/mcast.c:2234 + ipv6_mc_dad_complete+0x88/0x490 net/ipv6/mcast.c:2245 + addrconf_dad_completed+0x712/0xcd0 net/ipv6/addrconf.c:4342 + addrconf_dad_work+0xdc2/0x16f0 + process_one_work kernel/workqueue.c:3229 [inline] + process_scheduled_works+0xa63/0x1850 kernel/workqueue.c:3310 + +Memory state around the buggy address: + ffff888043eba080: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb + ffff888043eba100: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb +>ffff888043eba180: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb + ^ + ffff888043eba200: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb + ffff888043eba280: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb + +Fixes: 8c55facecd7a ("net: linkwatch: only report IF_OPER_LOWERLAYERDOWN if iflink is actually down") +Reported-by: syzbot+1939f24bdb783e9e43d9@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/netdev/674f3a18.050a0220.48a03.0041.GAE@google.com/T/#u +Signed-off-by: Eric Dumazet +Reviewed-by: Vladimir Oltean +Link: https://patch.msgid.link/20241203170933.2449307-1-edumazet@google.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/core/link_watch.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/net/core/link_watch.c b/net/core/link_watch.c +index cf867f6e38bf1..66422c95c83c7 100644 +--- a/net/core/link_watch.c ++++ b/net/core/link_watch.c +@@ -45,9 +45,14 @@ static unsigned char default_operstate(const struct net_device *dev) + int iflink = dev_get_iflink(dev); + struct net_device *peer; + +- if (iflink == dev->ifindex) ++ /* If called from netdev_run_todo()/linkwatch_sync_dev(), ++ * dev_net(dev) can be already freed, and RTNL is not held. ++ */ ++ if (dev->reg_state == NETREG_UNREGISTERED || ++ iflink == dev->ifindex) + return IF_OPER_DOWN; + ++ ASSERT_RTNL(); + peer = __dev_get_by_index(dev_net(dev), iflink); + if (!peer) + return IF_OPER_DOWN; +-- +2.43.0 + diff --git a/queue-6.6/net-enetc-do-not-configure-preemptible-tcs-if-sis-do.patch b/queue-6.6/net-enetc-do-not-configure-preemptible-tcs-if-sis-do.patch new file mode 100644 index 00000000000..2e317c57136 --- /dev/null +++ b/queue-6.6/net-enetc-do-not-configure-preemptible-tcs-if-sis-do.patch @@ -0,0 +1,69 @@ +From d5ecad4a6f4c6a54e1c388e0be84e9ae7b6fdf03 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Nov 2024 17:07:19 +0800 +Subject: net: enetc: Do not configure preemptible TCs if SIs do not support + +From: Wei Fang + +[ Upstream commit b2420b8c81ec674552d00c55d46245e5c184b260 ] + +Both ENETC PF and VF drivers share enetc_setup_tc_mqprio() to configure +MQPRIO. And enetc_setup_tc_mqprio() calls enetc_change_preemptible_tcs() +to configure preemptible TCs. However, only PF is able to configure +preemptible TCs. Because only PF has related registers, while VF does not +have these registers. So for VF, its hw->port pointer is NULL. Therefore, +VF will access an invalid pointer when accessing a non-existent register, +which will cause a crash issue. The simplified log is as follows. + +root@ls1028ardb:~# tc qdisc add dev eno0vf0 parent root handle 100: \ +mqprio num_tc 4 map 0 0 1 1 2 2 3 3 queues 1@0 1@1 1@2 1@3 hw 1 +[ 187.290775] Unable to handle kernel paging request at virtual address 0000000000001f00 +[ 187.424831] pc : enetc_mm_commit_preemptible_tcs+0x1c4/0x400 +[ 187.430518] lr : enetc_mm_commit_preemptible_tcs+0x30c/0x400 +[ 187.511140] Call trace: +[ 187.513588] enetc_mm_commit_preemptible_tcs+0x1c4/0x400 +[ 187.518918] enetc_setup_tc_mqprio+0x180/0x214 +[ 187.523374] enetc_vf_setup_tc+0x1c/0x30 +[ 187.527306] mqprio_enable_offload+0x144/0x178 +[ 187.531766] mqprio_init+0x3ec/0x668 +[ 187.535351] qdisc_create+0x15c/0x488 +[ 187.539023] tc_modify_qdisc+0x398/0x73c +[ 187.542958] rtnetlink_rcv_msg+0x128/0x378 +[ 187.547064] netlink_rcv_skb+0x60/0x130 +[ 187.550910] rtnetlink_rcv+0x18/0x24 +[ 187.554492] netlink_unicast+0x300/0x36c +[ 187.558425] netlink_sendmsg+0x1a8/0x420 +[ 187.606759] ---[ end trace 0000000000000000 ]--- + +In addition, some PFs also do not support configuring preemptible TCs, +such as eno1 and eno3 on LS1028A. It won't crash like it does for VFs, +but we should prevent these PFs from accessing these unimplemented +registers. + +Fixes: 827145392a4a ("net: enetc: only commit preemptible TCs to hardware when MM TX is active") +Signed-off-by: Wei Fang +Suggested-by: Vladimir Oltean +Reviewed-by: Frank Li +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/freescale/enetc/enetc.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c +index c17b9e3385168..87b27bd7a13bb 100644 +--- a/drivers/net/ethernet/freescale/enetc/enetc.c ++++ b/drivers/net/ethernet/freescale/enetc/enetc.c +@@ -28,6 +28,9 @@ EXPORT_SYMBOL_GPL(enetc_port_mac_wr); + static void enetc_change_preemptible_tcs(struct enetc_ndev_priv *priv, + u8 preemptible_tcs) + { ++ if (!(priv->si->hw_features & ENETC_SI_F_QBU)) ++ return; ++ + priv->preemptible_tcs = preemptible_tcs; + enetc_mm_commit_preemptible_tcs(priv); + } +-- +2.43.0 + diff --git a/queue-6.6/net-hsr-avoid-potential-out-of-bound-access-in-fill_.patch b/queue-6.6/net-hsr-avoid-potential-out-of-bound-access-in-fill_.patch new file mode 100644 index 00000000000..e92dfe5e5e8 --- /dev/null +++ b/queue-6.6/net-hsr-avoid-potential-out-of-bound-access-in-fill_.patch @@ -0,0 +1,95 @@ +From ecbeee63d17470718c15e1f0f6c1e9357be4ffd8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 Nov 2024 14:43:44 +0000 +Subject: net: hsr: avoid potential out-of-bound access in fill_frame_info() + +From: Eric Dumazet + +[ Upstream commit b9653d19e556c6afd035602927a93d100a0d7644 ] + +syzbot is able to feed a packet with 14 bytes, pretending +it is a vlan one. + +Since fill_frame_info() is relying on skb->mac_len already, +extend the check to cover this case. + +BUG: KMSAN: uninit-value in fill_frame_info net/hsr/hsr_forward.c:709 [inline] + BUG: KMSAN: uninit-value in hsr_forward_skb+0x9ee/0x3b10 net/hsr/hsr_forward.c:724 + fill_frame_info net/hsr/hsr_forward.c:709 [inline] + hsr_forward_skb+0x9ee/0x3b10 net/hsr/hsr_forward.c:724 + hsr_dev_xmit+0x2f0/0x350 net/hsr/hsr_device.c:235 + __netdev_start_xmit include/linux/netdevice.h:5002 [inline] + netdev_start_xmit include/linux/netdevice.h:5011 [inline] + xmit_one net/core/dev.c:3590 [inline] + dev_hard_start_xmit+0x247/0xa20 net/core/dev.c:3606 + __dev_queue_xmit+0x366a/0x57d0 net/core/dev.c:4434 + dev_queue_xmit include/linux/netdevice.h:3168 [inline] + packet_xmit+0x9c/0x6c0 net/packet/af_packet.c:276 + packet_snd net/packet/af_packet.c:3146 [inline] + packet_sendmsg+0x91ae/0xa6f0 net/packet/af_packet.c:3178 + sock_sendmsg_nosec net/socket.c:711 [inline] + __sock_sendmsg+0x30f/0x380 net/socket.c:726 + __sys_sendto+0x594/0x750 net/socket.c:2197 + __do_sys_sendto net/socket.c:2204 [inline] + __se_sys_sendto net/socket.c:2200 [inline] + __x64_sys_sendto+0x125/0x1d0 net/socket.c:2200 + x64_sys_call+0x346a/0x3c30 arch/x86/include/generated/asm/syscalls_64.h:45 + do_syscall_x64 arch/x86/entry/common.c:52 [inline] + do_syscall_64+0xcd/0x1e0 arch/x86/entry/common.c:83 + entry_SYSCALL_64_after_hwframe+0x77/0x7f + +Uninit was created at: + slab_post_alloc_hook mm/slub.c:4091 [inline] + slab_alloc_node mm/slub.c:4134 [inline] + kmem_cache_alloc_node_noprof+0x6bf/0xb80 mm/slub.c:4186 + kmalloc_reserve+0x13d/0x4a0 net/core/skbuff.c:587 + __alloc_skb+0x363/0x7b0 net/core/skbuff.c:678 + alloc_skb include/linux/skbuff.h:1323 [inline] + alloc_skb_with_frags+0xc8/0xd00 net/core/skbuff.c:6612 + sock_alloc_send_pskb+0xa81/0xbf0 net/core/sock.c:2881 + packet_alloc_skb net/packet/af_packet.c:2995 [inline] + packet_snd net/packet/af_packet.c:3089 [inline] + packet_sendmsg+0x74c6/0xa6f0 net/packet/af_packet.c:3178 + sock_sendmsg_nosec net/socket.c:711 [inline] + __sock_sendmsg+0x30f/0x380 net/socket.c:726 + __sys_sendto+0x594/0x750 net/socket.c:2197 + __do_sys_sendto net/socket.c:2204 [inline] + __se_sys_sendto net/socket.c:2200 [inline] + __x64_sys_sendto+0x125/0x1d0 net/socket.c:2200 + x64_sys_call+0x346a/0x3c30 arch/x86/include/generated/asm/syscalls_64.h:45 + do_syscall_x64 arch/x86/entry/common.c:52 [inline] + do_syscall_64+0xcd/0x1e0 arch/x86/entry/common.c:83 + entry_SYSCALL_64_after_hwframe+0x77/0x7f + +Fixes: 48b491a5cc74 ("net: hsr: fix mac_len checks") +Reported-by: syzbot+671e2853f9851d039551@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/netdev/6745dc7f.050a0220.21d33d.0018.GAE@google.com/T/#u +Signed-off-by: Eric Dumazet +Cc: WingMan Kwok +Cc: Murali Karicheri +Cc: MD Danish Anwar +Cc: Jiri Pirko +Cc: George McCollister +Link: https://patch.msgid.link/20241126144344.4177332-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/hsr/hsr_forward.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/hsr/hsr_forward.c b/net/hsr/hsr_forward.c +index 0323ab5023c69..2790f3964d6bd 100644 +--- a/net/hsr/hsr_forward.c ++++ b/net/hsr/hsr_forward.c +@@ -588,6 +588,8 @@ static int fill_frame_info(struct hsr_frame_info *frame, + frame->is_vlan = true; + + if (frame->is_vlan) { ++ if (skb->mac_len < offsetofend(struct hsr_vlan_ethhdr, vlanhdr)) ++ return -EINVAL; + vlan_hdr = (struct hsr_vlan_ethhdr *)ethhdr; + proto = vlan_hdr->vlanhdr.h_vlan_encapsulated_proto; + /* FIXME: */ +-- +2.43.0 + diff --git a/queue-6.6/net-ipv6-release-expired-exception-dst-cached-in-soc.patch b/queue-6.6/net-ipv6-release-expired-exception-dst-cached-in-soc.patch new file mode 100644 index 00000000000..84382a1524d --- /dev/null +++ b/queue-6.6/net-ipv6-release-expired-exception-dst-cached-in-soc.patch @@ -0,0 +1,85 @@ +From 2710e56064b74f86c7d1938e5dc347b68604fdd3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 Nov 2024 09:59:50 +0100 +Subject: net/ipv6: release expired exception dst cached in socket + +From: Jiri Wiesner + +[ Upstream commit 3301ab7d5aeb0fe270f73a3d4810c9d1b6a9f045 ] + +Dst objects get leaked in ip6_negative_advice() when this function is +executed for an expired IPv6 route located in the exception table. There +are several conditions that must be fulfilled for the leak to occur: +* an ICMPv6 packet indicating a change of the MTU for the path is received, + resulting in an exception dst being created +* a TCP connection that uses the exception dst for routing packets must + start timing out so that TCP begins retransmissions +* after the exception dst expires, the FIB6 garbage collector must not run + before TCP executes ip6_negative_advice() for the expired exception dst + +When TCP executes ip6_negative_advice() for an exception dst that has +expired and if no other socket holds a reference to the exception dst, the +refcount of the exception dst is 2, which corresponds to the increment +made by dst_init() and the increment made by the TCP socket for which the +connection is timing out. The refcount made by the socket is never +released. The refcount of the dst is decremented in sk_dst_reset() but +that decrement is counteracted by a dst_hold() intentionally placed just +before the sk_dst_reset() in ip6_negative_advice(). After +ip6_negative_advice() has finished, there is no other object tied to the +dst. The socket lost its reference stored in sk_dst_cache and the dst is +no longer in the exception table. The exception dst becomes a leaked +object. + +As a result of this dst leak, an unbalanced refcount is reported for the +loopback device of a net namespace being destroyed under kernels that do +not contain e5f80fcf869a ("ipv6: give an IPv6 dev to blackhole_netdev"): +unregister_netdevice: waiting for lo to become free. Usage count = 2 + +Fix the dst leak by removing the dst_hold() in ip6_negative_advice(). The +patch that introduced the dst_hold() in ip6_negative_advice() was +92f1655aa2b22 ("net: fix __dst_negative_advice() race"). But 92f1655aa2b22 +merely refactored the code with regards to the dst refcount so the issue +was present even before 92f1655aa2b22. The bug was introduced in +54c1a859efd9f ("ipv6: Don't drop cache route entry unless timer actually +expired.") where the expired cached route is deleted and the sk_dst_cache +member of the socket is set to NULL by calling dst_negative_advice() but +the refcount belonging to the socket is left unbalanced. + +The IPv4 version - ipv4_negative_advice() - is not affected by this bug. +When the TCP connection times out ipv4_negative_advice() merely resets the +sk_dst_cache of the socket while decrementing the refcount of the +exception dst. + +Fixes: 92f1655aa2b22 ("net: fix __dst_negative_advice() race") +Fixes: 54c1a859efd9f ("ipv6: Don't drop cache route entry unless timer actually expired.") +Link: https://lore.kernel.org/netdev/20241113105611.GA6723@incl/T/#u +Signed-off-by: Jiri Wiesner +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20241128085950.GA4505@incl +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/route.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/net/ipv6/route.c b/net/ipv6/route.c +index 0fdd062d4b05b..fc5c534620253 100644 +--- a/net/ipv6/route.c ++++ b/net/ipv6/route.c +@@ -2772,10 +2772,10 @@ static void ip6_negative_advice(struct sock *sk, + if (rt->rt6i_flags & RTF_CACHE) { + rcu_read_lock(); + if (rt6_check_expired(rt)) { +- /* counteract the dst_release() in sk_dst_reset() */ +- dst_hold(dst); ++ /* rt/dst can not be destroyed yet, ++ * because of rcu_read_lock() ++ */ + sk_dst_reset(sk); +- + rt6_remove_exception_rt(rt); + } + rcu_read_unlock(); +-- +2.43.0 + diff --git a/queue-6.6/net-mlx5e-remove-workaround-to-avoid-syndrome-for-in.patch b/queue-6.6/net-mlx5e-remove-workaround-to-avoid-syndrome-for-in.patch new file mode 100644 index 00000000000..6148696b243 --- /dev/null +++ b/queue-6.6/net-mlx5e-remove-workaround-to-avoid-syndrome-for-in.patch @@ -0,0 +1,69 @@ +From 33e7f648f3cb6036aaa7fbd708fa8013d340ab03 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Dec 2024 22:49:20 +0200 +Subject: net/mlx5e: Remove workaround to avoid syndrome for internal port + +From: Jianbo Liu + +[ Upstream commit 5085f861b414e4a51ce28a891dfa32a10a54b64e ] + +Previously a workaround was added to avoid syndrome 0xcdb051. It is +triggered when offload a rule with tunnel encapsulation, and +forwarding to another table, but not matching on the internal port in +firmware steering mode. The original workaround skips internal tunnel +port logic, which is not correct as not all cases are considered. As +an example, if vlan is configured on the uplink port, traffic can't +pass because vlan header is not added with this workaround. Besides, +there is no such issue for software steering. So, this patch removes +that, and returns error directly if trying to offload such rule for +firmware steering. + +Fixes: 06b4eac9c4be ("net/mlx5e: Don't offload internal port if filter device is out device") +Signed-off-by: Jianbo Liu +Tested-by: Frode Nordahl +Reviewed-by: Chris Mi +Reviewed-by: Ariel Levkovich +Signed-off-by: Tariq Toukan +Link: https://patch.msgid.link/20241203204920.232744-7-tariqt@nvidia.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + .../ethernet/mellanox/mlx5/core/en/tc_tun_encap.c | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c +index f1d1e1542e81b..c11092da2e7d8 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c +@@ -5,6 +5,7 @@ + #include + #include + #include "tc_tun_encap.h" ++#include "fs_core.h" + #include "en_tc.h" + #include "tc_tun.h" + #include "rep/tc.h" +@@ -24,10 +25,18 @@ static int mlx5e_set_int_port_tunnel(struct mlx5e_priv *priv, + + route_dev = dev_get_by_index(dev_net(e->out_dev), e->route_dev_ifindex); + +- if (!route_dev || !netif_is_ovs_master(route_dev) || +- attr->parse_attr->filter_dev == e->out_dev) ++ if (!route_dev || !netif_is_ovs_master(route_dev)) + goto out; + ++ if (priv->mdev->priv.steering->mode == MLX5_FLOW_STEERING_MODE_DMFS && ++ mlx5e_eswitch_uplink_rep(attr->parse_attr->filter_dev) && ++ (attr->esw_attr->dests[out_index].flags & MLX5_ESW_DEST_ENCAP)) { ++ mlx5_core_warn(priv->mdev, ++ "Matching on external port with encap + fwd to table actions is not allowed for firmware steering\n"); ++ err = -EINVAL; ++ goto out; ++ } ++ + err = mlx5e_set_fwd_to_int_port_actions(priv, attr, e->route_dev_ifindex, + MLX5E_TC_INT_PORT_EGRESS, + &attr->action, out_index); +-- +2.43.0 + diff --git a/queue-6.6/net-qed-allow-old-cards-not-supporting-num_images-to.patch b/queue-6.6/net-qed-allow-old-cards-not-supporting-num_images-to.patch new file mode 100644 index 00000000000..9ed26d9a72a --- /dev/null +++ b/queue-6.6/net-qed-allow-old-cards-not-supporting-num_images-to.patch @@ -0,0 +1,48 @@ +From b77deecd33968d1339d6e8d71080f08efd6e2cd1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 Nov 2024 09:33:58 +0100 +Subject: net/qed: allow old cards not supporting "num_images" to work + +From: Louis Leseur + +[ Upstream commit 7a0ea70da56ee8c2716d0b79e9959d3c47efab62 ] + +Commit 43645ce03e00 ("qed: Populate nvm image attribute shadow.") +added support for populating flash image attributes, notably +"num_images". However, some cards were not able to return this +information. In such cases, the driver would return EINVAL, causing the +driver to exit. + +Add check to return EOPNOTSUPP instead of EINVAL when the card is not +able to return these information. The caller function already handles +EOPNOTSUPP without error. + +Fixes: 43645ce03e00 ("qed: Populate nvm image attribute shadow.") +Co-developed-by: Florian Forestier +Signed-off-by: Florian Forestier +Signed-off-by: Louis Leseur +Link: https://patch.msgid.link/20241128083633.26431-1-louis.leseur@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/qlogic/qed/qed_mcp.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.c b/drivers/net/ethernet/qlogic/qed/qed_mcp.c +index 16e6bd4661433..6218d9c268554 100644 +--- a/drivers/net/ethernet/qlogic/qed/qed_mcp.c ++++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.c +@@ -3314,7 +3314,9 @@ int qed_mcp_bist_nvm_get_num_images(struct qed_hwfn *p_hwfn, + if (rc) + return rc; + +- if (((rsp & FW_MSG_CODE_MASK) != FW_MSG_CODE_OK)) ++ if (((rsp & FW_MSG_CODE_MASK) == FW_MSG_CODE_UNSUPPORTED)) ++ rc = -EOPNOTSUPP; ++ else if (((rsp & FW_MSG_CODE_MASK) != FW_MSG_CODE_OK)) + rc = -EINVAL; + + return rc; +-- +2.43.0 + diff --git a/queue-6.6/net-sched-fix-erspan_opt-settings-in-cls_flower.patch b/queue-6.6/net-sched-fix-erspan_opt-settings-in-cls_flower.patch new file mode 100644 index 00000000000..ded754bd36c --- /dev/null +++ b/queue-6.6/net-sched-fix-erspan_opt-settings-in-cls_flower.patch @@ -0,0 +1,68 @@ +From 4b84c2e3d8239a302c6192da071d78a1fcd9c556 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Dec 2024 10:21:38 -0500 +Subject: net: sched: fix erspan_opt settings in cls_flower + +From: Xin Long + +[ Upstream commit 292207809486d99c78068d3f459cbbbffde88415 ] + +When matching erspan_opt in cls_flower, only the (version, dir, hwid) +fields are relevant. However, in fl_set_erspan_opt() it initializes +all bits of erspan_opt and its mask to 1. This inadvertently requires +packets to match not only the (version, dir, hwid) fields but also the +other fields that are unexpectedly set to 1. + +This patch resolves the issue by ensuring that only the (version, dir, +hwid) fields are configured in fl_set_erspan_opt(), leaving the other +fields to 0 in erspan_opt. + +Fixes: 79b1011cb33d ("net: sched: allow flower to match erspan options") +Reported-by: Shuang Li +Signed-off-by: Xin Long +Reviewed-by: Cong Wang +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + net/sched/cls_flower.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c +index 6ee7064c82fcc..bcf1b8012b2c3 100644 +--- a/net/sched/cls_flower.c ++++ b/net/sched/cls_flower.c +@@ -1320,7 +1320,6 @@ static int fl_set_erspan_opt(const struct nlattr *nla, struct fl_flow_key *key, + int err; + + md = (struct erspan_metadata *)&key->enc_opts.data[key->enc_opts.len]; +- memset(md, 0xff, sizeof(*md)); + md->version = 1; + + if (!depth) +@@ -1349,9 +1348,9 @@ static int fl_set_erspan_opt(const struct nlattr *nla, struct fl_flow_key *key, + NL_SET_ERR_MSG(extack, "Missing tunnel key erspan option index"); + return -EINVAL; + } ++ memset(&md->u.index, 0xff, sizeof(md->u.index)); + if (tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_INDEX]) { + nla = tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_INDEX]; +- memset(&md->u, 0x00, sizeof(md->u)); + md->u.index = nla_get_be32(nla); + } + } else if (md->version == 2) { +@@ -1360,10 +1359,12 @@ static int fl_set_erspan_opt(const struct nlattr *nla, struct fl_flow_key *key, + NL_SET_ERR_MSG(extack, "Missing tunnel key erspan option dir or hwid"); + return -EINVAL; + } ++ md->u.md2.dir = 1; + if (tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_DIR]) { + nla = tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_DIR]; + md->u.md2.dir = nla_get_u8(nla); + } ++ set_hwid(&md->u.md2, 0xff); + if (tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_HWID]) { + nla = tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_HWID]; + set_hwid(&md->u.md2, nla_get_u8(nla)); +-- +2.43.0 + diff --git a/queue-6.6/net-sched-tbf-correct-backlog-statistic-for-gso-pack.patch b/queue-6.6/net-sched-tbf-correct-backlog-statistic-for-gso-pack.patch new file mode 100644 index 00000000000..b01d046d538 --- /dev/null +++ b/queue-6.6/net-sched-tbf-correct-backlog-statistic-for-gso-pack.patch @@ -0,0 +1,90 @@ +From 600e24f040c747fb6aef575cf571ce86943df3f0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Nov 2024 18:46:07 +0100 +Subject: net/sched: tbf: correct backlog statistic for GSO packets + +From: Martin Ottens + +[ Upstream commit 1596a135e3180c92e42dd1fbcad321f4fb3e3b17 ] + +When the length of a GSO packet in the tbf qdisc is larger than the burst +size configured the packet will be segmented by the tbf_segment function. +Whenever this function is used to enqueue SKBs, the backlog statistic of +the tbf is not increased correctly. This can lead to underflows of the +'backlog' byte-statistic value when these packets are dequeued from tbf. + +Reproduce the bug: +Ensure that the sender machine has GSO enabled. Configured the tbf on +the outgoing interface of the machine as follows (burstsize = 1 MTU): +$ tc qdisc add dev root handle 1: tbf rate 50Mbit burst 1514 latency 50ms + +Send bulk TCP traffic out via this interface, e.g., by running an iPerf3 +client on this machine. Check the qdisc statistics: +$ tc -s qdisc show dev + +The 'backlog' byte-statistic has incorrect values while traffic is +transferred, e.g., high values due to u32 underflows. When the transfer +is stopped, the value is != 0, which should never happen. + +This patch fixes this bug by updating the statistics correctly, even if +single SKBs of a GSO SKB cannot be enqueued. + +Fixes: e43ac79a4bc6 ("sch_tbf: segment too big GSO packets") +Signed-off-by: Martin Ottens +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20241125174608.1484356-1-martin.ottens@fau.de +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/sched/sch_tbf.c | 18 ++++++++++++------ + 1 file changed, 12 insertions(+), 6 deletions(-) + +diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c +index 17d2d00ddb182..f92174008499b 100644 +--- a/net/sched/sch_tbf.c ++++ b/net/sched/sch_tbf.c +@@ -208,7 +208,7 @@ static int tbf_segment(struct sk_buff *skb, struct Qdisc *sch, + struct tbf_sched_data *q = qdisc_priv(sch); + struct sk_buff *segs, *nskb; + netdev_features_t features = netif_skb_features(skb); +- unsigned int len = 0, prev_len = qdisc_pkt_len(skb); ++ unsigned int len = 0, prev_len = qdisc_pkt_len(skb), seg_len; + int ret, nb; + + segs = skb_gso_segment(skb, features & ~NETIF_F_GSO_MASK); +@@ -219,21 +219,27 @@ static int tbf_segment(struct sk_buff *skb, struct Qdisc *sch, + nb = 0; + skb_list_walk_safe(segs, segs, nskb) { + skb_mark_not_on_list(segs); +- qdisc_skb_cb(segs)->pkt_len = segs->len; +- len += segs->len; ++ seg_len = segs->len; ++ qdisc_skb_cb(segs)->pkt_len = seg_len; + ret = qdisc_enqueue(segs, q->qdisc, to_free); + if (ret != NET_XMIT_SUCCESS) { + if (net_xmit_drop_count(ret)) + qdisc_qstats_drop(sch); + } else { + nb++; ++ len += seg_len; + } + } + sch->q.qlen += nb; +- if (nb > 1) ++ sch->qstats.backlog += len; ++ if (nb > 0) { + qdisc_tree_reduce_backlog(sch, 1 - nb, prev_len - len); +- consume_skb(skb); +- return nb > 0 ? NET_XMIT_SUCCESS : NET_XMIT_DROP; ++ consume_skb(skb); ++ return NET_XMIT_SUCCESS; ++ } ++ ++ kfree_skb(skb); ++ return NET_XMIT_DROP; + } + + static int tbf_enqueue(struct sk_buff *skb, struct Qdisc *sch, +-- +2.43.0 + diff --git a/queue-6.6/net-smc-add-operations-to-merge-sndbuf-with-peer-dmb.patch b/queue-6.6/net-smc-add-operations-to-merge-sndbuf-with-peer-dmb.patch new file mode 100644 index 00000000000..02da0d30fe6 --- /dev/null +++ b/queue-6.6/net-smc-add-operations-to-merge-sndbuf-with-peer-dmb.patch @@ -0,0 +1,127 @@ +From 691098ba12faec4ee6d6d83b2d1ed0ea30ccf267 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 28 Apr 2024 14:07:35 +0800 +Subject: net/smc: add operations to merge sndbuf with peer DMB + +From: Wen Gu + +[ Upstream commit 4398888268582cb51b69c6ee94f551bb8d37d12f ] + +In some scenarios using Emulated-ISM device, sndbuf can share the same +physical memory region with peer DMB to avoid data copy from one side +to the other. In such case the sndbuf is only a descriptor that +describes the shared memory and does not actually occupy memory, it's +more like a ghost buffer. + + +----------+ +----------+ + | socket A | | socket B | + +----------+ +----------+ + | | + +--------+ +--------+ + | sndbuf | | DMB | + | desc | | desc | + +--------+ +--------+ + | | + | +----v-----+ + +--------------------------> memory | + +----------+ + +So here introduces three new SMC-D device operations to check if this +feature is supported by device, and to {attach|detach} ghost sndbuf to +peer DMB. For now only loopback-ism supports this. + +Signed-off-by: Wen Gu +Reviewed-by: Wenjia Zhang +Reviewed-and-tested-by: Jan Karcher +Signed-off-by: Paolo Abeni +Stable-dep-of: 0541db8ee32c ("net/smc: initialize close_work early to avoid warning") +Signed-off-by: Sasha Levin +--- + include/net/smc.h | 3 +++ + net/smc/smc_ism.c | 40 ++++++++++++++++++++++++++++++++++++++++ + net/smc/smc_ism.h | 4 ++++ + 3 files changed, 47 insertions(+) + +diff --git a/include/net/smc.h b/include/net/smc.h +index 9dfe57f3e4f0b..6fef76087b9ed 100644 +--- a/include/net/smc.h ++++ b/include/net/smc.h +@@ -79,6 +79,9 @@ struct smcd_ops { + int (*reset_vlan_required)(struct smcd_dev *dev); + int (*signal_event)(struct smcd_dev *dev, struct smcd_gid *rgid, + u32 trigger_irq, u32 event_code, u64 info); ++ int (*support_dmb_nocopy)(struct smcd_dev *dev); ++ int (*attach_dmb)(struct smcd_dev *dev, struct smcd_dmb *dmb); ++ int (*detach_dmb)(struct smcd_dev *dev, u64 token); + }; + + struct smcd_dev { +diff --git a/net/smc/smc_ism.c b/net/smc/smc_ism.c +index 3623df320de55..61ffc72014013 100644 +--- a/net/smc/smc_ism.c ++++ b/net/smc/smc_ism.c +@@ -228,6 +228,46 @@ int smc_ism_register_dmb(struct smc_link_group *lgr, int dmb_len, + #endif + } + ++bool smc_ism_support_dmb_nocopy(struct smcd_dev *smcd) ++{ ++ /* for now only loopback-ism supports ++ * merging sndbuf with peer DMB to avoid ++ * data copies between them. ++ */ ++ return (smcd->ops->support_dmb_nocopy && ++ smcd->ops->support_dmb_nocopy(smcd)); ++} ++ ++int smc_ism_attach_dmb(struct smcd_dev *dev, u64 token, ++ struct smc_buf_desc *dmb_desc) ++{ ++ struct smcd_dmb dmb; ++ int rc = 0; ++ ++ if (!dev->ops->attach_dmb) ++ return -EINVAL; ++ ++ memset(&dmb, 0, sizeof(dmb)); ++ dmb.dmb_tok = token; ++ rc = dev->ops->attach_dmb(dev, &dmb); ++ if (!rc) { ++ dmb_desc->sba_idx = dmb.sba_idx; ++ dmb_desc->token = dmb.dmb_tok; ++ dmb_desc->cpu_addr = dmb.cpu_addr; ++ dmb_desc->dma_addr = dmb.dma_addr; ++ dmb_desc->len = dmb.dmb_len; ++ } ++ return rc; ++} ++ ++int smc_ism_detach_dmb(struct smcd_dev *dev, u64 token) ++{ ++ if (!dev->ops->detach_dmb) ++ return -EINVAL; ++ ++ return dev->ops->detach_dmb(dev, token); ++} ++ + static int smc_nl_handle_smcd_dev(struct smcd_dev *smcd, + struct sk_buff *skb, + struct netlink_callback *cb) +diff --git a/net/smc/smc_ism.h b/net/smc/smc_ism.h +index 0e5e563099ec3..8312c3586d2b3 100644 +--- a/net/smc/smc_ism.h ++++ b/net/smc/smc_ism.h +@@ -41,6 +41,10 @@ int smc_ism_put_vlan(struct smcd_dev *dev, unsigned short vlan_id); + int smc_ism_register_dmb(struct smc_link_group *lgr, int buf_size, + struct smc_buf_desc *dmb_desc); + int smc_ism_unregister_dmb(struct smcd_dev *dev, struct smc_buf_desc *dmb_desc); ++bool smc_ism_support_dmb_nocopy(struct smcd_dev *smcd); ++int smc_ism_attach_dmb(struct smcd_dev *dev, u64 token, ++ struct smc_buf_desc *dmb_desc); ++int smc_ism_detach_dmb(struct smcd_dev *dev, u64 token); + int smc_ism_signal_shutdown(struct smc_link_group *lgr); + void smc_ism_get_system_eid(u8 **eid); + u16 smc_ism_get_chid(struct smcd_dev *dev); +-- +2.43.0 + diff --git a/queue-6.6/net-smc-at-de-tach-sndbuf-to-peer-dmb-if-supported.patch b/queue-6.6/net-smc-at-de-tach-sndbuf-to-peer-dmb-if-supported.patch new file mode 100644 index 00000000000..1369ee70846 --- /dev/null +++ b/queue-6.6/net-smc-at-de-tach-sndbuf-to-peer-dmb-if-supported.patch @@ -0,0 +1,180 @@ +From 48daf19b52680d489b64e6e66725242ce02df0af Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 28 Apr 2024 14:07:36 +0800 +Subject: net/smc: {at|de}tach sndbuf to peer DMB if supported + +From: Wen Gu + +[ Upstream commit ae2be35cbed2c8385e890147ea321a3fcc3ca5fa ] + +If the device used by SMC-D supports merging local sndbuf to peer DMB, +then create sndbuf descriptor and attach it to peer DMB once peer +token is obtained, and detach and free the sndbuf descriptor when the +connection is freed. + +Signed-off-by: Wen Gu +Reviewed-by: Wenjia Zhang +Reviewed-and-tested-by: Jan Karcher +Signed-off-by: Paolo Abeni +Stable-dep-of: 0541db8ee32c ("net/smc: initialize close_work early to avoid warning") +Signed-off-by: Sasha Levin +--- + net/smc/af_smc.c | 16 ++++++++++++ + net/smc/smc_core.c | 61 +++++++++++++++++++++++++++++++++++++++++++++- + net/smc/smc_core.h | 1 + + 3 files changed, 77 insertions(+), 1 deletion(-) + +diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c +index f3ed53ae849d3..c4b30ea4b6ca0 100644 +--- a/net/smc/af_smc.c ++++ b/net/smc/af_smc.c +@@ -1418,6 +1418,14 @@ static int smc_connect_ism(struct smc_sock *smc, + } + + smc_conn_save_peer_info(smc, aclc); ++ ++ if (smc_ism_support_dmb_nocopy(smc->conn.lgr->smcd)) { ++ rc = smcd_buf_attach(smc); ++ if (rc) { ++ rc = SMC_CLC_DECL_MEM; /* try to fallback */ ++ goto connect_abort; ++ } ++ } + smc_close_init(smc); + smc_rx_init(smc); + smc_tx_init(smc); +@@ -2522,6 +2530,14 @@ static void smc_listen_work(struct work_struct *work) + mutex_unlock(&smc_server_lgr_pending); + } + smc_conn_save_peer_info(new_smc, cclc); ++ ++ if (ini->is_smcd && ++ smc_ism_support_dmb_nocopy(new_smc->conn.lgr->smcd)) { ++ rc = smcd_buf_attach(new_smc); ++ if (rc) ++ goto out_decl; ++ } ++ + smc_listen_out_connected(new_smc); + SMC_STAT_SERV_SUCC_INC(sock_net(newclcsock->sk), ini); + goto out_free; +diff --git a/net/smc/smc_core.c b/net/smc/smc_core.c +index 605cdff671d65..0eeb0d4353446 100644 +--- a/net/smc/smc_core.c ++++ b/net/smc/smc_core.c +@@ -1143,6 +1143,20 @@ static void smcr_buf_unuse(struct smc_buf_desc *buf_desc, bool is_rmb, + } + } + ++static void smcd_buf_detach(struct smc_connection *conn) ++{ ++ struct smcd_dev *smcd = conn->lgr->smcd; ++ u64 peer_token = conn->peer_token; ++ ++ if (!conn->sndbuf_desc) ++ return; ++ ++ smc_ism_detach_dmb(smcd, peer_token); ++ ++ kfree(conn->sndbuf_desc); ++ conn->sndbuf_desc = NULL; ++} ++ + static void smc_buf_unuse(struct smc_connection *conn, + struct smc_link_group *lgr) + { +@@ -1186,6 +1200,8 @@ void smc_conn_free(struct smc_connection *conn) + if (lgr->is_smcd) { + if (!list_empty(&lgr->list)) + smc_ism_unset_conn(conn); ++ if (smc_ism_support_dmb_nocopy(lgr->smcd)) ++ smcd_buf_detach(conn); + tasklet_kill(&conn->rx_tsklet); + } else { + smc_cdc_wait_pend_tx_wr(conn); +@@ -1439,6 +1455,8 @@ static void smc_conn_kill(struct smc_connection *conn, bool soft) + smc_sk_wake_ups(smc); + if (conn->lgr->is_smcd) { + smc_ism_unset_conn(conn); ++ if (smc_ism_support_dmb_nocopy(conn->lgr->smcd)) ++ smcd_buf_detach(conn); + if (soft) + tasklet_kill(&conn->rx_tsklet); + else +@@ -2453,12 +2471,18 @@ int smc_buf_create(struct smc_sock *smc, bool is_smcd) + int rc; + + /* create send buffer */ ++ if (is_smcd && ++ smc_ism_support_dmb_nocopy(smc->conn.lgr->smcd)) ++ goto create_rmb; ++ + rc = __smc_buf_create(smc, is_smcd, false); + if (rc) + return rc; ++ ++create_rmb: + /* create rmb */ + rc = __smc_buf_create(smc, is_smcd, true); +- if (rc) { ++ if (rc && smc->conn.sndbuf_desc) { + down_write(&smc->conn.lgr->sndbufs_lock); + list_del(&smc->conn.sndbuf_desc->list); + up_write(&smc->conn.lgr->sndbufs_lock); +@@ -2468,6 +2492,41 @@ int smc_buf_create(struct smc_sock *smc, bool is_smcd) + return rc; + } + ++int smcd_buf_attach(struct smc_sock *smc) ++{ ++ struct smc_connection *conn = &smc->conn; ++ struct smcd_dev *smcd = conn->lgr->smcd; ++ u64 peer_token = conn->peer_token; ++ struct smc_buf_desc *buf_desc; ++ int rc; ++ ++ buf_desc = kzalloc(sizeof(*buf_desc), GFP_KERNEL); ++ if (!buf_desc) ++ return -ENOMEM; ++ ++ /* The ghost sndbuf_desc describes the same memory region as ++ * peer RMB. Its lifecycle is consistent with the connection's ++ * and it will be freed with the connections instead of the ++ * link group. ++ */ ++ rc = smc_ism_attach_dmb(smcd, peer_token, buf_desc); ++ if (rc) ++ goto free; ++ ++ smc->sk.sk_sndbuf = buf_desc->len; ++ buf_desc->cpu_addr = ++ (u8 *)buf_desc->cpu_addr + sizeof(struct smcd_cdc_msg); ++ buf_desc->len -= sizeof(struct smcd_cdc_msg); ++ conn->sndbuf_desc = buf_desc; ++ conn->sndbuf_desc->used = 1; ++ atomic_set(&conn->sndbuf_space, conn->sndbuf_desc->len); ++ return 0; ++ ++free: ++ kfree(buf_desc); ++ return rc; ++} ++ + static inline int smc_rmb_reserve_rtoken_idx(struct smc_link_group *lgr) + { + int i; +diff --git a/net/smc/smc_core.h b/net/smc/smc_core.h +index 670f8359da558..de001f4b46c7d 100644 +--- a/net/smc/smc_core.h ++++ b/net/smc/smc_core.h +@@ -556,6 +556,7 @@ void smc_smcd_terminate(struct smcd_dev *dev, struct smcd_gid *peer_gid, + void smc_smcd_terminate_all(struct smcd_dev *dev); + void smc_smcr_terminate_all(struct smc_ib_device *smcibdev); + int smc_buf_create(struct smc_sock *smc, bool is_smcd); ++int smcd_buf_attach(struct smc_sock *smc); + int smc_uncompress_bufsize(u8 compressed); + int smc_rmb_rtoken_handling(struct smc_connection *conn, struct smc_link *link, + struct smc_clc_msg_accept_confirm *clc); +-- +2.43.0 + diff --git a/queue-6.6/net-smc-compatible-with-128-bits-extended-gid-of-vir.patch b/queue-6.6/net-smc-compatible-with-128-bits-extended-gid-of-vir.patch new file mode 100644 index 00000000000..b663d3c8d58 --- /dev/null +++ b/queue-6.6/net-smc-compatible-with-128-bits-extended-gid-of-vir.patch @@ -0,0 +1,694 @@ +From b1a79e6f353052fa8cf1e0fc0b3fc34023b83080 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 Dec 2023 22:26:13 +0800 +Subject: net/smc: compatible with 128-bits extended GID of virtual ISM device + +From: Wen Gu + +[ Upstream commit b40584d145700addc70cc29e4f0850a4ed955b1c ] + +According to virtual ISM support feature defined by SMCv2.1, GIDs of +virtual ISM device are UUIDs defined by RFC4122, which are 128-bits +long. So some adaptation work is required. And note that the GIDs of +existing platform firmware ISM devices still remain 64-bits long. + +Signed-off-by: Wen Gu +Reviewed-by: Alexandra Winter +Signed-off-by: David S. Miller +Stable-dep-of: 0541db8ee32c ("net/smc: initialize close_work early to avoid warning") +Signed-off-by: Sasha Levin +--- + drivers/s390/net/ism_drv.c | 19 ++++++----- + include/net/smc.h | 15 ++++++--- + net/smc/af_smc.c | 66 ++++++++++++++++++++++++++++++-------- + net/smc/smc.h | 3 -- + net/smc/smc_clc.c | 43 ++++++++++++++++++------- + net/smc/smc_clc.h | 10 ++++-- + net/smc/smc_core.c | 31 ++++++++++++------ + net/smc/smc_core.h | 17 +++++++--- + net/smc/smc_diag.c | 7 ++-- + net/smc/smc_ism.c | 17 ++++++---- + net/smc/smc_ism.h | 3 +- + net/smc/smc_pnet.c | 4 +-- + 12 files changed, 167 insertions(+), 68 deletions(-) + +diff --git a/drivers/s390/net/ism_drv.c b/drivers/s390/net/ism_drv.c +index 622a61f8a3b84..f6a0626a6b3ec 100644 +--- a/drivers/s390/net/ism_drv.c ++++ b/drivers/s390/net/ism_drv.c +@@ -762,10 +762,10 @@ static int ism_query_rgid(struct ism_dev *ism, u64 rgid, u32 vid_valid, + return ism_cmd(ism, &cmd); + } + +-static int smcd_query_rgid(struct smcd_dev *smcd, u64 rgid, u32 vid_valid, +- u32 vid) ++static int smcd_query_rgid(struct smcd_dev *smcd, struct smcd_gid *rgid, ++ u32 vid_valid, u32 vid) + { +- return ism_query_rgid(smcd->priv, rgid, vid_valid, vid); ++ return ism_query_rgid(smcd->priv, rgid->gid, vid_valid, vid); + } + + static int smcd_register_dmb(struct smcd_dev *smcd, struct smcd_dmb *dmb, +@@ -816,10 +816,11 @@ static int ism_signal_ieq(struct ism_dev *ism, u64 rgid, u32 trigger_irq, + return ism_cmd(ism, &cmd); + } + +-static int smcd_signal_ieq(struct smcd_dev *smcd, u64 rgid, u32 trigger_irq, +- u32 event_code, u64 info) ++static int smcd_signal_ieq(struct smcd_dev *smcd, struct smcd_gid *rgid, ++ u32 trigger_irq, u32 event_code, u64 info) + { +- return ism_signal_ieq(smcd->priv, rgid, trigger_irq, event_code, info); ++ return ism_signal_ieq(smcd->priv, rgid->gid, ++ trigger_irq, event_code, info); + } + + static int smcd_move(struct smcd_dev *smcd, u64 dmb_tok, unsigned int idx, +@@ -840,9 +841,11 @@ static u64 ism_get_local_gid(struct ism_dev *ism) + return ism->local_gid; + } + +-static u64 smcd_get_local_gid(struct smcd_dev *smcd) ++static void smcd_get_local_gid(struct smcd_dev *smcd, ++ struct smcd_gid *smcd_gid) + { +- return ism_get_local_gid(smcd->priv); ++ smcd_gid->gid = ism_get_local_gid(smcd->priv); ++ smcd_gid->gid_ext = 0; + } + + static u16 ism_get_chid(struct ism_dev *ism) +diff --git a/include/net/smc.h b/include/net/smc.h +index a002552be29c3..a0dc1187e96ed 100644 +--- a/include/net/smc.h ++++ b/include/net/smc.h +@@ -52,9 +52,14 @@ struct smcd_dmb { + struct smcd_dev; + struct ism_client; + ++struct smcd_gid { ++ u64 gid; ++ u64 gid_ext; ++}; ++ + struct smcd_ops { +- int (*query_remote_gid)(struct smcd_dev *dev, u64 rgid, u32 vid_valid, +- u32 vid); ++ int (*query_remote_gid)(struct smcd_dev *dev, struct smcd_gid *rgid, ++ u32 vid_valid, u32 vid); + int (*register_dmb)(struct smcd_dev *dev, struct smcd_dmb *dmb, + struct ism_client *client); + int (*unregister_dmb)(struct smcd_dev *dev, struct smcd_dmb *dmb); +@@ -62,14 +67,14 @@ struct smcd_ops { + int (*del_vlan_id)(struct smcd_dev *dev, u64 vlan_id); + int (*set_vlan_required)(struct smcd_dev *dev); + int (*reset_vlan_required)(struct smcd_dev *dev); +- int (*signal_event)(struct smcd_dev *dev, u64 rgid, u32 trigger_irq, +- u32 event_code, u64 info); ++ int (*signal_event)(struct smcd_dev *dev, struct smcd_gid *rgid, ++ u32 trigger_irq, u32 event_code, u64 info); + int (*move_data)(struct smcd_dev *dev, u64 dmb_tok, unsigned int idx, + bool sf, unsigned int offset, void *data, + unsigned int size); + int (*supports_v2)(void); + u8* (*get_system_eid)(void); +- u64 (*get_local_gid)(struct smcd_dev *dev); ++ void (*get_local_gid)(struct smcd_dev *dev, struct smcd_gid *gid); + u16 (*get_chid)(struct smcd_dev *dev); + struct device* (*get_dev)(struct smcd_dev *dev); + }; +diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c +index ea24fb4dae0df..f3ed53ae849d3 100644 +--- a/net/smc/af_smc.c ++++ b/net/smc/af_smc.c +@@ -1026,7 +1026,8 @@ static int smc_find_ism_v2_device_clnt(struct smc_sock *smc, + { + int rc = SMC_CLC_DECL_NOSMCDDEV; + struct smcd_dev *smcd; +- int i = 1; ++ int i = 1, entry = 1; ++ bool is_virtual; + u16 chid; + + if (smcd_indicated(ini->smc_type_v1)) +@@ -1038,14 +1039,23 @@ static int smc_find_ism_v2_device_clnt(struct smc_sock *smc, + chid = smc_ism_get_chid(smcd); + if (!smc_find_ism_v2_is_unique_chid(chid, ini, i)) + continue; ++ is_virtual = __smc_ism_is_virtual(chid); + if (!smc_pnet_is_pnetid_set(smcd->pnetid) || + smc_pnet_is_ndev_pnetid(sock_net(&smc->sk), smcd->pnetid)) { ++ if (is_virtual && entry == SMCD_CLC_MAX_V2_GID_ENTRIES) ++ /* It's the last GID-CHID entry left in CLC ++ * Proposal SMC-Dv2 extension, but a virtual ++ * ISM device will take two entries. So give ++ * up it and try the next potential ISM device. ++ */ ++ continue; + ini->ism_dev[i] = smcd; + ini->ism_chid[i] = chid; + ini->is_smcd = true; + rc = 0; + i++; +- if (i > SMC_MAX_ISM_DEVS) ++ entry = is_virtual ? entry + 2 : entry + 1; ++ if (entry > SMCD_CLC_MAX_V2_GID_ENTRIES) + break; + } + } +@@ -1384,8 +1394,13 @@ static int smc_connect_ism(struct smc_sock *smc, + rc = smc_v2_determine_accepted_chid(aclc, ini); + if (rc) + return rc; ++ ++ if (__smc_ism_is_virtual(ini->ism_chid[ini->ism_selected])) ++ ini->ism_peer_gid[ini->ism_selected].gid_ext = ++ ntohll(aclc->d1.gid_ext); ++ /* for non-virtual ISM devices, peer gid_ext remains 0. */ + } +- ini->ism_peer_gid[ini->ism_selected] = ntohll(aclc->d0.gid); ++ ini->ism_peer_gid[ini->ism_selected].gid = ntohll(aclc->d0.gid); + + /* there is only one lgr role for SMC-D; use server lock */ + mutex_lock(&smc_server_lgr_pending); +@@ -2070,7 +2085,8 @@ static bool smc_is_already_selected(struct smcd_dev *smcd, + + /* check for ISM devices matching proposed ISM devices */ + static void smc_check_ism_v2_match(struct smc_init_info *ini, +- u16 proposed_chid, u64 proposed_gid, ++ u16 proposed_chid, ++ struct smcd_gid *proposed_gid, + unsigned int *matches) + { + struct smcd_dev *smcd; +@@ -2082,7 +2098,11 @@ static void smc_check_ism_v2_match(struct smc_init_info *ini, + continue; + if (smc_ism_get_chid(smcd) == proposed_chid && + !smc_ism_cantalk(proposed_gid, ISM_RESERVED_VLANID, smcd)) { +- ini->ism_peer_gid[*matches] = proposed_gid; ++ ini->ism_peer_gid[*matches].gid = proposed_gid->gid; ++ if (__smc_ism_is_virtual(proposed_chid)) ++ ini->ism_peer_gid[*matches].gid_ext = ++ proposed_gid->gid_ext; ++ /* non-virtual ISM's peer gid_ext remains 0. */ + ini->ism_dev[*matches] = smcd; + (*matches)++; + break; +@@ -2104,9 +2124,11 @@ static void smc_find_ism_v2_device_serv(struct smc_sock *new_smc, + struct smc_clc_v2_extension *smc_v2_ext; + struct smc_clc_msg_smcd *pclc_smcd; + unsigned int matches = 0; ++ struct smcd_gid smcd_gid; + u8 smcd_version; + u8 *eid = NULL; + int i, rc; ++ u16 chid; + + if (!(ini->smcd_version & SMC_V2) || !smcd_indicated(ini->smc_type_v2)) + goto not_found; +@@ -2116,18 +2138,35 @@ static void smc_find_ism_v2_device_serv(struct smc_sock *new_smc, + smcd_v2_ext = smc_get_clc_smcd_v2_ext(smc_v2_ext); + + mutex_lock(&smcd_dev_list.mutex); +- if (pclc_smcd->ism.chid) ++ if (pclc_smcd->ism.chid) { + /* check for ISM device matching proposed native ISM device */ ++ smcd_gid.gid = ntohll(pclc_smcd->ism.gid); ++ smcd_gid.gid_ext = 0; + smc_check_ism_v2_match(ini, ntohs(pclc_smcd->ism.chid), +- ntohll(pclc_smcd->ism.gid), &matches); +- for (i = 1; i <= smc_v2_ext->hdr.ism_gid_cnt; i++) { ++ &smcd_gid, &matches); ++ } ++ for (i = 0; i < smc_v2_ext->hdr.ism_gid_cnt; i++) { + /* check for ISM devices matching proposed non-native ISM + * devices + */ +- smc_check_ism_v2_match(ini, +- ntohs(smcd_v2_ext->gidchid[i - 1].chid), +- ntohll(smcd_v2_ext->gidchid[i - 1].gid), +- &matches); ++ smcd_gid.gid = ntohll(smcd_v2_ext->gidchid[i].gid); ++ smcd_gid.gid_ext = 0; ++ chid = ntohs(smcd_v2_ext->gidchid[i].chid); ++ if (__smc_ism_is_virtual(chid)) { ++ if ((i + 1) == smc_v2_ext->hdr.ism_gid_cnt || ++ chid != ntohs(smcd_v2_ext->gidchid[i + 1].chid)) ++ /* each virtual ISM device takes two GID-CHID ++ * entries and CHID of the second entry repeats ++ * that of the first entry. ++ * ++ * So check if the next GID-CHID entry exists ++ * and both two entries' CHIDs are the same. ++ */ ++ continue; ++ smcd_gid.gid_ext = ++ ntohll(smcd_v2_ext->gidchid[++i].gid); ++ } ++ smc_check_ism_v2_match(ini, chid, &smcd_gid, &matches); + } + mutex_unlock(&smcd_dev_list.mutex); + +@@ -2176,7 +2215,8 @@ static void smc_find_ism_v1_device_serv(struct smc_sock *new_smc, + if (!(ini->smcd_version & SMC_V1) || !smcd_indicated(ini->smc_type_v1)) + goto not_found; + ini->is_smcd = true; /* prepare ISM check */ +- ini->ism_peer_gid[0] = ntohll(pclc_smcd->ism.gid); ++ ini->ism_peer_gid[0].gid = ntohll(pclc_smcd->ism.gid); ++ ini->ism_peer_gid[0].gid_ext = 0; + rc = smc_find_ism_device(new_smc, ini); + if (rc) + goto not_found; +diff --git a/net/smc/smc.h b/net/smc/smc.h +index e377980b84145..e0afef7a786f8 100644 +--- a/net/smc/smc.h ++++ b/net/smc/smc.h +@@ -29,9 +29,6 @@ + #define SMCPROTO_SMC 0 /* SMC protocol, IPv4 */ + #define SMCPROTO_SMC6 1 /* SMC protocol, IPv6 */ + +-#define SMC_MAX_ISM_DEVS 8 /* max # of proposed non-native ISM +- * devices +- */ + #define SMC_AUTOCORKING_DEFAULT_SIZE 0x10000 /* 64K by default */ + + extern struct proto smc_proto; +diff --git a/net/smc/smc_clc.c b/net/smc/smc_clc.c +index a28dee81d6fa4..0084960a203dc 100644 +--- a/net/smc/smc_clc.c ++++ b/net/smc/smc_clc.c +@@ -891,11 +891,13 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini) + ETH_ALEN); + } + if (smcd_indicated(ini->smc_type_v1)) { ++ struct smcd_gid smcd_gid; ++ + /* add SMC-D specifics */ + if (ini->ism_dev[0]) { + smcd = ini->ism_dev[0]; +- pclc_smcd->ism.gid = +- htonll(smcd->ops->get_local_gid(smcd)); ++ smcd->ops->get_local_gid(smcd, &smcd_gid); ++ pclc_smcd->ism.gid = htonll(smcd_gid.gid); + pclc_smcd->ism.chid = + htons(smc_ism_get_chid(ini->ism_dev[0])); + } +@@ -927,10 +929,11 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini) + read_unlock(&smc_clc_eid_table.lock); + } + if (smcd_indicated(ini->smc_type_v2)) { ++ struct smcd_gid smcd_gid; + u8 *eid = NULL; ++ int entry = 0; + + v2_ext->hdr.flag.seid = smc_clc_eid_table.seid_enabled; +- v2_ext->hdr.ism_gid_cnt = ini->ism_offered_cnt; + v2_ext->hdr.smcd_v2_ext_offset = htons(sizeof(*v2_ext) - + offsetofend(struct smc_clnt_opts_area_hdr, + smcd_v2_ext_offset) + +@@ -942,14 +945,26 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini) + if (ini->ism_offered_cnt) { + for (i = 1; i <= ini->ism_offered_cnt; i++) { + smcd = ini->ism_dev[i]; +- gidchids[i - 1].gid = +- htonll(smcd->ops->get_local_gid(smcd)); +- gidchids[i - 1].chid = ++ smcd->ops->get_local_gid(smcd, &smcd_gid); ++ gidchids[entry].chid = + htons(smc_ism_get_chid(ini->ism_dev[i])); ++ gidchids[entry].gid = htonll(smcd_gid.gid); ++ if (smc_ism_is_virtual(smcd)) { ++ /* a virtual ISM device takes two ++ * entries. CHID of the second entry ++ * repeats that of the first entry. ++ */ ++ gidchids[entry + 1].chid = ++ gidchids[entry].chid; ++ gidchids[entry + 1].gid = ++ htonll(smcd_gid.gid_ext); ++ entry++; ++ } ++ entry++; + } +- plen += ini->ism_offered_cnt * +- sizeof(struct smc_clc_smcd_gid_chid); ++ plen += entry * sizeof(struct smc_clc_smcd_gid_chid); + } ++ v2_ext->hdr.ism_gid_cnt = entry; + } + if (smcr_indicated(ini->smc_type_v2)) { + memcpy(v2_ext->roce, ini->smcrv2.ib_gid_v2, SMC_GID_SIZE); +@@ -985,7 +1000,7 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini) + vec[i++].iov_len = sizeof(*smcd_v2_ext); + if (ini->ism_offered_cnt) { + vec[i].iov_base = gidchids; +- vec[i++].iov_len = ini->ism_offered_cnt * ++ vec[i++].iov_len = v2_ext->hdr.ism_gid_cnt * + sizeof(struct smc_clc_smcd_gid_chid); + } + } +@@ -1016,13 +1031,16 @@ smcd_clc_prep_confirm_accept(struct smc_connection *conn, + struct smc_clc_msg_trail *trl) + { + struct smcd_dev *smcd = conn->lgr->smcd; ++ struct smcd_gid smcd_gid; ++ u16 chid; + int len; + + /* SMC-D specific settings */ + memcpy(clc->hdr.eyecatcher, SMCD_EYECATCHER, + sizeof(SMCD_EYECATCHER)); ++ smcd->ops->get_local_gid(smcd, &smcd_gid); + clc->hdr.typev1 = SMC_TYPE_D; +- clc->d0.gid = htonll(smcd->ops->get_local_gid(smcd)); ++ clc->d0.gid = htonll(smcd_gid.gid); + clc->d0.token = htonll(conn->rmb_desc->token); + clc->d0.dmbe_size = conn->rmbe_size_comp; + clc->d0.dmbe_idx = 0; +@@ -1030,9 +1048,12 @@ smcd_clc_prep_confirm_accept(struct smc_connection *conn, + if (version == SMC_V1) { + clc->hdr.length = htons(SMCD_CLC_ACCEPT_CONFIRM_LEN); + } else { +- clc->d1.chid = htons(smc_ism_get_chid(smcd)); ++ chid = smc_ism_get_chid(smcd); ++ clc->d1.chid = htons(chid); + if (eid && eid[0]) + memcpy(clc->d1.eid, eid, SMC_MAX_EID_LEN); ++ if (__smc_ism_is_virtual(chid)) ++ clc->d1.gid_ext = htonll(smcd_gid.gid_ext); + len = SMCD_CLC_ACCEPT_CONFIRM_LEN_V2; + if (first_contact) { + *fce_len = smc_clc_fill_fce_v2x(fce_v2x, ini); +diff --git a/net/smc/smc_clc.h b/net/smc/smc_clc.h +index d7b1716cfb0fd..c8d6282ec9c04 100644 +--- a/net/smc/smc_clc.h ++++ b/net/smc/smc_clc.h +@@ -171,6 +171,11 @@ struct smc_clc_msg_proposal { /* clc proposal message sent by Linux */ + + #define SMC_CLC_MAX_V6_PREFIX 8 + #define SMC_CLC_MAX_UEID 8 ++#define SMCD_CLC_MAX_V2_GID_ENTRIES 8 /* max # of CHID-GID entries in CLC ++ * proposal SMC-Dv2 extension. ++ * each ISM device takes one entry and ++ * each virtual ISM takes two entries. ++ */ + + struct smc_clc_msg_proposal_area { + struct smc_clc_msg_proposal pclc_base; +@@ -180,7 +185,8 @@ struct smc_clc_msg_proposal_area { + struct smc_clc_v2_extension pclc_v2_ext; + u8 user_eids[SMC_CLC_MAX_UEID][SMC_MAX_EID_LEN]; + struct smc_clc_smcd_v2_extension pclc_smcd_v2_ext; +- struct smc_clc_smcd_gid_chid pclc_gidchids[SMC_MAX_ISM_DEVS]; ++ struct smc_clc_smcd_gid_chid ++ pclc_gidchids[SMCD_CLC_MAX_V2_GID_ENTRIES]; + struct smc_clc_msg_trail pclc_trl; + }; + +@@ -271,7 +277,7 @@ struct smc_clc_msg_accept_confirm { /* clc accept / confirm message */ + struct { /* v2 only, but 12 bytes reserved in v1 */ + __be16 chid; + u8 eid[SMC_MAX_EID_LEN]; +- u8 reserved5[8]; ++ __be64 gid_ext; + } __packed d1; + }; + }; +diff --git a/net/smc/smc_core.c b/net/smc/smc_core.c +index f99bb9d0adcc6..605cdff671d65 100644 +--- a/net/smc/smc_core.c ++++ b/net/smc/smc_core.c +@@ -506,6 +506,7 @@ static int smc_nl_fill_smcd_lgr(struct smc_link_group *lgr, + { + char smc_pnet[SMC_MAX_PNETID_LEN + 1]; + struct smcd_dev *smcd = lgr->smcd; ++ struct smcd_gid smcd_gid; + struct nlattr *attrs; + void *nlh; + +@@ -521,11 +522,11 @@ static int smc_nl_fill_smcd_lgr(struct smc_link_group *lgr, + + if (nla_put_u32(skb, SMC_NLA_LGR_D_ID, *((u32 *)&lgr->id))) + goto errattr; ++ smcd->ops->get_local_gid(smcd, &smcd_gid); + if (nla_put_u64_64bit(skb, SMC_NLA_LGR_D_GID, +- smcd->ops->get_local_gid(smcd), +- SMC_NLA_LGR_D_PAD)) ++ smcd_gid.gid, SMC_NLA_LGR_D_PAD)) + goto errattr; +- if (nla_put_u64_64bit(skb, SMC_NLA_LGR_D_PEER_GID, lgr->peer_gid, ++ if (nla_put_u64_64bit(skb, SMC_NLA_LGR_D_PEER_GID, lgr->peer_gid.gid, + SMC_NLA_LGR_D_PAD)) + goto errattr; + if (nla_put_u8(skb, SMC_NLA_LGR_D_VLAN_ID, lgr->vlan_id)) +@@ -876,7 +877,10 @@ static int smc_lgr_create(struct smc_sock *smc, struct smc_init_info *ini) + /* SMC-D specific settings */ + smcd = ini->ism_dev[ini->ism_selected]; + get_device(smcd->ops->get_dev(smcd)); +- lgr->peer_gid = ini->ism_peer_gid[ini->ism_selected]; ++ lgr->peer_gid.gid = ++ ini->ism_peer_gid[ini->ism_selected].gid; ++ lgr->peer_gid.gid_ext = ++ ini->ism_peer_gid[ini->ism_selected].gid_ext; + lgr->smcd = ini->ism_dev[ini->ism_selected]; + lgr_list = &ini->ism_dev[ini->ism_selected]->lgr_list; + lgr_lock = &lgr->smcd->lgr_lock; +@@ -1514,7 +1518,8 @@ void smc_lgr_terminate_sched(struct smc_link_group *lgr) + } + + /* Called when peer lgr shutdown (regularly or abnormally) is received */ +-void smc_smcd_terminate(struct smcd_dev *dev, u64 peer_gid, unsigned short vlan) ++void smc_smcd_terminate(struct smcd_dev *dev, struct smcd_gid *peer_gid, ++ unsigned short vlan) + { + struct smc_link_group *lgr, *l; + LIST_HEAD(lgr_free_list); +@@ -1522,9 +1527,12 @@ void smc_smcd_terminate(struct smcd_dev *dev, u64 peer_gid, unsigned short vlan) + /* run common cleanup function and build free list */ + spin_lock_bh(&dev->lgr_lock); + list_for_each_entry_safe(lgr, l, &dev->lgr_list, list) { +- if ((!peer_gid || lgr->peer_gid == peer_gid) && ++ if ((!peer_gid->gid || ++ (lgr->peer_gid.gid == peer_gid->gid && ++ !smc_ism_is_virtual(dev) ? 1 : ++ lgr->peer_gid.gid_ext == peer_gid->gid_ext)) && + (vlan == VLAN_VID_MASK || lgr->vlan_id == vlan)) { +- if (peer_gid) /* peer triggered termination */ ++ if (peer_gid->gid) /* peer triggered termination */ + lgr->peer_shutdown = 1; + list_move(&lgr->list, &lgr_free_list); + lgr->freeing = 1; +@@ -1860,9 +1868,12 @@ static bool smcr_lgr_match(struct smc_link_group *lgr, u8 smcr_version, + } + + static bool smcd_lgr_match(struct smc_link_group *lgr, +- struct smcd_dev *smcismdev, u64 peer_gid) ++ struct smcd_dev *smcismdev, ++ struct smcd_gid *peer_gid) + { +- return lgr->peer_gid == peer_gid && lgr->smcd == smcismdev; ++ return lgr->peer_gid.gid == peer_gid->gid && lgr->smcd == smcismdev && ++ smc_ism_is_virtual(smcismdev) ? ++ (lgr->peer_gid.gid_ext == peer_gid->gid_ext) : 1; + } + + /* create a new SMC connection (and a new link group if necessary) */ +@@ -1892,7 +1903,7 @@ int smc_conn_create(struct smc_sock *smc, struct smc_init_info *ini) + write_lock_bh(&lgr->conns_lock); + if ((ini->is_smcd ? + smcd_lgr_match(lgr, ini->ism_dev[ini->ism_selected], +- ini->ism_peer_gid[ini->ism_selected]) : ++ &ini->ism_peer_gid[ini->ism_selected]) : + smcr_lgr_match(lgr, ini->smcr_version, + ini->peer_systemid, + ini->peer_gid, ini->peer_mac, role, +diff --git a/net/smc/smc_core.h b/net/smc/smc_core.h +index 120027d404692..670f8359da558 100644 +--- a/net/smc/smc_core.h ++++ b/net/smc/smc_core.h +@@ -17,9 +17,11 @@ + #include + #include + #include ++#include + + #include "smc.h" + #include "smc_ib.h" ++#include "smc_clc.h" + + #define SMC_RMBS_PER_LGR_MAX 255 /* max. # of RMBs per link group */ + #define SMC_CONN_PER_LGR_MIN 16 /* min. # of connections per link group */ +@@ -355,7 +357,7 @@ struct smc_link_group { + /* max links can be added in lgr */ + }; + struct { /* SMC-D */ +- u64 peer_gid; ++ struct smcd_gid peer_gid; + /* Peer GID (remote) */ + struct smcd_dev *smcd; + /* ISM device for VLAN reg. */ +@@ -392,6 +394,11 @@ struct smc_init_info_smcrv2 { + struct smc_gidlist gidlist; + }; + ++#define SMC_MAX_V2_ISM_DEVS SMCD_CLC_MAX_V2_GID_ENTRIES ++ /* max # of proposed non-native ISM devices, ++ * which can't exceed the max # of CHID-GID ++ * entries in CLC proposal SMC-Dv2 extension. ++ */ + struct smc_init_info { + u8 is_smcd; + u8 smc_type_v1; +@@ -416,9 +423,9 @@ struct smc_init_info { + u32 ib_clcqpn; + struct smc_init_info_smcrv2 smcrv2; + /* SMC-D */ +- u64 ism_peer_gid[SMC_MAX_ISM_DEVS + 1]; +- struct smcd_dev *ism_dev[SMC_MAX_ISM_DEVS + 1]; +- u16 ism_chid[SMC_MAX_ISM_DEVS + 1]; ++ struct smcd_gid ism_peer_gid[SMC_MAX_V2_ISM_DEVS + 1]; ++ struct smcd_dev *ism_dev[SMC_MAX_V2_ISM_DEVS + 1]; ++ u16 ism_chid[SMC_MAX_V2_ISM_DEVS + 1]; + u8 ism_offered_cnt; /* # of ISM devices offered */ + u8 ism_selected; /* index of selected ISM dev*/ + u8 smcd_version; +@@ -544,7 +551,7 @@ void smc_lgr_hold(struct smc_link_group *lgr); + void smc_lgr_put(struct smc_link_group *lgr); + void smcr_port_add(struct smc_ib_device *smcibdev, u8 ibport); + void smcr_port_err(struct smc_ib_device *smcibdev, u8 ibport); +-void smc_smcd_terminate(struct smcd_dev *dev, u64 peer_gid, ++void smc_smcd_terminate(struct smcd_dev *dev, struct smcd_gid *peer_gid, + unsigned short vlan); + void smc_smcd_terminate_all(struct smcd_dev *dev); + void smc_smcr_terminate_all(struct smc_ib_device *smcibdev); +diff --git a/net/smc/smc_diag.c b/net/smc/smc_diag.c +index d58c699b5328a..086e48b3cdea6 100644 +--- a/net/smc/smc_diag.c ++++ b/net/smc/smc_diag.c +@@ -21,6 +21,7 @@ + + #include "smc.h" + #include "smc_core.h" ++#include "smc_ism.h" + + struct smc_diag_dump_ctx { + int pos[2]; +@@ -167,12 +168,14 @@ static int __smc_diag_dump(struct sock *sk, struct sk_buff *skb, + struct smc_connection *conn = &smc->conn; + struct smcd_diag_dmbinfo dinfo; + struct smcd_dev *smcd = conn->lgr->smcd; ++ struct smcd_gid smcd_gid; + + memset(&dinfo, 0, sizeof(dinfo)); + + dinfo.linkid = *((u32 *)conn->lgr->id); +- dinfo.peer_gid = conn->lgr->peer_gid; +- dinfo.my_gid = smcd->ops->get_local_gid(smcd); ++ dinfo.peer_gid = conn->lgr->peer_gid.gid; ++ smcd->ops->get_local_gid(smcd, &smcd_gid); ++ dinfo.my_gid = smcd_gid.gid; + dinfo.token = conn->rmb_desc->token; + dinfo.peer_token = conn->peer_token; + +diff --git a/net/smc/smc_ism.c b/net/smc/smc_ism.c +index fbee2493091f1..a33f861cf7c19 100644 +--- a/net/smc/smc_ism.c ++++ b/net/smc/smc_ism.c +@@ -44,7 +44,8 @@ static struct ism_client smc_ism_client = { + #endif + + /* Test if an ISM communication is possible - same CPC */ +-int smc_ism_cantalk(u64 peer_gid, unsigned short vlan_id, struct smcd_dev *smcd) ++int smc_ism_cantalk(struct smcd_gid *peer_gid, unsigned short vlan_id, ++ struct smcd_dev *smcd) + { + return smcd->ops->query_remote_gid(smcd, peer_gid, vlan_id ? 1 : 0, + vlan_id); +@@ -208,7 +209,7 @@ int smc_ism_register_dmb(struct smc_link_group *lgr, int dmb_len, + dmb.dmb_len = dmb_len; + dmb.sba_idx = dmb_desc->sba_idx; + dmb.vlan_id = lgr->vlan_id; +- dmb.rgid = lgr->peer_gid; ++ dmb.rgid = lgr->peer_gid.gid; + rc = lgr->smcd->ops->register_dmb(lgr->smcd, &dmb, &smc_ism_client); + if (!rc) { + dmb_desc->sba_idx = dmb.sba_idx; +@@ -340,18 +341,20 @@ union smcd_sw_event_info { + + static void smcd_handle_sw_event(struct smc_ism_event_work *wrk) + { ++ struct smcd_gid peer_gid = { .gid = wrk->event.tok, ++ .gid_ext = 0 }; + union smcd_sw_event_info ev_info; + + ev_info.info = wrk->event.info; + switch (wrk->event.code) { + case ISM_EVENT_CODE_SHUTDOWN: /* Peer shut down DMBs */ +- smc_smcd_terminate(wrk->smcd, wrk->event.tok, ev_info.vlan_id); ++ smc_smcd_terminate(wrk->smcd, &peer_gid, ev_info.vlan_id); + break; + case ISM_EVENT_CODE_TESTLINK: /* Activity timer */ + if (ev_info.code == ISM_EVENT_REQUEST) { + ev_info.code = ISM_EVENT_RESPONSE; + wrk->smcd->ops->signal_event(wrk->smcd, +- wrk->event.tok, ++ &peer_gid, + ISM_EVENT_REQUEST_IR, + ISM_EVENT_CODE_TESTLINK, + ev_info.info); +@@ -365,10 +368,12 @@ static void smc_ism_event_work(struct work_struct *work) + { + struct smc_ism_event_work *wrk = + container_of(work, struct smc_ism_event_work, work); ++ struct smcd_gid smcd_gid = { .gid = wrk->event.tok, ++ .gid_ext = 0 }; + + switch (wrk->event.type) { + case ISM_EVENT_GID: /* GID event, token is peer GID */ +- smc_smcd_terminate(wrk->smcd, wrk->event.tok, VLAN_VID_MASK); ++ smc_smcd_terminate(wrk->smcd, &smcd_gid, VLAN_VID_MASK); + break; + case ISM_EVENT_DMB: + break; +@@ -525,7 +530,7 @@ int smc_ism_signal_shutdown(struct smc_link_group *lgr) + memcpy(ev_info.uid, lgr->id, SMC_LGR_ID_SIZE); + ev_info.vlan_id = lgr->vlan_id; + ev_info.code = ISM_EVENT_REQUEST; +- rc = lgr->smcd->ops->signal_event(lgr->smcd, lgr->peer_gid, ++ rc = lgr->smcd->ops->signal_event(lgr->smcd, &lgr->peer_gid, + ISM_EVENT_REQUEST_IR, + ISM_EVENT_CODE_SHUTDOWN, + ev_info.info); +diff --git a/net/smc/smc_ism.h b/net/smc/smc_ism.h +index d1228a615f23c..0e5e563099ec3 100644 +--- a/net/smc/smc_ism.h ++++ b/net/smc/smc_ism.h +@@ -32,7 +32,8 @@ struct smc_ism_vlanid { /* VLAN id set on ISM device */ + + struct smcd_dev; + +-int smc_ism_cantalk(u64 peer_gid, unsigned short vlan_id, struct smcd_dev *dev); ++int smc_ism_cantalk(struct smcd_gid *peer_gid, unsigned short vlan_id, ++ struct smcd_dev *dev); + void smc_ism_set_conn(struct smc_connection *conn); + void smc_ism_unset_conn(struct smc_connection *conn); + int smc_ism_get_vlan(struct smcd_dev *dev, unsigned short vlan_id); +diff --git a/net/smc/smc_pnet.c b/net/smc/smc_pnet.c +index 284cec1e20ec1..dbcc72b43d0c0 100644 +--- a/net/smc/smc_pnet.c ++++ b/net/smc/smc_pnet.c +@@ -1113,8 +1113,8 @@ static void smc_pnet_find_ism_by_pnetid(struct net_device *ndev, + list_for_each_entry(ismdev, &smcd_dev_list.list, list) { + if (smc_pnet_match(ismdev->pnetid, ndev_pnetid) && + !ismdev->going_away && +- (!ini->ism_peer_gid[0] || +- !smc_ism_cantalk(ini->ism_peer_gid[0], ini->vlan_id, ++ (!ini->ism_peer_gid[0].gid || ++ !smc_ism_cantalk(&ini->ism_peer_gid[0], ini->vlan_id, + ismdev))) { + ini->ism_dev[0] = ismdev; + break; +-- +2.43.0 + diff --git a/queue-6.6/net-smc-define-a-reserved-chid-range-for-virtual-ism.patch b/queue-6.6/net-smc-define-a-reserved-chid-range-for-virtual-ism.patch new file mode 100644 index 00000000000..2a601299778 --- /dev/null +++ b/queue-6.6/net-smc-define-a-reserved-chid-range-for-virtual-ism.patch @@ -0,0 +1,64 @@ +From f199d60614fb7bbaba78492728b5b7a8b4e2dbd5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 Dec 2023 22:26:12 +0800 +Subject: net/smc: define a reserved CHID range for virtual ISM devices + +From: Wen Gu + +[ Upstream commit 8dd512df3c98ce8081e3541990bf849157675723 ] + +According to virtual ISM support feature defined by SMCv2.1, CHIDs in +the range 0xFF00 to 0xFFFF are reserved for use by virtual ISM devices. + +And two helpers are introduced to distinguish virtual ISM devices from +the existing platform firmware ISM devices. + +Signed-off-by: Wen Gu +Reviewed-and-tested-by: Wenjia Zhang +Reviewed-by: Alexandra Winter +Signed-off-by: David S. Miller +Stable-dep-of: 0541db8ee32c ("net/smc: initialize close_work early to avoid warning") +Signed-off-by: Sasha Levin +--- + net/smc/smc_ism.h | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + +diff --git a/net/smc/smc_ism.h b/net/smc/smc_ism.h +index 832b2f42d79f3..d1228a615f23c 100644 +--- a/net/smc/smc_ism.h ++++ b/net/smc/smc_ism.h +@@ -15,6 +15,8 @@ + + #include "smc.h" + ++#define SMC_VIRTUAL_ISM_CHID_MASK 0xFF00 ++ + struct smcd_dev_list { /* List of SMCD devices */ + struct list_head list; + struct mutex mutex; /* Protects list of devices */ +@@ -56,4 +58,22 @@ static inline int smc_ism_write(struct smcd_dev *smcd, u64 dmb_tok, + return rc < 0 ? rc : 0; + } + ++static inline bool __smc_ism_is_virtual(u16 chid) ++{ ++ /* CHIDs in range of 0xFF00 to 0xFFFF are reserved ++ * for virtual ISM device. ++ * ++ * loopback-ism: 0xFFFF ++ * virtio-ism: 0xFF00 ~ 0xFFFE ++ */ ++ return ((chid & 0xFF00) == 0xFF00); ++} ++ ++static inline bool smc_ism_is_virtual(struct smcd_dev *smcd) ++{ ++ u16 chid = smcd->ops->get_chid(smcd); ++ ++ return __smc_ism_is_virtual(chid); ++} ++ + #endif +-- +2.43.0 + diff --git a/queue-6.6/net-smc-fix-lgr-and-link-use-after-free-issue.patch b/queue-6.6/net-smc-fix-lgr-and-link-use-after-free-issue.patch new file mode 100644 index 00000000000..7c4882d6ae4 --- /dev/null +++ b/queue-6.6/net-smc-fix-lgr-and-link-use-after-free-issue.patch @@ -0,0 +1,92 @@ +From 7510ba86773185e342545903770f1f0be0813dfc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 Nov 2024 21:30:14 +0800 +Subject: net/smc: fix LGR and link use-after-free issue + +From: Wen Gu + +[ Upstream commit 2c7f14ed9c19ec0f149479d1c2842ec1f9bf76d7 ] + +We encountered a LGR/link use-after-free issue, which manifested as +the LGR/link refcnt reaching 0 early and entering the clear process, +making resource access unsafe. + + refcount_t: addition on 0; use-after-free. + WARNING: CPU: 14 PID: 107447 at lib/refcount.c:25 refcount_warn_saturate+0x9c/0x140 + Workqueue: events smc_lgr_terminate_work [smc] + Call trace: + refcount_warn_saturate+0x9c/0x140 + __smc_lgr_terminate.part.45+0x2a8/0x370 [smc] + smc_lgr_terminate_work+0x28/0x30 [smc] + process_one_work+0x1b8/0x420 + worker_thread+0x158/0x510 + kthread+0x114/0x118 + +or + + refcount_t: underflow; use-after-free. + WARNING: CPU: 6 PID: 93140 at lib/refcount.c:28 refcount_warn_saturate+0xf0/0x140 + Workqueue: smc_hs_wq smc_listen_work [smc] + Call trace: + refcount_warn_saturate+0xf0/0x140 + smcr_link_put+0x1cc/0x1d8 [smc] + smc_conn_free+0x110/0x1b0 [smc] + smc_conn_abort+0x50/0x60 [smc] + smc_listen_find_device+0x75c/0x790 [smc] + smc_listen_work+0x368/0x8a0 [smc] + process_one_work+0x1b8/0x420 + worker_thread+0x158/0x510 + kthread+0x114/0x118 + +It is caused by repeated release of LGR/link refcnt. One suspect is that +smc_conn_free() is called repeatedly because some smc_conn_free() from +server listening path are not protected by sock lock. + +e.g. + +Calls under socklock | smc_listen_work +------------------------------------------------------- +lock_sock(sk) | smc_conn_abort +smc_conn_free | \- smc_conn_free +\- smcr_link_put | \- smcr_link_put (duplicated) +release_sock(sk) + +So here add sock lock protection in smc_listen_work() path, making it +exclusive with other connection operations. + +Fixes: 3b2dec2603d5 ("net/smc: restructure client and server code in af_smc") +Co-developed-by: Guangguan Wang +Signed-off-by: Guangguan Wang +Co-developed-by: Kai +Signed-off-by: Kai +Signed-off-by: Wen Gu +Reviewed-by: Wenjia Zhang +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/smc/af_smc.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c +index 755659703a625..77c6c0dff069e 100644 +--- a/net/smc/af_smc.c ++++ b/net/smc/af_smc.c +@@ -1907,6 +1907,7 @@ static void smc_listen_out(struct smc_sock *new_smc) + if (tcp_sk(new_smc->clcsock->sk)->syn_smc) + atomic_dec(&lsmc->queued_smc_hs); + ++ release_sock(newsmcsk); /* lock in smc_listen_work() */ + if (lsmc->sk.sk_state == SMC_LISTEN) { + lock_sock_nested(&lsmc->sk, SINGLE_DEPTH_NESTING); + smc_accept_enqueue(&lsmc->sk, newsmcsk); +@@ -2428,6 +2429,7 @@ static void smc_listen_work(struct work_struct *work) + u8 accept_version; + int rc = 0; + ++ lock_sock(&new_smc->sk); /* release in smc_listen_out() */ + if (new_smc->listen_smc->sk.sk_state != SMC_LISTEN) + return smc_listen_out_err(new_smc); + +-- +2.43.0 + diff --git a/queue-6.6/net-smc-initialize-close_work-early-to-avoid-warning.patch b/queue-6.6/net-smc-initialize-close_work-early-to-avoid-warning.patch new file mode 100644 index 00000000000..2c3cd3a7ad9 --- /dev/null +++ b/queue-6.6/net-smc-initialize-close_work-early-to-avoid-warning.patch @@ -0,0 +1,100 @@ +From 2abd14f64246ccfa5bbaa214b9e7247ba5bd9f07 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 Nov 2024 21:30:13 +0800 +Subject: net/smc: initialize close_work early to avoid warning + +From: Wen Gu + +[ Upstream commit 0541db8ee32c09463a72d0987382b3a3336b0043 ] + +We encountered a warning that close_work was canceled before +initialization. + + WARNING: CPU: 7 PID: 111103 at kernel/workqueue.c:3047 __flush_work+0x19e/0x1b0 + Workqueue: events smc_lgr_terminate_work [smc] + RIP: 0010:__flush_work+0x19e/0x1b0 + Call Trace: + ? __wake_up_common+0x7a/0x190 + ? work_busy+0x80/0x80 + __cancel_work_timer+0xe3/0x160 + smc_close_cancel_work+0x1a/0x70 [smc] + smc_close_active_abort+0x207/0x360 [smc] + __smc_lgr_terminate.part.38+0xc8/0x180 [smc] + process_one_work+0x19e/0x340 + worker_thread+0x30/0x370 + ? process_one_work+0x340/0x340 + kthread+0x117/0x130 + ? __kthread_cancel_work+0x50/0x50 + ret_from_fork+0x22/0x30 + +This is because when smc_close_cancel_work is triggered, e.g. the RDMA +driver is rmmod and the LGR is terminated, the conn->close_work is +flushed before initialization, resulting in WARN_ON(!work->func). + +__smc_lgr_terminate | smc_connect_{rdma|ism} +------------------------------------------------------------- + | smc_conn_create + | \- smc_lgr_register_conn +for conn in lgr->conns_all | +\- smc_conn_kill | + \- smc_close_active_abort | + \- smc_close_cancel_work | + \- cancel_work_sync | + \- __flush_work | + (close_work) | + | smc_close_init + | \- INIT_WORK(&close_work) + +So fix this by initializing close_work before establishing the +connection. + +Fixes: 46c28dbd4c23 ("net/smc: no socket state changes in tasklet context") +Fixes: 413498440e30 ("net/smc: add SMC-D support in af_smc") +Signed-off-by: Wen Gu +Reviewed-by: Wenjia Zhang +Reviewed-by: Alexandra Winter +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/smc/af_smc.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c +index f343e91eec0e4..755659703a625 100644 +--- a/net/smc/af_smc.c ++++ b/net/smc/af_smc.c +@@ -383,6 +383,7 @@ void smc_sk_init(struct net *net, struct sock *sk, int protocol) + smc->limit_smc_hs = net->smc.limit_smc_hs; + smc->use_fallback = false; /* assume rdma capability first */ + smc->fallback_rsn = 0; ++ smc_close_init(smc); + } + + static struct sock *smc_sock_alloc(struct net *net, struct socket *sock, +@@ -1298,7 +1299,6 @@ static int smc_connect_rdma(struct smc_sock *smc, + goto connect_abort; + } + +- smc_close_init(smc); + smc_rx_init(smc); + + if (ini->first_contact_local) { +@@ -1434,7 +1434,6 @@ static int smc_connect_ism(struct smc_sock *smc, + goto connect_abort; + } + } +- smc_close_init(smc); + smc_rx_init(smc); + smc_tx_init(smc); + +@@ -2486,7 +2485,6 @@ static void smc_listen_work(struct work_struct *work) + goto out_decl; + + mutex_lock(&smc_server_lgr_pending); +- smc_close_init(new_smc); + smc_rx_init(new_smc); + smc_tx_init(new_smc); + +-- +2.43.0 + diff --git a/queue-6.6/net-smc-introduce-sub-functions-for-smc_clc_send_con.patch b/queue-6.6/net-smc-introduce-sub-functions-for-smc_clc_send_con.patch new file mode 100644 index 00000000000..16086400cab --- /dev/null +++ b/queue-6.6/net-smc-introduce-sub-functions-for-smc_clc_send_con.patch @@ -0,0 +1,250 @@ +From a00eb93176ca82cf4e16fce91b293593a10f4f2c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 Dec 2023 22:26:08 +0800 +Subject: net/smc: introduce sub-functions for smc_clc_send_confirm_accept() + +From: Wen Gu + +[ Upstream commit 5205ac4483b630e47c65f192a3ac19be7a8ea648 ] + +There is a large if-else block in smc_clc_send_confirm_accept() and it +is better to split it into two sub-functions. + +Suggested-by: Alexandra Winter +Signed-off-by: Wen Gu +Reviewed-by: Alexandra Winter +Signed-off-by: David S. Miller +Stable-dep-of: 0541db8ee32c ("net/smc: initialize close_work early to avoid warning") +Signed-off-by: Sasha Levin +--- + net/smc/smc_clc.c | 197 +++++++++++++++++++++++++++------------------- + 1 file changed, 115 insertions(+), 82 deletions(-) + +diff --git a/net/smc/smc_clc.c b/net/smc/smc_clc.c +index b34aff73ada4c..d471a06baac32 100644 +--- a/net/smc/smc_clc.c ++++ b/net/smc/smc_clc.c +@@ -1007,6 +1007,112 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini) + return reason_code; + } + ++static void ++smcd_clc_prep_confirm_accept(struct smc_connection *conn, ++ struct smc_clc_msg_accept_confirm_v2 *clc_v2, ++ int first_contact, u8 version, ++ u8 *eid, struct smc_init_info *ini, ++ int *fce_len, ++ struct smc_clc_first_contact_ext_v2x *fce_v2x, ++ struct smc_clc_msg_trail *trl) ++{ ++ struct smcd_dev *smcd = conn->lgr->smcd; ++ struct smc_clc_msg_accept_confirm *clc; ++ int len; ++ ++ /* SMC-D specific settings */ ++ clc = (struct smc_clc_msg_accept_confirm *)clc_v2; ++ memcpy(clc->hdr.eyecatcher, SMCD_EYECATCHER, ++ sizeof(SMCD_EYECATCHER)); ++ clc->hdr.typev1 = SMC_TYPE_D; ++ clc->d0.gid = htonll(smcd->ops->get_local_gid(smcd)); ++ clc->d0.token = htonll(conn->rmb_desc->token); ++ clc->d0.dmbe_size = conn->rmbe_size_comp; ++ clc->d0.dmbe_idx = 0; ++ memcpy(&clc->d0.linkid, conn->lgr->id, SMC_LGR_ID_SIZE); ++ if (version == SMC_V1) { ++ clc->hdr.length = htons(SMCD_CLC_ACCEPT_CONFIRM_LEN); ++ } else { ++ clc_v2->d1.chid = htons(smc_ism_get_chid(smcd)); ++ if (eid && eid[0]) ++ memcpy(clc_v2->d1.eid, eid, SMC_MAX_EID_LEN); ++ len = SMCD_CLC_ACCEPT_CONFIRM_LEN_V2; ++ if (first_contact) { ++ *fce_len = smc_clc_fill_fce_v2x(fce_v2x, ini); ++ len += *fce_len; ++ } ++ clc_v2->hdr.length = htons(len); ++ } ++ memcpy(trl->eyecatcher, SMCD_EYECATCHER, ++ sizeof(SMCD_EYECATCHER)); ++} ++ ++static void ++smcr_clc_prep_confirm_accept(struct smc_connection *conn, ++ struct smc_clc_msg_accept_confirm_v2 *clc_v2, ++ int first_contact, u8 version, ++ u8 *eid, struct smc_init_info *ini, ++ int *fce_len, ++ struct smc_clc_first_contact_ext_v2x *fce_v2x, ++ struct smc_clc_fce_gid_ext *gle, ++ struct smc_clc_msg_trail *trl) ++{ ++ struct smc_clc_msg_accept_confirm *clc; ++ struct smc_link *link = conn->lnk; ++ int len; ++ ++ /* SMC-R specific settings */ ++ clc = (struct smc_clc_msg_accept_confirm *)clc_v2; ++ memcpy(clc->hdr.eyecatcher, SMC_EYECATCHER, ++ sizeof(SMC_EYECATCHER)); ++ clc->hdr.typev1 = SMC_TYPE_R; ++ memcpy(clc->r0.lcl.id_for_peer, local_systemid, ++ sizeof(local_systemid)); ++ memcpy(&clc->r0.lcl.gid, link->gid, SMC_GID_SIZE); ++ memcpy(&clc->r0.lcl.mac, &link->smcibdev->mac[link->ibport - 1], ++ ETH_ALEN); ++ hton24(clc->r0.qpn, link->roce_qp->qp_num); ++ clc->r0.rmb_rkey = ++ htonl(conn->rmb_desc->mr[link->link_idx]->rkey); ++ clc->r0.rmbe_idx = 1; /* for now: 1 RMB = 1 RMBE */ ++ clc->r0.rmbe_alert_token = htonl(conn->alert_token_local); ++ switch (clc->hdr.type) { ++ case SMC_CLC_ACCEPT: ++ clc->r0.qp_mtu = link->path_mtu; ++ break; ++ case SMC_CLC_CONFIRM: ++ clc->r0.qp_mtu = min(link->path_mtu, link->peer_mtu); ++ break; ++ } ++ clc->r0.rmbe_size = conn->rmbe_size_comp; ++ clc->r0.rmb_dma_addr = conn->rmb_desc->is_vm ? ++ cpu_to_be64((uintptr_t)conn->rmb_desc->cpu_addr) : ++ cpu_to_be64((u64)sg_dma_address ++ (conn->rmb_desc->sgt[link->link_idx].sgl)); ++ hton24(clc->r0.psn, link->psn_initial); ++ if (version == SMC_V1) { ++ clc->hdr.length = htons(SMCR_CLC_ACCEPT_CONFIRM_LEN); ++ } else { ++ if (eid && eid[0]) ++ memcpy(clc_v2->r1.eid, eid, SMC_MAX_EID_LEN); ++ len = SMCR_CLC_ACCEPT_CONFIRM_LEN_V2; ++ if (first_contact) { ++ *fce_len = smc_clc_fill_fce_v2x(fce_v2x, ini); ++ len += *fce_len; ++ fce_v2x->fce_v2_base.v2_direct = ++ !link->lgr->uses_gateway; ++ if (clc->hdr.type == SMC_CLC_CONFIRM) { ++ memset(gle, 0, sizeof(*gle)); ++ gle->gid_cnt = ini->smcrv2.gidlist.len; ++ len += sizeof(*gle); ++ len += gle->gid_cnt * sizeof(gle->gid[0]); ++ } ++ } ++ clc_v2->hdr.length = htons(len); ++ } ++ memcpy(trl->eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER)); ++} ++ + /* build and send CLC CONFIRM / ACCEPT message */ + static int smc_clc_send_confirm_accept(struct smc_sock *smc, + struct smc_clc_msg_accept_confirm_v2 *clc_v2, +@@ -1015,11 +1121,10 @@ static int smc_clc_send_confirm_accept(struct smc_sock *smc, + { + struct smc_clc_first_contact_ext_v2x fce_v2x; + struct smc_connection *conn = &smc->conn; +- struct smcd_dev *smcd = conn->lgr->smcd; + struct smc_clc_msg_accept_confirm *clc; + struct smc_clc_fce_gid_ext gle; + struct smc_clc_msg_trail trl; +- int i, len, fce_len; ++ int i, fce_len; + struct kvec vec[5]; + struct msghdr msg; + +@@ -1028,86 +1133,14 @@ static int smc_clc_send_confirm_accept(struct smc_sock *smc, + clc->hdr.version = version; /* SMC version */ + if (first_contact) + clc->hdr.typev2 |= SMC_FIRST_CONTACT_MASK; +- if (conn->lgr->is_smcd) { +- /* SMC-D specific settings */ +- memcpy(clc->hdr.eyecatcher, SMCD_EYECATCHER, +- sizeof(SMCD_EYECATCHER)); +- clc->hdr.typev1 = SMC_TYPE_D; +- clc->d0.gid = htonll(smcd->ops->get_local_gid(smcd)); +- clc->d0.token = htonll(conn->rmb_desc->token); +- clc->d0.dmbe_size = conn->rmbe_size_comp; +- clc->d0.dmbe_idx = 0; +- memcpy(&clc->d0.linkid, conn->lgr->id, SMC_LGR_ID_SIZE); +- if (version == SMC_V1) { +- clc->hdr.length = htons(SMCD_CLC_ACCEPT_CONFIRM_LEN); +- } else { +- clc_v2->d1.chid = htons(smc_ism_get_chid(smcd)); +- if (eid && eid[0]) +- memcpy(clc_v2->d1.eid, eid, SMC_MAX_EID_LEN); +- len = SMCD_CLC_ACCEPT_CONFIRM_LEN_V2; +- if (first_contact) { +- fce_len = smc_clc_fill_fce_v2x(&fce_v2x, ini); +- len += fce_len; +- } +- clc_v2->hdr.length = htons(len); +- } +- memcpy(trl.eyecatcher, SMCD_EYECATCHER, +- sizeof(SMCD_EYECATCHER)); +- } else { +- struct smc_link *link = conn->lnk; +- +- /* SMC-R specific settings */ +- memcpy(clc->hdr.eyecatcher, SMC_EYECATCHER, +- sizeof(SMC_EYECATCHER)); +- clc->hdr.typev1 = SMC_TYPE_R; +- clc->hdr.length = htons(SMCR_CLC_ACCEPT_CONFIRM_LEN); +- memcpy(clc->r0.lcl.id_for_peer, local_systemid, +- sizeof(local_systemid)); +- memcpy(&clc->r0.lcl.gid, link->gid, SMC_GID_SIZE); +- memcpy(&clc->r0.lcl.mac, &link->smcibdev->mac[link->ibport - 1], +- ETH_ALEN); +- hton24(clc->r0.qpn, link->roce_qp->qp_num); +- clc->r0.rmb_rkey = +- htonl(conn->rmb_desc->mr[link->link_idx]->rkey); +- clc->r0.rmbe_idx = 1; /* for now: 1 RMB = 1 RMBE */ +- clc->r0.rmbe_alert_token = htonl(conn->alert_token_local); +- switch (clc->hdr.type) { +- case SMC_CLC_ACCEPT: +- clc->r0.qp_mtu = link->path_mtu; +- break; +- case SMC_CLC_CONFIRM: +- clc->r0.qp_mtu = min(link->path_mtu, link->peer_mtu); +- break; +- } +- clc->r0.rmbe_size = conn->rmbe_size_comp; +- clc->r0.rmb_dma_addr = conn->rmb_desc->is_vm ? +- cpu_to_be64((uintptr_t)conn->rmb_desc->cpu_addr) : +- cpu_to_be64((u64)sg_dma_address +- (conn->rmb_desc->sgt[link->link_idx].sgl)); +- hton24(clc->r0.psn, link->psn_initial); +- if (version == SMC_V1) { +- clc->hdr.length = htons(SMCR_CLC_ACCEPT_CONFIRM_LEN); +- } else { +- if (eid && eid[0]) +- memcpy(clc_v2->r1.eid, eid, SMC_MAX_EID_LEN); +- len = SMCR_CLC_ACCEPT_CONFIRM_LEN_V2; +- if (first_contact) { +- fce_len = smc_clc_fill_fce_v2x(&fce_v2x, ini); +- len += fce_len; +- fce_v2x.fce_v2_base.v2_direct = +- !link->lgr->uses_gateway; +- if (clc->hdr.type == SMC_CLC_CONFIRM) { +- memset(&gle, 0, sizeof(gle)); +- gle.gid_cnt = ini->smcrv2.gidlist.len; +- len += sizeof(gle); +- len += gle.gid_cnt * sizeof(gle.gid[0]); +- } +- } +- clc_v2->hdr.length = htons(len); +- } +- memcpy(trl.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER)); +- } +- ++ if (conn->lgr->is_smcd) ++ smcd_clc_prep_confirm_accept(conn, clc_v2, first_contact, ++ version, eid, ini, &fce_len, ++ &fce_v2x, &trl); ++ else ++ smcr_clc_prep_confirm_accept(conn, clc_v2, first_contact, ++ version, eid, ini, &fce_len, ++ &fce_v2x, &gle, &trl); + memset(&msg, 0, sizeof(msg)); + i = 0; + vec[i].iov_base = clc_v2; +-- +2.43.0 + diff --git a/queue-6.6/net-smc-mark-optional-smcd_ops-and-check-for-support.patch b/queue-6.6/net-smc-mark-optional-smcd_ops-and-check-for-support.patch new file mode 100644 index 00000000000..9e282ee8f52 --- /dev/null +++ b/queue-6.6/net-smc-mark-optional-smcd_ops-and-check-for-support.patch @@ -0,0 +1,99 @@ +From 1dc94ae6574e8c5068e87374548931af15df371e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 28 Apr 2024 14:07:32 +0800 +Subject: net/smc: mark optional smcd_ops and check for support when called + +From: Wen Gu + +[ Upstream commit d1d8d0b6c7c68b0665456831fa779174ebd78f90 ] + +Some operations are not supported by new introduced Emulated-ISM, so +mark them as optional and check if the device supports them when called. + +Signed-off-by: Wen Gu +Reviewed-by: Wenjia Zhang +Reviewed-and-tested-by: Jan Karcher +Signed-off-by: Paolo Abeni +Stable-dep-of: 0541db8ee32c ("net/smc: initialize close_work early to avoid warning") +Signed-off-by: Sasha Levin +--- + include/net/smc.h | 14 ++++++++------ + net/smc/smc_ism.c | 9 ++++++++- + 2 files changed, 16 insertions(+), 7 deletions(-) + +diff --git a/include/net/smc.h b/include/net/smc.h +index a0dc1187e96ed..9dfe57f3e4f0b 100644 +--- a/include/net/smc.h ++++ b/include/net/smc.h +@@ -63,12 +63,6 @@ struct smcd_ops { + int (*register_dmb)(struct smcd_dev *dev, struct smcd_dmb *dmb, + struct ism_client *client); + int (*unregister_dmb)(struct smcd_dev *dev, struct smcd_dmb *dmb); +- int (*add_vlan_id)(struct smcd_dev *dev, u64 vlan_id); +- int (*del_vlan_id)(struct smcd_dev *dev, u64 vlan_id); +- int (*set_vlan_required)(struct smcd_dev *dev); +- int (*reset_vlan_required)(struct smcd_dev *dev); +- int (*signal_event)(struct smcd_dev *dev, struct smcd_gid *rgid, +- u32 trigger_irq, u32 event_code, u64 info); + int (*move_data)(struct smcd_dev *dev, u64 dmb_tok, unsigned int idx, + bool sf, unsigned int offset, void *data, + unsigned int size); +@@ -77,6 +71,14 @@ struct smcd_ops { + void (*get_local_gid)(struct smcd_dev *dev, struct smcd_gid *gid); + u16 (*get_chid)(struct smcd_dev *dev); + struct device* (*get_dev)(struct smcd_dev *dev); ++ ++ /* optional operations */ ++ int (*add_vlan_id)(struct smcd_dev *dev, u64 vlan_id); ++ int (*del_vlan_id)(struct smcd_dev *dev, u64 vlan_id); ++ int (*set_vlan_required)(struct smcd_dev *dev); ++ int (*reset_vlan_required)(struct smcd_dev *dev); ++ int (*signal_event)(struct smcd_dev *dev, struct smcd_gid *rgid, ++ u32 trigger_irq, u32 event_code, u64 info); + }; + + struct smcd_dev { +diff --git a/net/smc/smc_ism.c b/net/smc/smc_ism.c +index a33f861cf7c19..3623df320de55 100644 +--- a/net/smc/smc_ism.c ++++ b/net/smc/smc_ism.c +@@ -105,6 +105,8 @@ int smc_ism_get_vlan(struct smcd_dev *smcd, unsigned short vlanid) + + if (!vlanid) /* No valid vlan id */ + return -EINVAL; ++ if (!smcd->ops->add_vlan_id) ++ return -EOPNOTSUPP; + + /* create new vlan entry, in case we need it */ + new_vlan = kzalloc(sizeof(*new_vlan), GFP_KERNEL); +@@ -150,6 +152,8 @@ int smc_ism_put_vlan(struct smcd_dev *smcd, unsigned short vlanid) + + if (!vlanid) /* No valid vlan id */ + return -EINVAL; ++ if (!smcd->ops->del_vlan_id) ++ return -EOPNOTSUPP; + + spin_lock_irqsave(&smcd->lock, flags); + list_for_each_entry(vlan, &smcd->vlan, list) { +@@ -351,7 +355,8 @@ static void smcd_handle_sw_event(struct smc_ism_event_work *wrk) + smc_smcd_terminate(wrk->smcd, &peer_gid, ev_info.vlan_id); + break; + case ISM_EVENT_CODE_TESTLINK: /* Activity timer */ +- if (ev_info.code == ISM_EVENT_REQUEST) { ++ if (ev_info.code == ISM_EVENT_REQUEST && ++ wrk->smcd->ops->signal_event) { + ev_info.code = ISM_EVENT_RESPONSE; + wrk->smcd->ops->signal_event(wrk->smcd, + &peer_gid, +@@ -526,6 +531,8 @@ int smc_ism_signal_shutdown(struct smc_link_group *lgr) + + if (lgr->peer_shutdown) + return 0; ++ if (!lgr->smcd->ops->signal_event) ++ return 0; + + memcpy(ev_info.uid, lgr->id, SMC_LGR_ID_SIZE); + ev_info.vlan_id = lgr->vlan_id; +-- +2.43.0 + diff --git a/queue-6.6/net-smc-refactoring-initialization-of-smc-sock.patch b/queue-6.6/net-smc-refactoring-initialization-of-smc-sock.patch new file mode 100644 index 00000000000..1c345ca7e1c --- /dev/null +++ b/queue-6.6/net-smc-refactoring-initialization-of-smc-sock.patch @@ -0,0 +1,177 @@ +From 41ea23f5fc1b637a56820282043ffbc028f2b10d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 14 Jun 2024 02:00:28 +0800 +Subject: net/smc: refactoring initialization of smc sock + +From: D. Wythe + +[ Upstream commit d0e35656d83458d668593930f1568d464dde429c ] + +This patch aims to isolate the shared components of SMC socket +allocation by introducing smc_sk_init() for sock initialization +and __smc_create_clcsk() for the initialization of clcsock. + +This is in preparation for the subsequent implementation of the +AF_INET version of SMC. + +Signed-off-by: D. Wythe +Reviewed-by: Tony Lu +Reviewed-by: Wenjia Zhang +Reviewed-by: Dust Li +Tested-by: Niklas Schnelle +Tested-by: Wenjia Zhang +Signed-off-by: David S. Miller +Stable-dep-of: 0541db8ee32c ("net/smc: initialize close_work early to avoid warning") +Signed-off-by: Sasha Levin +--- + net/smc/af_smc.c | 86 +++++++++++++++++++++++++++--------------------- + net/smc/smc.h | 5 +++ + 2 files changed, 53 insertions(+), 38 deletions(-) + +diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c +index c4b30ea4b6ca0..f343e91eec0e4 100644 +--- a/net/smc/af_smc.c ++++ b/net/smc/af_smc.c +@@ -362,25 +362,15 @@ static void smc_destruct(struct sock *sk) + return; + } + +-static struct sock *smc_sock_alloc(struct net *net, struct socket *sock, +- int protocol) ++void smc_sk_init(struct net *net, struct sock *sk, int protocol) + { +- struct smc_sock *smc; +- struct proto *prot; +- struct sock *sk; +- +- prot = (protocol == SMCPROTO_SMC6) ? &smc_proto6 : &smc_proto; +- sk = sk_alloc(net, PF_SMC, GFP_KERNEL, prot, 0); +- if (!sk) +- return NULL; ++ struct smc_sock *smc = smc_sk(sk); + +- sock_init_data(sock, sk); /* sets sk_refcnt to 1 */ + sk->sk_state = SMC_INIT; + sk->sk_destruct = smc_destruct; + sk->sk_protocol = protocol; + WRITE_ONCE(sk->sk_sndbuf, 2 * READ_ONCE(net->smc.sysctl_wmem)); + WRITE_ONCE(sk->sk_rcvbuf, 2 * READ_ONCE(net->smc.sysctl_rmem)); +- smc = smc_sk(sk); + INIT_WORK(&smc->tcp_listen_work, smc_tcp_listen_work); + INIT_WORK(&smc->connect_work, smc_connect_work); + INIT_DELAYED_WORK(&smc->conn.tx_work, smc_tx_work); +@@ -390,6 +380,24 @@ static struct sock *smc_sock_alloc(struct net *net, struct socket *sock, + sk->sk_prot->hash(sk); + mutex_init(&smc->clcsock_release_lock); + smc_init_saved_callbacks(smc); ++ smc->limit_smc_hs = net->smc.limit_smc_hs; ++ smc->use_fallback = false; /* assume rdma capability first */ ++ smc->fallback_rsn = 0; ++} ++ ++static struct sock *smc_sock_alloc(struct net *net, struct socket *sock, ++ int protocol) ++{ ++ struct proto *prot; ++ struct sock *sk; ++ ++ prot = (protocol == SMCPROTO_SMC6) ? &smc_proto6 : &smc_proto; ++ sk = sk_alloc(net, PF_SMC, GFP_KERNEL, prot, 0); ++ if (!sk) ++ return NULL; ++ ++ sock_init_data(sock, sk); /* sets sk_refcnt to 1 */ ++ smc_sk_init(net, sk, protocol); + + return sk; + } +@@ -3303,6 +3311,31 @@ static const struct proto_ops smc_sock_ops = { + .splice_read = smc_splice_read, + }; + ++int smc_create_clcsk(struct net *net, struct sock *sk, int family) ++{ ++ struct smc_sock *smc = smc_sk(sk); ++ int rc; ++ ++ rc = sock_create_kern(net, family, SOCK_STREAM, IPPROTO_TCP, ++ &smc->clcsock); ++ if (rc) { ++ sk_common_release(sk); ++ return rc; ++ } ++ ++ /* smc_clcsock_release() does not wait smc->clcsock->sk's ++ * destruction; its sk_state might not be TCP_CLOSE after ++ * smc->sk is close()d, and TCP timers can be fired later, ++ * which need net ref. ++ */ ++ sk = smc->clcsock->sk; ++ __netns_tracker_free(net, &sk->ns_tracker, false); ++ sk->sk_net_refcnt = 1; ++ get_net_track(net, &sk->ns_tracker, GFP_KERNEL); ++ sock_inuse_add(net, 1); ++ return 0; ++} ++ + static int __smc_create(struct net *net, struct socket *sock, int protocol, + int kern, struct socket *clcsock) + { +@@ -3328,35 +3361,12 @@ static int __smc_create(struct net *net, struct socket *sock, int protocol, + + /* create internal TCP socket for CLC handshake and fallback */ + smc = smc_sk(sk); +- smc->use_fallback = false; /* assume rdma capability first */ +- smc->fallback_rsn = 0; +- +- /* default behavior from limit_smc_hs in every net namespace */ +- smc->limit_smc_hs = net->smc.limit_smc_hs; + + rc = 0; +- if (!clcsock) { +- rc = sock_create_kern(net, family, SOCK_STREAM, IPPROTO_TCP, +- &smc->clcsock); +- if (rc) { +- sk_common_release(sk); +- goto out; +- } +- +- /* smc_clcsock_release() does not wait smc->clcsock->sk's +- * destruction; its sk_state might not be TCP_CLOSE after +- * smc->sk is close()d, and TCP timers can be fired later, +- * which need net ref. +- */ +- sk = smc->clcsock->sk; +- __netns_tracker_free(net, &sk->ns_tracker, false); +- sk->sk_net_refcnt = 1; +- get_net_track(net, &sk->ns_tracker, GFP_KERNEL); +- sock_inuse_add(net, 1); +- } else { ++ if (clcsock) + smc->clcsock = clcsock; +- } +- ++ else ++ rc = smc_create_clcsk(net, sk, family); + out: + return rc; + } +diff --git a/net/smc/smc.h b/net/smc/smc.h +index e0afef7a786f8..36699ba551887 100644 +--- a/net/smc/smc.h ++++ b/net/smc/smc.h +@@ -34,6 +34,11 @@ + extern struct proto smc_proto; + extern struct proto smc_proto6; + ++/* smc sock initialization */ ++void smc_sk_init(struct net *net, struct sock *sk, int protocol); ++/* clcsock initialization */ ++int smc_create_clcsk(struct net *net, struct sock *sk, int family); ++ + #ifdef ATOMIC64_INIT + #define KERNEL_HAS_ATOMIC64 + #endif +-- +2.43.0 + diff --git a/queue-6.6/net-smc-rename-some-fce-to-fce_v2x-for-clarity.patch b/queue-6.6/net-smc-rename-some-fce-to-fce_v2x-for-clarity.patch new file mode 100644 index 00000000000..ee47f6e681b --- /dev/null +++ b/queue-6.6/net-smc-rename-some-fce-to-fce_v2x-for-clarity.patch @@ -0,0 +1,103 @@ +From 0043baf8ea53dbe5a0a3469307e5d8e81cbd9127 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 Dec 2023 22:26:07 +0800 +Subject: net/smc: rename some 'fce' to 'fce_v2x' for clarity + +From: Wen Gu + +[ Upstream commit ac053a169c71ceb0f25f784fce9ea720455097b4 ] + +Rename some functions or variables with 'fce' in their name but used in +SMCv2.1 as 'fce_v2x' for clarity. + +Signed-off-by: Wen Gu +Signed-off-by: David S. Miller +Stable-dep-of: 0541db8ee32c ("net/smc: initialize close_work early to avoid warning") +Signed-off-by: Sasha Levin +--- + net/smc/smc_clc.c | 30 ++++++++++++++++-------------- + 1 file changed, 16 insertions(+), 14 deletions(-) + +diff --git a/net/smc/smc_clc.c b/net/smc/smc_clc.c +index 1489a8421d786..b34aff73ada4c 100644 +--- a/net/smc/smc_clc.c ++++ b/net/smc/smc_clc.c +@@ -428,15 +428,16 @@ smc_clc_msg_decl_valid(struct smc_clc_msg_decline *dclc) + return true; + } + +-static int smc_clc_fill_fce(struct smc_clc_first_contact_ext_v2x *fce, +- struct smc_init_info *ini) ++static int smc_clc_fill_fce_v2x(struct smc_clc_first_contact_ext_v2x *fce_v2x, ++ struct smc_init_info *ini) + { +- int ret = sizeof(*fce); ++ int ret = sizeof(*fce_v2x); + +- memset(fce, 0, sizeof(*fce)); +- fce->fce_v2_base.os_type = SMC_CLC_OS_LINUX; +- fce->fce_v2_base.release = ini->release_nr; +- memcpy(fce->fce_v2_base.hostname, smc_hostname, sizeof(smc_hostname)); ++ memset(fce_v2x, 0, sizeof(*fce_v2x)); ++ fce_v2x->fce_v2_base.os_type = SMC_CLC_OS_LINUX; ++ fce_v2x->fce_v2_base.release = ini->release_nr; ++ memcpy(fce_v2x->fce_v2_base.hostname, ++ smc_hostname, sizeof(smc_hostname)); + if (ini->is_smcd && ini->release_nr < SMC_RELEASE_1) { + ret = sizeof(struct smc_clc_first_contact_ext); + goto out; +@@ -444,8 +445,8 @@ static int smc_clc_fill_fce(struct smc_clc_first_contact_ext_v2x *fce, + + if (ini->release_nr >= SMC_RELEASE_1) { + if (!ini->is_smcd) { +- fce->max_conns = ini->max_conns; +- fce->max_links = ini->max_links; ++ fce_v2x->max_conns = ini->max_conns; ++ fce_v2x->max_links = ini->max_links; + } + } + +@@ -1012,8 +1013,8 @@ static int smc_clc_send_confirm_accept(struct smc_sock *smc, + int first_contact, u8 version, + u8 *eid, struct smc_init_info *ini) + { ++ struct smc_clc_first_contact_ext_v2x fce_v2x; + struct smc_connection *conn = &smc->conn; +- struct smc_clc_first_contact_ext_v2x fce; + struct smcd_dev *smcd = conn->lgr->smcd; + struct smc_clc_msg_accept_confirm *clc; + struct smc_clc_fce_gid_ext gle; +@@ -1045,7 +1046,7 @@ static int smc_clc_send_confirm_accept(struct smc_sock *smc, + memcpy(clc_v2->d1.eid, eid, SMC_MAX_EID_LEN); + len = SMCD_CLC_ACCEPT_CONFIRM_LEN_V2; + if (first_contact) { +- fce_len = smc_clc_fill_fce(&fce, ini); ++ fce_len = smc_clc_fill_fce_v2x(&fce_v2x, ini); + len += fce_len; + } + clc_v2->hdr.length = htons(len); +@@ -1091,9 +1092,10 @@ static int smc_clc_send_confirm_accept(struct smc_sock *smc, + memcpy(clc_v2->r1.eid, eid, SMC_MAX_EID_LEN); + len = SMCR_CLC_ACCEPT_CONFIRM_LEN_V2; + if (first_contact) { +- fce_len = smc_clc_fill_fce(&fce, ini); ++ fce_len = smc_clc_fill_fce_v2x(&fce_v2x, ini); + len += fce_len; +- fce.fce_v2_base.v2_direct = !link->lgr->uses_gateway; ++ fce_v2x.fce_v2_base.v2_direct = ++ !link->lgr->uses_gateway; + if (clc->hdr.type == SMC_CLC_CONFIRM) { + memset(&gle, 0, sizeof(gle)); + gle.gid_cnt = ini->smcrv2.gidlist.len; +@@ -1120,7 +1122,7 @@ static int smc_clc_send_confirm_accept(struct smc_sock *smc, + SMCR_CLC_ACCEPT_CONFIRM_LEN) - + sizeof(trl); + if (version > SMC_V1 && first_contact) { +- vec[i].iov_base = &fce; ++ vec[i].iov_base = &fce_v2x; + vec[i++].iov_len = fce_len; + if (!conn->lgr->is_smcd) { + if (clc->hdr.type == SMC_CLC_CONFIRM) { +-- +2.43.0 + diff --git a/queue-6.6/net-smc-unify-the-structs-of-accept-or-confirm-messa.patch b/queue-6.6/net-smc-unify-the-structs-of-accept-or-confirm-messa.patch new file mode 100644 index 00000000000..c8822b8dcff --- /dev/null +++ b/queue-6.6/net-smc-unify-the-structs-of-accept-or-confirm-messa.patch @@ -0,0 +1,474 @@ +From 5e39581587629a940e2a3959aee26b2fb4572ba9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 Dec 2023 22:26:09 +0800 +Subject: net/smc: unify the structs of accept or confirm message for v1 and v2 + +From: Wen Gu + +[ Upstream commit 9505450d55b0f7809fe63c36ad9339a909461c87 ] + +The structs of CLC accept and confirm messages for SMCv1 and SMCv2 are +separately defined and often casted to each other in the code, which may +increase the risk of errors caused by future divergence of them. So +unify them into one struct for better maintainability. + +Suggested-by: Alexandra Winter +Signed-off-by: Wen Gu +Reviewed-by: Alexandra Winter +Signed-off-by: David S. Miller +Stable-dep-of: 0541db8ee32c ("net/smc: initialize close_work early to avoid warning") +Signed-off-by: Sasha Levin +--- + net/smc/af_smc.c | 52 +++++++++++++------------------------ + net/smc/smc_clc.c | 65 ++++++++++++++++++++--------------------------- + net/smc/smc_clc.h | 42 +++++++++++++----------------- + 3 files changed, 62 insertions(+), 97 deletions(-) + +diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c +index 3158b94fd347a..ea24fb4dae0df 100644 +--- a/net/smc/af_smc.c ++++ b/net/smc/af_smc.c +@@ -659,8 +659,6 @@ static bool smc_isascii(char *hostname) + static void smc_conn_save_peer_info_fce(struct smc_sock *smc, + struct smc_clc_msg_accept_confirm *clc) + { +- struct smc_clc_msg_accept_confirm_v2 *clc_v2 = +- (struct smc_clc_msg_accept_confirm_v2 *)clc; + struct smc_clc_first_contact_ext *fce; + int clc_v2_len; + +@@ -669,17 +667,15 @@ static void smc_conn_save_peer_info_fce(struct smc_sock *smc, + return; + + if (smc->conn.lgr->is_smcd) { +- memcpy(smc->conn.lgr->negotiated_eid, clc_v2->d1.eid, ++ memcpy(smc->conn.lgr->negotiated_eid, clc->d1.eid, + SMC_MAX_EID_LEN); +- clc_v2_len = offsetofend(struct smc_clc_msg_accept_confirm_v2, +- d1); ++ clc_v2_len = offsetofend(struct smc_clc_msg_accept_confirm, d1); + } else { +- memcpy(smc->conn.lgr->negotiated_eid, clc_v2->r1.eid, ++ memcpy(smc->conn.lgr->negotiated_eid, clc->r1.eid, + SMC_MAX_EID_LEN); +- clc_v2_len = offsetofend(struct smc_clc_msg_accept_confirm_v2, +- r1); ++ clc_v2_len = offsetofend(struct smc_clc_msg_accept_confirm, r1); + } +- fce = (struct smc_clc_first_contact_ext *)(((u8 *)clc_v2) + clc_v2_len); ++ fce = (struct smc_clc_first_contact_ext *)(((u8 *)clc) + clc_v2_len); + smc->conn.lgr->peer_os = fce->os_type; + smc->conn.lgr->peer_smc_release = fce->release; + if (smc_isascii(fce->hostname)) +@@ -1131,13 +1127,13 @@ static int smc_connect_ism_vlan_cleanup(struct smc_sock *smc, + } + + #define SMC_CLC_MAX_ACCEPT_LEN \ +- (sizeof(struct smc_clc_msg_accept_confirm_v2) + \ ++ (sizeof(struct smc_clc_msg_accept_confirm) + \ + sizeof(struct smc_clc_first_contact_ext_v2x) + \ + sizeof(struct smc_clc_msg_trail)) + + /* CLC handshake during connect */ + static int smc_connect_clc(struct smc_sock *smc, +- struct smc_clc_msg_accept_confirm_v2 *aclc2, ++ struct smc_clc_msg_accept_confirm *aclc, + struct smc_init_info *ini) + { + int rc = 0; +@@ -1147,7 +1143,7 @@ static int smc_connect_clc(struct smc_sock *smc, + if (rc) + return rc; + /* receive SMC Accept CLC message */ +- return smc_clc_wait_msg(smc, aclc2, SMC_CLC_MAX_ACCEPT_LEN, ++ return smc_clc_wait_msg(smc, aclc, SMC_CLC_MAX_ACCEPT_LEN, + SMC_CLC_ACCEPT, CLC_WAIT_TIME); + } + +@@ -1183,10 +1179,8 @@ static int smc_connect_rdma_v2_prepare(struct smc_sock *smc, + struct smc_clc_msg_accept_confirm *aclc, + struct smc_init_info *ini) + { +- struct smc_clc_msg_accept_confirm_v2 *clc_v2 = +- (struct smc_clc_msg_accept_confirm_v2 *)aclc; + struct smc_clc_first_contact_ext *fce = +- smc_get_clc_first_contact_ext(clc_v2, false); ++ smc_get_clc_first_contact_ext(aclc, false); + struct net *net = sock_net(&smc->sk); + int rc; + +@@ -1309,10 +1303,7 @@ static int smc_connect_rdma(struct smc_sock *smc, + } + + if (aclc->hdr.version > SMC_V1) { +- struct smc_clc_msg_accept_confirm_v2 *clc_v2 = +- (struct smc_clc_msg_accept_confirm_v2 *)aclc; +- +- eid = clc_v2->r1.eid; ++ eid = aclc->r1.eid; + if (ini->first_contact_local) + smc_fill_gid_list(link->lgr, &ini->smcrv2.gidlist, + link->smcibdev, link->gid); +@@ -1353,7 +1344,7 @@ static int smc_connect_rdma(struct smc_sock *smc, + * Determine from the CHID of the received CLC ACCEPT the ISM device chosen. + */ + static int +-smc_v2_determine_accepted_chid(struct smc_clc_msg_accept_confirm_v2 *aclc, ++smc_v2_determine_accepted_chid(struct smc_clc_msg_accept_confirm *aclc, + struct smc_init_info *ini) + { + int i; +@@ -1380,12 +1371,9 @@ static int smc_connect_ism(struct smc_sock *smc, + ini->first_contact_peer = aclc->hdr.typev2 & SMC_FIRST_CONTACT_MASK; + + if (aclc->hdr.version == SMC_V2) { +- struct smc_clc_msg_accept_confirm_v2 *aclc_v2 = +- (struct smc_clc_msg_accept_confirm_v2 *)aclc; +- + if (ini->first_contact_peer) { + struct smc_clc_first_contact_ext *fce = +- smc_get_clc_first_contact_ext(aclc_v2, true); ++ smc_get_clc_first_contact_ext(aclc, true); + + ini->release_nr = fce->release; + rc = smc_clc_clnt_v2x_features_validate(fce, ini); +@@ -1393,7 +1381,7 @@ static int smc_connect_ism(struct smc_sock *smc, + return rc; + } + +- rc = smc_v2_determine_accepted_chid(aclc_v2, ini); ++ rc = smc_v2_determine_accepted_chid(aclc, ini); + if (rc) + return rc; + } +@@ -1419,12 +1407,8 @@ static int smc_connect_ism(struct smc_sock *smc, + smc_rx_init(smc); + smc_tx_init(smc); + +- if (aclc->hdr.version > SMC_V1) { +- struct smc_clc_msg_accept_confirm_v2 *clc_v2 = +- (struct smc_clc_msg_accept_confirm_v2 *)aclc; +- +- eid = clc_v2->d1.eid; +- } ++ if (aclc->hdr.version > SMC_V1) ++ eid = aclc->d1.eid; + + rc = smc_clc_send_confirm(smc, ini->first_contact_local, + aclc->hdr.version, eid, ini); +@@ -1475,7 +1459,6 @@ static int smc_connect_check_aclc(struct smc_init_info *ini, + static int __smc_connect(struct smc_sock *smc) + { + u8 version = smc_ism_is_v2_capable() ? SMC_V2 : SMC_V1; +- struct smc_clc_msg_accept_confirm_v2 *aclc2; + struct smc_clc_msg_accept_confirm *aclc; + struct smc_init_info *ini = NULL; + u8 *buf = NULL; +@@ -1523,11 +1506,10 @@ static int __smc_connect(struct smc_sock *smc) + rc = SMC_CLC_DECL_MEM; + goto fallback; + } +- aclc2 = (struct smc_clc_msg_accept_confirm_v2 *)buf; +- aclc = (struct smc_clc_msg_accept_confirm *)aclc2; ++ aclc = (struct smc_clc_msg_accept_confirm *)buf; + + /* perform CLC handshake */ +- rc = smc_connect_clc(smc, aclc2, ini); ++ rc = smc_connect_clc(smc, aclc, ini); + if (rc) { + /* -EAGAIN on timeout, see tcp_recvmsg() */ + if (rc == -EAGAIN) { +diff --git a/net/smc/smc_clc.c b/net/smc/smc_clc.c +index d471a06baac32..a28dee81d6fa4 100644 +--- a/net/smc/smc_clc.c ++++ b/net/smc/smc_clc.c +@@ -387,9 +387,9 @@ static bool smc_clc_msg_prop_valid(struct smc_clc_msg_proposal *pclc) + + /* check arriving CLC accept or confirm */ + static bool +-smc_clc_msg_acc_conf_valid(struct smc_clc_msg_accept_confirm_v2 *clc_v2) ++smc_clc_msg_acc_conf_valid(struct smc_clc_msg_accept_confirm *clc) + { +- struct smc_clc_msg_hdr *hdr = &clc_v2->hdr; ++ struct smc_clc_msg_hdr *hdr = &clc->hdr; + + if (hdr->typev1 != SMC_TYPE_R && hdr->typev1 != SMC_TYPE_D) + return false; +@@ -459,7 +459,7 @@ static int smc_clc_fill_fce_v2x(struct smc_clc_first_contact_ext_v2x *fce_v2x, + */ + static bool smc_clc_msg_hdr_valid(struct smc_clc_msg_hdr *clcm, bool check_trl) + { +- struct smc_clc_msg_accept_confirm_v2 *clc_v2; ++ struct smc_clc_msg_accept_confirm *clc; + struct smc_clc_msg_proposal *pclc; + struct smc_clc_msg_decline *dclc; + struct smc_clc_msg_trail *trl; +@@ -477,12 +477,11 @@ static bool smc_clc_msg_hdr_valid(struct smc_clc_msg_hdr *clcm, bool check_trl) + break; + case SMC_CLC_ACCEPT: + case SMC_CLC_CONFIRM: +- clc_v2 = (struct smc_clc_msg_accept_confirm_v2 *)clcm; +- if (!smc_clc_msg_acc_conf_valid(clc_v2)) ++ clc = (struct smc_clc_msg_accept_confirm *)clcm; ++ if (!smc_clc_msg_acc_conf_valid(clc)) + return false; + trl = (struct smc_clc_msg_trail *) +- ((u8 *)clc_v2 + ntohs(clc_v2->hdr.length) - +- sizeof(*trl)); ++ ((u8 *)clc + ntohs(clc->hdr.length) - sizeof(*trl)); + break; + case SMC_CLC_DECLINE: + dclc = (struct smc_clc_msg_decline *)clcm; +@@ -1009,7 +1008,7 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini) + + static void + smcd_clc_prep_confirm_accept(struct smc_connection *conn, +- struct smc_clc_msg_accept_confirm_v2 *clc_v2, ++ struct smc_clc_msg_accept_confirm *clc, + int first_contact, u8 version, + u8 *eid, struct smc_init_info *ini, + int *fce_len, +@@ -1017,11 +1016,9 @@ smcd_clc_prep_confirm_accept(struct smc_connection *conn, + struct smc_clc_msg_trail *trl) + { + struct smcd_dev *smcd = conn->lgr->smcd; +- struct smc_clc_msg_accept_confirm *clc; + int len; + + /* SMC-D specific settings */ +- clc = (struct smc_clc_msg_accept_confirm *)clc_v2; + memcpy(clc->hdr.eyecatcher, SMCD_EYECATCHER, + sizeof(SMCD_EYECATCHER)); + clc->hdr.typev1 = SMC_TYPE_D; +@@ -1033,15 +1030,15 @@ smcd_clc_prep_confirm_accept(struct smc_connection *conn, + if (version == SMC_V1) { + clc->hdr.length = htons(SMCD_CLC_ACCEPT_CONFIRM_LEN); + } else { +- clc_v2->d1.chid = htons(smc_ism_get_chid(smcd)); ++ clc->d1.chid = htons(smc_ism_get_chid(smcd)); + if (eid && eid[0]) +- memcpy(clc_v2->d1.eid, eid, SMC_MAX_EID_LEN); ++ memcpy(clc->d1.eid, eid, SMC_MAX_EID_LEN); + len = SMCD_CLC_ACCEPT_CONFIRM_LEN_V2; + if (first_contact) { + *fce_len = smc_clc_fill_fce_v2x(fce_v2x, ini); + len += *fce_len; + } +- clc_v2->hdr.length = htons(len); ++ clc->hdr.length = htons(len); + } + memcpy(trl->eyecatcher, SMCD_EYECATCHER, + sizeof(SMCD_EYECATCHER)); +@@ -1049,7 +1046,7 @@ smcd_clc_prep_confirm_accept(struct smc_connection *conn, + + static void + smcr_clc_prep_confirm_accept(struct smc_connection *conn, +- struct smc_clc_msg_accept_confirm_v2 *clc_v2, ++ struct smc_clc_msg_accept_confirm *clc, + int first_contact, u8 version, + u8 *eid, struct smc_init_info *ini, + int *fce_len, +@@ -1057,12 +1054,10 @@ smcr_clc_prep_confirm_accept(struct smc_connection *conn, + struct smc_clc_fce_gid_ext *gle, + struct smc_clc_msg_trail *trl) + { +- struct smc_clc_msg_accept_confirm *clc; + struct smc_link *link = conn->lnk; + int len; + + /* SMC-R specific settings */ +- clc = (struct smc_clc_msg_accept_confirm *)clc_v2; + memcpy(clc->hdr.eyecatcher, SMC_EYECATCHER, + sizeof(SMC_EYECATCHER)); + clc->hdr.typev1 = SMC_TYPE_R; +@@ -1094,7 +1089,7 @@ smcr_clc_prep_confirm_accept(struct smc_connection *conn, + clc->hdr.length = htons(SMCR_CLC_ACCEPT_CONFIRM_LEN); + } else { + if (eid && eid[0]) +- memcpy(clc_v2->r1.eid, eid, SMC_MAX_EID_LEN); ++ memcpy(clc->r1.eid, eid, SMC_MAX_EID_LEN); + len = SMCR_CLC_ACCEPT_CONFIRM_LEN_V2; + if (first_contact) { + *fce_len = smc_clc_fill_fce_v2x(fce_v2x, ini); +@@ -1108,20 +1103,19 @@ smcr_clc_prep_confirm_accept(struct smc_connection *conn, + len += gle->gid_cnt * sizeof(gle->gid[0]); + } + } +- clc_v2->hdr.length = htons(len); ++ clc->hdr.length = htons(len); + } + memcpy(trl->eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER)); + } + + /* build and send CLC CONFIRM / ACCEPT message */ + static int smc_clc_send_confirm_accept(struct smc_sock *smc, +- struct smc_clc_msg_accept_confirm_v2 *clc_v2, ++ struct smc_clc_msg_accept_confirm *clc, + int first_contact, u8 version, + u8 *eid, struct smc_init_info *ini) + { + struct smc_clc_first_contact_ext_v2x fce_v2x; + struct smc_connection *conn = &smc->conn; +- struct smc_clc_msg_accept_confirm *clc; + struct smc_clc_fce_gid_ext gle; + struct smc_clc_msg_trail trl; + int i, fce_len; +@@ -1129,21 +1123,20 @@ static int smc_clc_send_confirm_accept(struct smc_sock *smc, + struct msghdr msg; + + /* send SMC Confirm CLC msg */ +- clc = (struct smc_clc_msg_accept_confirm *)clc_v2; + clc->hdr.version = version; /* SMC version */ + if (first_contact) + clc->hdr.typev2 |= SMC_FIRST_CONTACT_MASK; + if (conn->lgr->is_smcd) +- smcd_clc_prep_confirm_accept(conn, clc_v2, first_contact, ++ smcd_clc_prep_confirm_accept(conn, clc, first_contact, + version, eid, ini, &fce_len, + &fce_v2x, &trl); + else +- smcr_clc_prep_confirm_accept(conn, clc_v2, first_contact, ++ smcr_clc_prep_confirm_accept(conn, clc, first_contact, + version, eid, ini, &fce_len, + &fce_v2x, &gle, &trl); + memset(&msg, 0, sizeof(msg)); + i = 0; +- vec[i].iov_base = clc_v2; ++ vec[i].iov_base = clc; + if (version > SMC_V1) + vec[i++].iov_len = (clc->hdr.typev1 == SMC_TYPE_D ? + SMCD_CLC_ACCEPT_CONFIRM_LEN_V2 : +@@ -1177,16 +1170,16 @@ static int smc_clc_send_confirm_accept(struct smc_sock *smc, + int smc_clc_send_confirm(struct smc_sock *smc, bool clnt_first_contact, + u8 version, u8 *eid, struct smc_init_info *ini) + { +- struct smc_clc_msg_accept_confirm_v2 cclc_v2; ++ struct smc_clc_msg_accept_confirm cclc; + int reason_code = 0; + int len; + + /* send SMC Confirm CLC msg */ +- memset(&cclc_v2, 0, sizeof(cclc_v2)); +- cclc_v2.hdr.type = SMC_CLC_CONFIRM; +- len = smc_clc_send_confirm_accept(smc, &cclc_v2, clnt_first_contact, ++ memset(&cclc, 0, sizeof(cclc)); ++ cclc.hdr.type = SMC_CLC_CONFIRM; ++ len = smc_clc_send_confirm_accept(smc, &cclc, clnt_first_contact, + version, eid, ini); +- if (len < ntohs(cclc_v2.hdr.length)) { ++ if (len < ntohs(cclc.hdr.length)) { + if (len >= 0) { + reason_code = -ENETUNREACH; + smc->sk.sk_err = -reason_code; +@@ -1202,14 +1195,14 @@ int smc_clc_send_confirm(struct smc_sock *smc, bool clnt_first_contact, + int smc_clc_send_accept(struct smc_sock *new_smc, bool srv_first_contact, + u8 version, u8 *negotiated_eid, struct smc_init_info *ini) + { +- struct smc_clc_msg_accept_confirm_v2 aclc_v2; ++ struct smc_clc_msg_accept_confirm aclc; + int len; + +- memset(&aclc_v2, 0, sizeof(aclc_v2)); +- aclc_v2.hdr.type = SMC_CLC_ACCEPT; +- len = smc_clc_send_confirm_accept(new_smc, &aclc_v2, srv_first_contact, ++ memset(&aclc, 0, sizeof(aclc)); ++ aclc.hdr.type = SMC_CLC_ACCEPT; ++ len = smc_clc_send_confirm_accept(new_smc, &aclc, srv_first_contact, + version, negotiated_eid, ini); +- if (len < ntohs(aclc_v2.hdr.length)) ++ if (len < ntohs(aclc.hdr.length)) + len = len >= 0 ? -EPROTO : -new_smc->clcsock->sk->sk_err; + + return len > 0 ? 0 : len; +@@ -1270,10 +1263,8 @@ int smc_clc_clnt_v2x_features_validate(struct smc_clc_first_contact_ext *fce, + int smc_clc_v2x_features_confirm_check(struct smc_clc_msg_accept_confirm *cclc, + struct smc_init_info *ini) + { +- struct smc_clc_msg_accept_confirm_v2 *clc_v2 = +- (struct smc_clc_msg_accept_confirm_v2 *)cclc; + struct smc_clc_first_contact_ext *fce = +- smc_get_clc_first_contact_ext(clc_v2, ini->is_smcd); ++ smc_get_clc_first_contact_ext(cclc, ini->is_smcd); + struct smc_clc_first_contact_ext_v2x *fce_v2x = + (struct smc_clc_first_contact_ext_v2x *)fce; + +diff --git a/net/smc/smc_clc.h b/net/smc/smc_clc.h +index 08155a96a02a1..d7b1716cfb0fd 100644 +--- a/net/smc/smc_clc.h ++++ b/net/smc/smc_clc.h +@@ -257,30 +257,23 @@ struct smc_clc_fce_gid_ext { + }; + + struct smc_clc_msg_accept_confirm { /* clc accept / confirm message */ +- struct smc_clc_msg_hdr hdr; +- union { +- struct smcr_clc_msg_accept_confirm r0; /* SMC-R */ +- struct { /* SMC-D */ +- struct smcd_clc_msg_accept_confirm_common d0; +- u32 reserved5[3]; +- }; +- }; +-} __packed; /* format defined in RFC7609 */ +- +-struct smc_clc_msg_accept_confirm_v2 { /* clc accept / confirm message */ + struct smc_clc_msg_hdr hdr; + union { + struct { /* SMC-R */ + struct smcr_clc_msg_accept_confirm r0; +- u8 eid[SMC_MAX_EID_LEN]; +- u8 reserved6[8]; +- } r1; ++ struct { /* v2 only */ ++ u8 eid[SMC_MAX_EID_LEN]; ++ u8 reserved6[8]; ++ } __packed r1; ++ }; + struct { /* SMC-D */ + struct smcd_clc_msg_accept_confirm_common d0; +- __be16 chid; +- u8 eid[SMC_MAX_EID_LEN]; +- u8 reserved5[8]; +- } d1; ++ struct { /* v2 only, but 12 bytes reserved in v1 */ ++ __be16 chid; ++ u8 eid[SMC_MAX_EID_LEN]; ++ u8 reserved5[8]; ++ } __packed d1; ++ }; + }; + }; + +@@ -389,24 +382,23 @@ smc_get_clc_smcd_v2_ext(struct smc_clc_v2_extension *prop_v2ext) + } + + static inline struct smc_clc_first_contact_ext * +-smc_get_clc_first_contact_ext(struct smc_clc_msg_accept_confirm_v2 *clc_v2, ++smc_get_clc_first_contact_ext(struct smc_clc_msg_accept_confirm *clc, + bool is_smcd) + { + int clc_v2_len; + +- if (clc_v2->hdr.version == SMC_V1 || +- !(clc_v2->hdr.typev2 & SMC_FIRST_CONTACT_MASK)) ++ if (clc->hdr.version == SMC_V1 || ++ !(clc->hdr.typev2 & SMC_FIRST_CONTACT_MASK)) + return NULL; + + if (is_smcd) + clc_v2_len = +- offsetofend(struct smc_clc_msg_accept_confirm_v2, d1); ++ offsetofend(struct smc_clc_msg_accept_confirm, d1); + else + clc_v2_len = +- offsetofend(struct smc_clc_msg_accept_confirm_v2, r1); ++ offsetofend(struct smc_clc_msg_accept_confirm, r1); + +- return (struct smc_clc_first_contact_ext *)(((u8 *)clc_v2) + +- clc_v2_len); ++ return (struct smc_clc_first_contact_ext *)(((u8 *)clc) + clc_v2_len); + } + + struct smcd_dev; +-- +2.43.0 + diff --git a/queue-6.6/net-timestamp-make-sk_tskey-more-predictable-in-erro.patch b/queue-6.6/net-timestamp-make-sk_tskey-more-predictable-in-erro.patch new file mode 100644 index 00000000000..7e78a792b20 --- /dev/null +++ b/queue-6.6/net-timestamp-make-sk_tskey-more-predictable-in-erro.patch @@ -0,0 +1,127 @@ +From 8974b17291faf17ea19920f2949c943f2871f865 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Feb 2024 03:04:28 -0800 +Subject: net-timestamp: make sk_tskey more predictable in error path + +From: Vadim Fedorenko + +[ Upstream commit 488b6d91b07112eaaaa4454332c1480894d4e06e ] + +When SOF_TIMESTAMPING_OPT_ID is used to ambiguate timestamped datagrams, +the sk_tskey can become unpredictable in case of any error happened +during sendmsg(). Move increment later in the code and make decrement of +sk_tskey in error path. This solution is still racy in case of multiple +threads doing snedmsg() over the very same socket in parallel, but still +makes error path much more predictable. + +Fixes: 09c2d251b707 ("net-timestamp: add key to disambiguate concurrent datagrams") +Reported-by: Andy Lutomirski +Signed-off-by: Vadim Fedorenko +Reviewed-by: Willem de Bruijn +Link: https://lore.kernel.org/r/20240213110428.1681540-1-vadfed@meta.com +Signed-off-by: Paolo Abeni +Stable-dep-of: 3301ab7d5aeb ("net/ipv6: release expired exception dst cached in socket") +Signed-off-by: Sasha Levin +--- + net/ipv4/ip_output.c | 13 ++++++++----- + net/ipv6/ip6_output.c | 13 ++++++++----- + 2 files changed, 16 insertions(+), 10 deletions(-) + +diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c +index 2458461e24874..765bd3f2a8408 100644 +--- a/net/ipv4/ip_output.c ++++ b/net/ipv4/ip_output.c +@@ -972,8 +972,8 @@ static int __ip_append_data(struct sock *sk, + unsigned int maxfraglen, fragheaderlen, maxnonfragsize; + int csummode = CHECKSUM_NONE; + struct rtable *rt = (struct rtable *)cork->dst; ++ bool paged, hold_tskey, extra_uref = false; + unsigned int wmem_alloc_delta = 0; +- bool paged, extra_uref = false; + u32 tskey = 0; + + skb = skb_peek_tail(queue); +@@ -982,10 +982,6 @@ static int __ip_append_data(struct sock *sk, + mtu = cork->gso_size ? IP_MAX_MTU : cork->fragsize; + paged = !!cork->gso_size; + +- if (cork->tx_flags & SKBTX_ANY_TSTAMP && +- READ_ONCE(sk->sk_tsflags) & SOF_TIMESTAMPING_OPT_ID) +- tskey = atomic_inc_return(&sk->sk_tskey) - 1; +- + hh_len = LL_RESERVED_SPACE(rt->dst.dev); + + fragheaderlen = sizeof(struct iphdr) + (opt ? opt->optlen : 0); +@@ -1052,6 +1048,11 @@ static int __ip_append_data(struct sock *sk, + + cork->length += length; + ++ hold_tskey = cork->tx_flags & SKBTX_ANY_TSTAMP && ++ READ_ONCE(sk->sk_tsflags) & SOF_TIMESTAMPING_OPT_ID; ++ if (hold_tskey) ++ tskey = atomic_inc_return(&sk->sk_tskey) - 1; ++ + /* So, what's going on in the loop below? + * + * We use calculated fragment length to generate chained skb, +@@ -1274,6 +1275,8 @@ static int __ip_append_data(struct sock *sk, + cork->length -= length; + IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTDISCARDS); + refcount_add(wmem_alloc_delta, &sk->sk_wmem_alloc); ++ if (hold_tskey) ++ atomic_dec(&sk->sk_tskey); + return err; + } + +diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c +index 5d8d86c159dc3..65e2f19814358 100644 +--- a/net/ipv6/ip6_output.c ++++ b/net/ipv6/ip6_output.c +@@ -1501,11 +1501,11 @@ static int __ip6_append_data(struct sock *sk, + bool zc = false; + u32 tskey = 0; + struct rt6_info *rt = (struct rt6_info *)cork->dst; ++ bool paged, hold_tskey, extra_uref = false; + struct ipv6_txoptions *opt = v6_cork->opt; + int csummode = CHECKSUM_NONE; + unsigned int maxnonfragsize, headersize; + unsigned int wmem_alloc_delta = 0; +- bool paged, extra_uref = false; + + skb = skb_peek_tail(queue); + if (!skb) { +@@ -1517,10 +1517,6 @@ static int __ip6_append_data(struct sock *sk, + mtu = cork->gso_size ? IP6_MAX_MTU : cork->fragsize; + orig_mtu = mtu; + +- if (cork->tx_flags & SKBTX_ANY_TSTAMP && +- READ_ONCE(sk->sk_tsflags) & SOF_TIMESTAMPING_OPT_ID) +- tskey = atomic_inc_return(&sk->sk_tskey) - 1; +- + hh_len = LL_RESERVED_SPACE(rt->dst.dev); + + fragheaderlen = sizeof(struct ipv6hdr) + rt->rt6i_nfheader_len + +@@ -1617,6 +1613,11 @@ static int __ip6_append_data(struct sock *sk, + flags &= ~MSG_SPLICE_PAGES; + } + ++ hold_tskey = cork->tx_flags & SKBTX_ANY_TSTAMP && ++ READ_ONCE(sk->sk_tsflags) & SOF_TIMESTAMPING_OPT_ID; ++ if (hold_tskey) ++ tskey = atomic_inc_return(&sk->sk_tskey) - 1; ++ + /* + * Let's try using as much space as possible. + * Use MTU if total length of the message fits into the MTU. +@@ -1873,6 +1874,8 @@ static int __ip6_append_data(struct sock *sk, + cork->length -= length; + IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS); + refcount_add(wmem_alloc_delta, &sk->sk_wmem_alloc); ++ if (hold_tskey) ++ atomic_dec(&sk->sk_tskey); + return err; + } + +-- +2.43.0 + diff --git a/queue-6.6/netfilter-ipset-hold-module-reference-while-requesti.patch b/queue-6.6/netfilter-ipset-hold-module-reference-while-requesti.patch new file mode 100644 index 00000000000..515f37be03f --- /dev/null +++ b/queue-6.6/netfilter-ipset-hold-module-reference-while-requesti.patch @@ -0,0 +1,49 @@ +From 81c7058b582e861c7ed9183d54dba39fdbc34ab4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 Nov 2024 16:30:38 +0100 +Subject: netfilter: ipset: Hold module reference while requesting a module + +From: Phil Sutter + +[ Upstream commit 456f010bfaefde84d3390c755eedb1b0a5857c3c ] + +User space may unload ip_set.ko while it is itself requesting a set type +backend module, leading to a kernel crash. The race condition may be +provoked by inserting an mdelay() right after the nfnl_unlock() call. + +Fixes: a7b4f989a629 ("netfilter: ipset: IP set core support") +Signed-off-by: Phil Sutter +Acked-by: Jozsef Kadlecsik +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/ipset/ip_set_core.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c +index 61431690cbd5f..cc20e6d56807c 100644 +--- a/net/netfilter/ipset/ip_set_core.c ++++ b/net/netfilter/ipset/ip_set_core.c +@@ -104,14 +104,19 @@ find_set_type(const char *name, u8 family, u8 revision) + static bool + load_settype(const char *name) + { ++ if (!try_module_get(THIS_MODULE)) ++ return false; ++ + nfnl_unlock(NFNL_SUBSYS_IPSET); + pr_debug("try to load ip_set_%s\n", name); + if (request_module("ip_set_%s", name) < 0) { + pr_warn("Can't find ip_set type %s\n", name); + nfnl_lock(NFNL_SUBSYS_IPSET); ++ module_put(THIS_MODULE); + return false; + } + nfnl_lock(NFNL_SUBSYS_IPSET); ++ module_put(THIS_MODULE); + return true; + } + +-- +2.43.0 + diff --git a/queue-6.6/netfilter-nft_inner-incorrect-percpu-area-handling-u.patch b/queue-6.6/netfilter-nft_inner-incorrect-percpu-area-handling-u.patch new file mode 100644 index 00000000000..33c4fe86da9 --- /dev/null +++ b/queue-6.6/netfilter-nft_inner-incorrect-percpu-area-handling-u.patch @@ -0,0 +1,169 @@ +From cffc455e40d4140383413ad4f06f2bd1b892b4fb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 Nov 2024 12:46:54 +0100 +Subject: netfilter: nft_inner: incorrect percpu area handling under softirq + +From: Pablo Neira Ayuso + +[ Upstream commit 7b1d83da254be3bf054965c8f3b1ad976f460ae5 ] + +Softirq can interrupt ongoing packet from process context that is +walking over the percpu area that contains inner header offsets. + +Disable bh and perform three checks before restoring the percpu inner +header offsets to validate that the percpu area is valid for this +skbuff: + +1) If the NFT_PKTINFO_INNER_FULL flag is set on, then this skbuff + has already been parsed before for inner header fetching to + register. + +2) Validate that the percpu area refers to this skbuff using the + skbuff pointer as a cookie. If there is a cookie mismatch, then + this skbuff needs to be parsed again. + +3) Finally, validate if the percpu area refers to this tunnel type. + +Only after these three checks the percpu area is restored to a on-stack +copy and bh is enabled again. + +After inner header fetching, the on-stack copy is stored back to the +percpu area. + +Fixes: 3a07327d10a0 ("netfilter: nft_inner: support for inner tunnel header matching") +Reported-by: syzbot+84d0441b9860f0d63285@syzkaller.appspotmail.com +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + include/net/netfilter/nf_tables_core.h | 1 + + net/netfilter/nft_inner.c | 57 ++++++++++++++++++++------ + 2 files changed, 46 insertions(+), 12 deletions(-) + +diff --git a/include/net/netfilter/nf_tables_core.h b/include/net/netfilter/nf_tables_core.h +index 780a5f6ad4a67..16855c2a03f8e 100644 +--- a/include/net/netfilter/nf_tables_core.h ++++ b/include/net/netfilter/nf_tables_core.h +@@ -161,6 +161,7 @@ enum { + }; + + struct nft_inner_tun_ctx { ++ unsigned long cookie; + u16 type; + u16 inner_tunoff; + u16 inner_lloff; +diff --git a/net/netfilter/nft_inner.c b/net/netfilter/nft_inner.c +index 928312d01eb1d..817ab978d24a1 100644 +--- a/net/netfilter/nft_inner.c ++++ b/net/netfilter/nft_inner.c +@@ -210,35 +210,66 @@ static int nft_inner_parse(const struct nft_inner *priv, + struct nft_pktinfo *pkt, + struct nft_inner_tun_ctx *tun_ctx) + { +- struct nft_inner_tun_ctx ctx = {}; + u32 off = pkt->inneroff; + + if (priv->flags & NFT_INNER_HDRSIZE && +- nft_inner_parse_tunhdr(priv, pkt, &ctx, &off) < 0) ++ nft_inner_parse_tunhdr(priv, pkt, tun_ctx, &off) < 0) + return -1; + + if (priv->flags & (NFT_INNER_LL | NFT_INNER_NH)) { +- if (nft_inner_parse_l2l3(priv, pkt, &ctx, off) < 0) ++ if (nft_inner_parse_l2l3(priv, pkt, tun_ctx, off) < 0) + return -1; + } else if (priv->flags & NFT_INNER_TH) { +- ctx.inner_thoff = off; +- ctx.flags |= NFT_PAYLOAD_CTX_INNER_TH; ++ tun_ctx->inner_thoff = off; ++ tun_ctx->flags |= NFT_PAYLOAD_CTX_INNER_TH; + } + +- *tun_ctx = ctx; + tun_ctx->type = priv->type; ++ tun_ctx->cookie = (unsigned long)pkt->skb; + pkt->flags |= NFT_PKTINFO_INNER_FULL; + + return 0; + } + ++static bool nft_inner_restore_tun_ctx(const struct nft_pktinfo *pkt, ++ struct nft_inner_tun_ctx *tun_ctx) ++{ ++ struct nft_inner_tun_ctx *this_cpu_tun_ctx; ++ ++ local_bh_disable(); ++ this_cpu_tun_ctx = this_cpu_ptr(&nft_pcpu_tun_ctx); ++ if (this_cpu_tun_ctx->cookie != (unsigned long)pkt->skb) { ++ local_bh_enable(); ++ return false; ++ } ++ *tun_ctx = *this_cpu_tun_ctx; ++ local_bh_enable(); ++ ++ return true; ++} ++ ++static void nft_inner_save_tun_ctx(const struct nft_pktinfo *pkt, ++ const struct nft_inner_tun_ctx *tun_ctx) ++{ ++ struct nft_inner_tun_ctx *this_cpu_tun_ctx; ++ ++ local_bh_disable(); ++ this_cpu_tun_ctx = this_cpu_ptr(&nft_pcpu_tun_ctx); ++ if (this_cpu_tun_ctx->cookie != tun_ctx->cookie) ++ *this_cpu_tun_ctx = *tun_ctx; ++ local_bh_enable(); ++} ++ + static bool nft_inner_parse_needed(const struct nft_inner *priv, + const struct nft_pktinfo *pkt, +- const struct nft_inner_tun_ctx *tun_ctx) ++ struct nft_inner_tun_ctx *tun_ctx) + { + if (!(pkt->flags & NFT_PKTINFO_INNER_FULL)) + return true; + ++ if (!nft_inner_restore_tun_ctx(pkt, tun_ctx)) ++ return true; ++ + if (priv->type != tun_ctx->type) + return true; + +@@ -248,27 +279,29 @@ static bool nft_inner_parse_needed(const struct nft_inner *priv, + static void nft_inner_eval(const struct nft_expr *expr, struct nft_regs *regs, + const struct nft_pktinfo *pkt) + { +- struct nft_inner_tun_ctx *tun_ctx = this_cpu_ptr(&nft_pcpu_tun_ctx); + const struct nft_inner *priv = nft_expr_priv(expr); ++ struct nft_inner_tun_ctx tun_ctx = {}; + + if (nft_payload_inner_offset(pkt) < 0) + goto err; + +- if (nft_inner_parse_needed(priv, pkt, tun_ctx) && +- nft_inner_parse(priv, (struct nft_pktinfo *)pkt, tun_ctx) < 0) ++ if (nft_inner_parse_needed(priv, pkt, &tun_ctx) && ++ nft_inner_parse(priv, (struct nft_pktinfo *)pkt, &tun_ctx) < 0) + goto err; + + switch (priv->expr_type) { + case NFT_INNER_EXPR_PAYLOAD: +- nft_payload_inner_eval((struct nft_expr *)&priv->expr, regs, pkt, tun_ctx); ++ nft_payload_inner_eval((struct nft_expr *)&priv->expr, regs, pkt, &tun_ctx); + break; + case NFT_INNER_EXPR_META: +- nft_meta_inner_eval((struct nft_expr *)&priv->expr, regs, pkt, tun_ctx); ++ nft_meta_inner_eval((struct nft_expr *)&priv->expr, regs, pkt, &tun_ctx); + break; + default: + WARN_ON_ONCE(1); + goto err; + } ++ nft_inner_save_tun_ctx(pkt, &tun_ctx); ++ + return; + err: + regs->verdict.code = NFT_BREAK; +-- +2.43.0 + diff --git a/queue-6.6/netfilter-nft_set_hash-skip-duplicated-elements-pend.patch b/queue-6.6/netfilter-nft_set_hash-skip-duplicated-elements-pend.patch new file mode 100644 index 00000000000..d5e46c3bd34 --- /dev/null +++ b/queue-6.6/netfilter-nft_set_hash-skip-duplicated-elements-pend.patch @@ -0,0 +1,97 @@ +From f2428dc4c12cb808229be4b4f6d1ee885cca3b0d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Dec 2024 00:04:49 +0100 +Subject: netfilter: nft_set_hash: skip duplicated elements pending gc run + +From: Pablo Neira Ayuso + +[ Upstream commit 7ffc7481153bbabf3332c6a19b289730c7e1edf5 ] + +rhashtable does not provide stable walk, duplicated elements are +possible in case of resizing. I considered that checking for errors when +calling rhashtable_walk_next() was sufficient to detect the resizing. +However, rhashtable_walk_next() returns -EAGAIN only at the end of the +iteration, which is too late, because a gc work containing duplicated +elements could have been already scheduled for removal to the worker. + +Add a u32 gc worker sequence number per set, bump it on every workqueue +run. Annotate gc worker sequence number on the expired element. Use it +to skip those already seen in this gc workqueue run. + +Note that this new field is never reset in case gc transaction fails, so +next gc worker run on the expired element overrides it. Wraparound of gc +worker sequence number should not be an issue with stale gc worker +sequence number in the element, that would just postpone the element +removal in one gc run. + +Note that it is not possible to use flags to annotate that element is +pending gc run to detect duplicates, given that gc transaction can be +invalidated in case of update from the control plane, therefore, not +allowing to clear such flag. + +On x86_64, pahole reports no changes in the size of nft_rhash_elem. + +Fixes: f6c383b8c31a ("netfilter: nf_tables: adapt set backend to use GC transaction API") +Reported-by: Laurent Fasnacht +Tested-by: Laurent Fasnacht +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_set_hash.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/net/netfilter/nft_set_hash.c b/net/netfilter/nft_set_hash.c +index 3a96d4a77a228..cc1ae18485faf 100644 +--- a/net/netfilter/nft_set_hash.c ++++ b/net/netfilter/nft_set_hash.c +@@ -24,10 +24,12 @@ + struct nft_rhash { + struct rhashtable ht; + struct delayed_work gc_work; ++ u32 wq_gc_seq; + }; + + struct nft_rhash_elem { + struct rhash_head node; ++ u32 wq_gc_seq; + struct nft_set_ext ext; + }; + +@@ -331,6 +333,10 @@ static void nft_rhash_gc(struct work_struct *work) + if (!gc) + goto done; + ++ /* Elements never collected use a zero gc worker sequence number. */ ++ if (unlikely(++priv->wq_gc_seq == 0)) ++ priv->wq_gc_seq++; ++ + rhashtable_walk_enter(&priv->ht, &hti); + rhashtable_walk_start(&hti); + +@@ -348,6 +354,14 @@ static void nft_rhash_gc(struct work_struct *work) + goto try_later; + } + ++ /* rhashtable walk is unstable, already seen in this gc run? ++ * Then, skip this element. In case of (unlikely) sequence ++ * wraparound and stale element wq_gc_seq, next gc run will ++ * just find this expired element. ++ */ ++ if (he->wq_gc_seq == priv->wq_gc_seq) ++ continue; ++ + if (nft_set_elem_is_dead(&he->ext)) + goto dead_elem; + +@@ -364,6 +378,8 @@ static void nft_rhash_gc(struct work_struct *work) + if (!gc) + goto try_later; + ++ /* annotate gc sequence for this attempt. */ ++ he->wq_gc_seq = priv->wq_gc_seq; + nft_trans_gc_elem_add(gc, he); + } + +-- +2.43.0 + diff --git a/queue-6.6/netfilter-nft_socket-remove-warn_on_once-on-maximum-.patch b/queue-6.6/netfilter-nft_socket-remove-warn_on_once-on-maximum-.patch new file mode 100644 index 00000000000..7f9b2ef372e --- /dev/null +++ b/queue-6.6/netfilter-nft_socket-remove-warn_on_once-on-maximum-.patch @@ -0,0 +1,38 @@ +From 454666b07ae4bba0f01035e29608ee662499849e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 Nov 2024 11:59:06 +0100 +Subject: netfilter: nft_socket: remove WARN_ON_ONCE on maximum cgroup level + +From: Pablo Neira Ayuso + +[ Upstream commit b7529880cb961d515642ce63f9d7570869bbbdc3 ] + +cgroup maximum depth is INT_MAX by default, there is a cgroup toggle to +restrict this maximum depth to a more reasonable value not to harm +performance. Remove unnecessary WARN_ON_ONCE which is reachable from +userspace. + +Fixes: 7f3287db6543 ("netfilter: nft_socket: make cgroupsv2 matching work with namespaces") +Reported-by: syzbot+57bac0866ddd99fe47c0@syzkaller.appspotmail.com +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_socket.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/netfilter/nft_socket.c b/net/netfilter/nft_socket.c +index 0a8883a93e836..187b667bad6c3 100644 +--- a/net/netfilter/nft_socket.c ++++ b/net/netfilter/nft_socket.c +@@ -68,7 +68,7 @@ static noinline int nft_socket_cgroup_subtree_level(void) + + cgroup_put(cgrp); + +- if (WARN_ON_ONCE(level > 255)) ++ if (level > 255) + return -ERANGE; + + if (WARN_ON_ONCE(level < 0)) +-- +2.43.0 + diff --git a/queue-6.6/netfilter-x_tables-fix-led-id-check-in-led_tg_check.patch b/queue-6.6/netfilter-x_tables-fix-led-id-check-in-led_tg_check.patch new file mode 100644 index 00000000000..f32df6cd331 --- /dev/null +++ b/queue-6.6/netfilter-x_tables-fix-led-id-check-in-led_tg_check.patch @@ -0,0 +1,109 @@ +From e9a09adef9ad20f3f9bbf736bde73ad35ef66ee7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 Nov 2024 09:55:42 +0300 +Subject: netfilter: x_tables: fix LED ID check in led_tg_check() + +From: Dmitry Antipov + +[ Upstream commit 04317f4eb2aad312ad85c1a17ad81fe75f1f9bc7 ] + +Syzbot has reported the following BUG detected by KASAN: + +BUG: KASAN: slab-out-of-bounds in strlen+0x58/0x70 +Read of size 1 at addr ffff8881022da0c8 by task repro/5879 +... +Call Trace: + + dump_stack_lvl+0x241/0x360 + ? __pfx_dump_stack_lvl+0x10/0x10 + ? __pfx__printk+0x10/0x10 + ? _printk+0xd5/0x120 + ? __virt_addr_valid+0x183/0x530 + ? __virt_addr_valid+0x183/0x530 + print_report+0x169/0x550 + ? __virt_addr_valid+0x183/0x530 + ? __virt_addr_valid+0x183/0x530 + ? __virt_addr_valid+0x45f/0x530 + ? __phys_addr+0xba/0x170 + ? strlen+0x58/0x70 + kasan_report+0x143/0x180 + ? strlen+0x58/0x70 + strlen+0x58/0x70 + kstrdup+0x20/0x80 + led_tg_check+0x18b/0x3c0 + xt_check_target+0x3bb/0xa40 + ? __pfx_xt_check_target+0x10/0x10 + ? stack_depot_save_flags+0x6e4/0x830 + ? nft_target_init+0x174/0xc30 + nft_target_init+0x82d/0xc30 + ? __pfx_nft_target_init+0x10/0x10 + ? nf_tables_newrule+0x1609/0x2980 + ? nf_tables_newrule+0x1609/0x2980 + ? rcu_is_watching+0x15/0xb0 + ? nf_tables_newrule+0x1609/0x2980 + ? nf_tables_newrule+0x1609/0x2980 + ? __kmalloc_noprof+0x21a/0x400 + nf_tables_newrule+0x1860/0x2980 + ? __pfx_nf_tables_newrule+0x10/0x10 + ? __nla_parse+0x40/0x60 + nfnetlink_rcv+0x14e5/0x2ab0 + ? __pfx_validate_chain+0x10/0x10 + ? __pfx_nfnetlink_rcv+0x10/0x10 + ? __lock_acquire+0x1384/0x2050 + ? netlink_deliver_tap+0x2e/0x1b0 + ? __pfx_lock_release+0x10/0x10 + ? netlink_deliver_tap+0x2e/0x1b0 + netlink_unicast+0x7f8/0x990 + ? __pfx_netlink_unicast+0x10/0x10 + ? __virt_addr_valid+0x183/0x530 + ? __check_object_size+0x48e/0x900 + netlink_sendmsg+0x8e4/0xcb0 + ? __pfx_netlink_sendmsg+0x10/0x10 + ? aa_sock_msg_perm+0x91/0x160 + ? __pfx_netlink_sendmsg+0x10/0x10 + __sock_sendmsg+0x223/0x270 + ____sys_sendmsg+0x52a/0x7e0 + ? __pfx_____sys_sendmsg+0x10/0x10 + __sys_sendmsg+0x292/0x380 + ? __pfx___sys_sendmsg+0x10/0x10 + ? lockdep_hardirqs_on_prepare+0x43d/0x780 + ? __pfx_lockdep_hardirqs_on_prepare+0x10/0x10 + ? exc_page_fault+0x590/0x8c0 + ? do_syscall_64+0xb6/0x230 + do_syscall_64+0xf3/0x230 + entry_SYSCALL_64_after_hwframe+0x77/0x7f +... + + +Since an invalid (without '\0' byte at all) byte sequence may be passed +from userspace, add an extra check to ensure that such a sequence is +rejected as possible ID and so never passed to 'kstrdup()' and further. + +Reported-by: syzbot+6c8215822f35fdb35667@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=6c8215822f35fdb35667 +Fixes: 268cb38e1802 ("netfilter: x_tables: add LED trigger target") +Signed-off-by: Dmitry Antipov +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/xt_LED.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/net/netfilter/xt_LED.c b/net/netfilter/xt_LED.c +index f7b0286d106ac..8a80fd76fe45b 100644 +--- a/net/netfilter/xt_LED.c ++++ b/net/netfilter/xt_LED.c +@@ -96,7 +96,9 @@ static int led_tg_check(const struct xt_tgchk_param *par) + struct xt_led_info_internal *ledinternal; + int err; + +- if (ledinfo->id[0] == '\0') ++ /* Bail out if empty string or not a string at all. */ ++ if (ledinfo->id[0] == '\0' || ++ !memchr(ledinfo->id, '\0', sizeof(ledinfo->id))) + return -EINVAL; + + mutex_lock(&xt_led_mutex); +-- +2.43.0 + diff --git a/queue-6.6/ntp-clean-up-comments.patch b/queue-6.6/ntp-clean-up-comments.patch new file mode 100644 index 00000000000..e0f91d42ae0 --- /dev/null +++ b/queue-6.6/ntp-clean-up-comments.patch @@ -0,0 +1,425 @@ +From a952ef82c4ecc4b4ef6ddae4b810213d5944b945 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Sep 2024 15:17:39 +0200 +Subject: ntp: Clean up comments + +From: Thomas Gleixner + +[ Upstream commit a0581cdb2e5d3ad633e51a945b6f0527ce70b68a ] + +Usage of different comment formatting makes fast reading and parsing the +code harder. There are several multi-line comments which do not follow the +coding style by starting with a line only containing '/*'. There are also +comments which do not start with capitals. + +Clean up all those comments to be consistent and remove comments which +document the obvious. + +Signed-off-by: Thomas Gleixner +Signed-off-by: Anna-Maria Behnsen +Signed-off-by: Thomas Gleixner +Acked-by: John Stultz +Link: https://lore.kernel.org/all/20240911-devel-anna-maria-b4-timers-ptp-ntp-v1-3-2d52f4e13476@linutronix.de +Stable-dep-of: f5807b0606da ("ntp: Remove invalid cast in time offset math") +Signed-off-by: Sasha Levin +--- + kernel/time/ntp.c | 144 +++++++++++++++++++++++++--------------------- + 1 file changed, 78 insertions(+), 66 deletions(-) + +diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c +index 8e68a85996f7d..99213d931f63f 100644 +--- a/kernel/time/ntp.c ++++ b/kernel/time/ntp.c +@@ -119,7 +119,8 @@ static long pps_stbcnt; /* stability limit exceeded */ + static long pps_errcnt; /* calibration errors */ + + +-/* PPS kernel consumer compensates the whole phase error immediately. ++/* ++ * PPS kernel consumer compensates the whole phase error immediately. + * Otherwise, reduce the offset by a fixed factor times the time constant. + */ + static inline s64 ntp_offset_chunk(s64 offset) +@@ -132,8 +133,7 @@ static inline s64 ntp_offset_chunk(s64 offset) + + static inline void pps_reset_freq_interval(void) + { +- /* the PPS calibration interval may end +- surprisingly early */ ++ /* The PPS calibration interval may end surprisingly early */ + pps_shift = PPS_INTMIN; + pps_intcnt = 0; + } +@@ -151,9 +151,9 @@ static inline void pps_clear(void) + pps_freq = 0; + } + +-/* Decrease pps_valid to indicate that another second has passed since +- * the last PPS signal. When it reaches 0, indicate that PPS signal is +- * missing. ++/* ++ * Decrease pps_valid to indicate that another second has passed since the ++ * last PPS signal. When it reaches 0, indicate that PPS signal is missing. + */ + static inline void pps_dec_valid(void) + { +@@ -174,17 +174,21 @@ static inline void pps_set_freq(s64 freq) + static inline int is_error_status(int status) + { + return (status & (STA_UNSYNC|STA_CLOCKERR)) +- /* PPS signal lost when either PPS time or +- * PPS frequency synchronization requested ++ /* ++ * PPS signal lost when either PPS time or PPS frequency ++ * synchronization requested + */ + || ((status & (STA_PPSFREQ|STA_PPSTIME)) + && !(status & STA_PPSSIGNAL)) +- /* PPS jitter exceeded when +- * PPS time synchronization requested */ ++ /* ++ * PPS jitter exceeded when PPS time synchronization ++ * requested ++ */ + || ((status & (STA_PPSTIME|STA_PPSJITTER)) + == (STA_PPSTIME|STA_PPSJITTER)) +- /* PPS wander exceeded or calibration error when +- * PPS frequency synchronization requested ++ /* ++ * PPS wander exceeded or calibration error when PPS ++ * frequency synchronization requested + */ + || ((status & STA_PPSFREQ) + && (status & (STA_PPSWANDER|STA_PPSERROR))); +@@ -270,8 +274,8 @@ static void ntp_update_frequency(void) + new_base = div_u64(second_length, NTP_INTERVAL_FREQ); + + /* +- * Don't wait for the next second_overflow, apply +- * the change to the tick length immediately: ++ * Don't wait for the next second_overflow, apply the change to the ++ * tick length immediately: + */ + tick_length += new_base - tick_length_base; + tick_length_base = new_base; +@@ -307,10 +311,7 @@ static void ntp_update_offset(long offset) + offset *= NSEC_PER_USEC; + } + +- /* +- * Scale the phase adjustment and +- * clamp to the operating range. +- */ ++ /* Scale the phase adjustment and clamp to the operating range. */ + offset = clamp(offset, -MAXPHASE, MAXPHASE); + + /* +@@ -349,7 +350,8 @@ static void ntp_update_offset(long offset) + */ + void ntp_clear(void) + { +- time_adjust = 0; /* stop active adjtime() */ ++ /* Stop active adjtime() */ ++ time_adjust = 0; + time_status |= STA_UNSYNC; + time_maxerror = NTP_PHASE_LIMIT; + time_esterror = NTP_PHASE_LIMIT; +@@ -387,7 +389,7 @@ ktime_t ntp_get_next_leap(void) + } + + /* +- * this routine handles the overflow of the microsecond field ++ * This routine handles the overflow of the microsecond field + * + * The tricky bits of code to handle the accurate clock support + * were provided by Dave Mills (Mills@UDEL.EDU) of NTP fame. +@@ -452,7 +454,6 @@ int second_overflow(time64_t secs) + break; + } + +- + /* Bump the maxerror field */ + time_maxerror += MAXFREQ / NSEC_PER_USEC; + if (time_maxerror > NTP_PHASE_LIMIT) { +@@ -688,7 +689,7 @@ static inline void process_adj_status(const struct __kernel_timex *txc) + time_state = TIME_OK; + time_status = STA_UNSYNC; + ntp_next_leap_sec = TIME64_MAX; +- /* restart PPS frequency calibration */ ++ /* Restart PPS frequency calibration */ + pps_reset_freq_interval(); + } + +@@ -699,7 +700,7 @@ static inline void process_adj_status(const struct __kernel_timex *txc) + if (!(time_status & STA_PLL) && (txc->status & STA_PLL)) + time_reftime = __ktime_get_real_seconds(); + +- /* only set allowed bits */ ++ /* Only set allowed bits */ + time_status &= STA_RONLY; + time_status |= txc->status & ~STA_RONLY; + } +@@ -721,7 +722,7 @@ static inline void process_adjtimex_modes(const struct __kernel_timex *txc, + time_freq = txc->freq * PPM_SCALE; + time_freq = min(time_freq, MAXFREQ_SCALED); + time_freq = max(time_freq, -MAXFREQ_SCALED); +- /* update pps_freq */ ++ /* Update pps_freq */ + pps_set_freq(time_freq); + } + +@@ -754,7 +755,7 @@ static inline void process_adjtimex_modes(const struct __kernel_timex *txc, + + + /* +- * adjtimex mainly allows reading (and writing, if superuser) of ++ * adjtimex() mainly allows reading (and writing, if superuser) of + * kernel time-keeping variables. used by xntpd. + */ + int __do_adjtimex(struct __kernel_timex *txc, const struct timespec64 *ts, +@@ -798,8 +799,7 @@ int __do_adjtimex(struct __kernel_timex *txc, const struct timespec64 *ts, + txc->offset = (u32)txc->offset / NSEC_PER_USEC; + } + +- result = time_state; /* mostly `TIME_OK' */ +- /* check for errors */ ++ result = time_state; + if (is_error_status(time_status)) + result = TIME_ERROR; + +@@ -814,7 +814,7 @@ int __do_adjtimex(struct __kernel_timex *txc, const struct timespec64 *ts, + txc->tick = tick_usec; + txc->tai = *time_tai; + +- /* fill PPS status fields */ ++ /* Fill PPS status fields */ + pps_fill_timex(txc); + + txc->time.tv_sec = ts->tv_sec; +@@ -845,17 +845,21 @@ int __do_adjtimex(struct __kernel_timex *txc, const struct timespec64 *ts, + + #ifdef CONFIG_NTP_PPS + +-/* actually struct pps_normtime is good old struct timespec, but it is ++/* ++ * struct pps_normtime is basically a struct timespec, but it is + * semantically different (and it is the reason why it was invented): + * pps_normtime.nsec has a range of ( -NSEC_PER_SEC / 2, NSEC_PER_SEC / 2 ] +- * while timespec.tv_nsec has a range of [0, NSEC_PER_SEC) */ ++ * while timespec.tv_nsec has a range of [0, NSEC_PER_SEC) ++ */ + struct pps_normtime { + s64 sec; /* seconds */ + long nsec; /* nanoseconds */ + }; + +-/* normalize the timestamp so that nsec is in the +- ( -NSEC_PER_SEC / 2, NSEC_PER_SEC / 2 ] interval */ ++/* ++ * Normalize the timestamp so that nsec is in the ++ * [ -NSEC_PER_SEC / 2, NSEC_PER_SEC / 2 ] interval ++ */ + static inline struct pps_normtime pps_normalize_ts(struct timespec64 ts) + { + struct pps_normtime norm = { +@@ -871,7 +875,7 @@ static inline struct pps_normtime pps_normalize_ts(struct timespec64 ts) + return norm; + } + +-/* get current phase correction and jitter */ ++/* Get current phase correction and jitter */ + static inline long pps_phase_filter_get(long *jitter) + { + *jitter = pps_tf[0] - pps_tf[1]; +@@ -882,7 +886,7 @@ static inline long pps_phase_filter_get(long *jitter) + return pps_tf[0]; + } + +-/* add the sample to the phase filter */ ++/* Add the sample to the phase filter */ + static inline void pps_phase_filter_add(long err) + { + pps_tf[2] = pps_tf[1]; +@@ -890,8 +894,9 @@ static inline void pps_phase_filter_add(long err) + pps_tf[0] = err; + } + +-/* decrease frequency calibration interval length. +- * It is halved after four consecutive unstable intervals. ++/* ++ * Decrease frequency calibration interval length. It is halved after four ++ * consecutive unstable intervals. + */ + static inline void pps_dec_freq_interval(void) + { +@@ -904,8 +909,9 @@ static inline void pps_dec_freq_interval(void) + } + } + +-/* increase frequency calibration interval length. +- * It is doubled after four consecutive stable intervals. ++/* ++ * Increase frequency calibration interval length. It is doubled after ++ * four consecutive stable intervals. + */ + static inline void pps_inc_freq_interval(void) + { +@@ -918,7 +924,8 @@ static inline void pps_inc_freq_interval(void) + } + } + +-/* update clock frequency based on MONOTONIC_RAW clock PPS signal ++/* ++ * Update clock frequency based on MONOTONIC_RAW clock PPS signal + * timestamps + * + * At the end of the calibration interval the difference between the +@@ -932,7 +939,7 @@ static long hardpps_update_freq(struct pps_normtime freq_norm) + long delta, delta_mod; + s64 ftemp; + +- /* check if the frequency interval was too long */ ++ /* Check if the frequency interval was too long */ + if (freq_norm.sec > (2 << pps_shift)) { + time_status |= STA_PPSERROR; + pps_errcnt++; +@@ -943,9 +950,10 @@ static long hardpps_update_freq(struct pps_normtime freq_norm) + return 0; + } + +- /* here the raw frequency offset and wander (stability) is +- * calculated. If the wander is less than the wander threshold +- * the interval is increased; otherwise it is decreased. ++ /* ++ * Here the raw frequency offset and wander (stability) is ++ * calculated. If the wander is less than the wander threshold the ++ * interval is increased; otherwise it is decreased. + */ + ftemp = div_s64(((s64)(-freq_norm.nsec)) << NTP_SCALE_SHIFT, + freq_norm.sec); +@@ -957,13 +965,14 @@ static long hardpps_update_freq(struct pps_normtime freq_norm) + time_status |= STA_PPSWANDER; + pps_stbcnt++; + pps_dec_freq_interval(); +- } else { /* good sample */ ++ } else { ++ /* Good sample */ + pps_inc_freq_interval(); + } + +- /* the stability metric is calculated as the average of recent +- * frequency changes, but is used only for performance +- * monitoring ++ /* ++ * The stability metric is calculated as the average of recent ++ * frequency changes, but is used only for performance monitoring + */ + delta_mod = delta; + if (delta_mod < 0) +@@ -972,7 +981,7 @@ static long hardpps_update_freq(struct pps_normtime freq_norm) + (NTP_SCALE_SHIFT - SHIFT_USEC), + NSEC_PER_USEC) - pps_stabil) >> PPS_INTMIN; + +- /* if enabled, the system clock frequency is updated */ ++ /* If enabled, the system clock frequency is updated */ + if ((time_status & STA_PPSFREQ) != 0 && + (time_status & STA_FREQHOLD) == 0) { + time_freq = pps_freq; +@@ -982,17 +991,18 @@ static long hardpps_update_freq(struct pps_normtime freq_norm) + return delta; + } + +-/* correct REALTIME clock phase error against PPS signal */ ++/* Correct REALTIME clock phase error against PPS signal */ + static void hardpps_update_phase(long error) + { + long correction = -error; + long jitter; + +- /* add the sample to the median filter */ ++ /* Add the sample to the median filter */ + pps_phase_filter_add(correction); + correction = pps_phase_filter_get(&jitter); + +- /* Nominal jitter is due to PPS signal noise. If it exceeds the ++ /* ++ * Nominal jitter is due to PPS signal noise. If it exceeds the + * threshold, the sample is discarded; otherwise, if so enabled, + * the time offset is updated. + */ +@@ -1003,13 +1013,13 @@ static void hardpps_update_phase(long error) + time_status |= STA_PPSJITTER; + pps_jitcnt++; + } else if (time_status & STA_PPSTIME) { +- /* correct the time using the phase offset */ ++ /* Correct the time using the phase offset */ + time_offset = div_s64(((s64)correction) << NTP_SCALE_SHIFT, + NTP_INTERVAL_FREQ); +- /* cancel running adjtime() */ ++ /* Cancel running adjtime() */ + time_adjust = 0; + } +- /* update jitter */ ++ /* Update jitter */ + pps_jitter += (jitter - pps_jitter) >> PPS_INTMIN; + } + +@@ -1031,41 +1041,43 @@ void __hardpps(const struct timespec64 *phase_ts, const struct timespec64 *raw_t + + pts_norm = pps_normalize_ts(*phase_ts); + +- /* clear the error bits, they will be set again if needed */ ++ /* Clear the error bits, they will be set again if needed */ + time_status &= ~(STA_PPSJITTER | STA_PPSWANDER | STA_PPSERROR); + +- /* indicate signal presence */ ++ /* Indicate signal presence */ + time_status |= STA_PPSSIGNAL; + pps_valid = PPS_VALID; + +- /* when called for the first time, +- * just start the frequency interval */ ++ /* ++ * When called for the first time, just start the frequency ++ * interval ++ */ + if (unlikely(pps_fbase.tv_sec == 0)) { + pps_fbase = *raw_ts; + return; + } + +- /* ok, now we have a base for frequency calculation */ ++ /* Ok, now we have a base for frequency calculation */ + freq_norm = pps_normalize_ts(timespec64_sub(*raw_ts, pps_fbase)); + +- /* check that the signal is in the range +- * [1s - MAXFREQ us, 1s + MAXFREQ us], otherwise reject it */ ++ /* ++ * Check that the signal is in the range ++ * [1s - MAXFREQ us, 1s + MAXFREQ us], otherwise reject it ++ */ + if ((freq_norm.sec == 0) || + (freq_norm.nsec > MAXFREQ * freq_norm.sec) || + (freq_norm.nsec < -MAXFREQ * freq_norm.sec)) { + time_status |= STA_PPSJITTER; +- /* restart the frequency calibration interval */ ++ /* Restart the frequency calibration interval */ + pps_fbase = *raw_ts; + printk_deferred(KERN_ERR "hardpps: PPSJITTER: bad pulse\n"); + return; + } + +- /* signal is ok */ +- +- /* check if the current frequency interval is finished */ ++ /* Signal is ok. Check if the current frequency interval is finished */ + if (freq_norm.sec >= (1 << pps_shift)) { + pps_calcnt++; +- /* restart the frequency calibration interval */ ++ /* Restart the frequency calibration interval */ + pps_fbase = *raw_ts; + hardpps_update_freq(freq_norm); + } +-- +2.43.0 + diff --git a/queue-6.6/ntp-cleanup-formatting-of-code.patch b/queue-6.6/ntp-cleanup-formatting-of-code.patch new file mode 100644 index 00000000000..aeb5d6b4ccb --- /dev/null +++ b/queue-6.6/ntp-cleanup-formatting-of-code.patch @@ -0,0 +1,134 @@ +From c0d8606cfcee702fb4097c32d30a2cd87d35ddf1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Sep 2024 15:17:40 +0200 +Subject: ntp: Cleanup formatting of code + +From: Anna-Maria Behnsen + +[ Upstream commit 38007dc032bd90920463c5d2e6a27d89f7617d6d ] + +Code is partially formatted in a creative way which makes reading +harder. Examples are function calls over several lines where the +indentation does not start at the same height then the open bracket after +the function name. + +Improve formatting but do not make a functional change. + +Signed-off-by: Anna-Maria Behnsen +Signed-off-by: Thomas Gleixner +Acked-by: John Stultz +Link: https://lore.kernel.org/all/20240911-devel-anna-maria-b4-timers-ptp-ntp-v1-4-2d52f4e13476@linutronix.de +Stable-dep-of: f5807b0606da ("ntp: Remove invalid cast in time offset math") +Signed-off-by: Sasha Levin +--- + kernel/time/ntp.c | 37 +++++++++++++------------------------ + 1 file changed, 13 insertions(+), 24 deletions(-) + +diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c +index 99213d931f63f..eca9de85b0a76 100644 +--- a/kernel/time/ntp.c ++++ b/kernel/time/ntp.c +@@ -428,8 +428,7 @@ int second_overflow(time64_t secs) + } else if (secs == ntp_next_leap_sec) { + leap = -1; + time_state = TIME_OOP; +- printk(KERN_NOTICE +- "Clock: inserting leap second 23:59:60 UTC\n"); ++ pr_notice("Clock: inserting leap second 23:59:60 UTC\n"); + } + break; + case TIME_DEL: +@@ -440,8 +439,7 @@ int second_overflow(time64_t secs) + leap = 1; + ntp_next_leap_sec = TIME64_MAX; + time_state = TIME_WAIT; +- printk(KERN_NOTICE +- "Clock: deleting leap second 23:59:59 UTC\n"); ++ pr_notice("Clock: deleting leap second 23:59:59 UTC\n"); + } + break; + case TIME_OOP: +@@ -834,10 +832,8 @@ int __do_adjtimex(struct __kernel_timex *txc, const struct timespec64 *ts, + txc->tai--; + txc->time.tv_sec++; + } +- if ((time_state == TIME_OOP) && +- (ts->tv_sec == ntp_next_leap_sec)) { ++ if ((time_state == TIME_OOP) && (ts->tv_sec == ntp_next_leap_sec)) + result = TIME_WAIT; +- } + } + + return result; +@@ -944,9 +940,8 @@ static long hardpps_update_freq(struct pps_normtime freq_norm) + time_status |= STA_PPSERROR; + pps_errcnt++; + pps_dec_freq_interval(); +- printk_deferred(KERN_ERR +- "hardpps: PPSERROR: interval too long - %lld s\n", +- freq_norm.sec); ++ printk_deferred(KERN_ERR "hardpps: PPSERROR: interval too long - %lld s\n", ++ freq_norm.sec); + return 0; + } + +@@ -960,8 +955,7 @@ static long hardpps_update_freq(struct pps_normtime freq_norm) + delta = shift_right(ftemp - pps_freq, NTP_SCALE_SHIFT); + pps_freq = ftemp; + if (delta > PPS_MAXWANDER || delta < -PPS_MAXWANDER) { +- printk_deferred(KERN_WARNING +- "hardpps: PPSWANDER: change=%ld\n", delta); ++ printk_deferred(KERN_WARNING "hardpps: PPSWANDER: change=%ld\n", delta); + time_status |= STA_PPSWANDER; + pps_stbcnt++; + pps_dec_freq_interval(); +@@ -977,13 +971,11 @@ static long hardpps_update_freq(struct pps_normtime freq_norm) + delta_mod = delta; + if (delta_mod < 0) + delta_mod = -delta_mod; +- pps_stabil += (div_s64(((s64)delta_mod) << +- (NTP_SCALE_SHIFT - SHIFT_USEC), +- NSEC_PER_USEC) - pps_stabil) >> PPS_INTMIN; ++ pps_stabil += (div_s64(((s64)delta_mod) << (NTP_SCALE_SHIFT - SHIFT_USEC), ++ NSEC_PER_USEC) - pps_stabil) >> PPS_INTMIN; + + /* If enabled, the system clock frequency is updated */ +- if ((time_status & STA_PPSFREQ) != 0 && +- (time_status & STA_FREQHOLD) == 0) { ++ if ((time_status & STA_PPSFREQ) && !(time_status & STA_FREQHOLD)) { + time_freq = pps_freq; + ntp_update_frequency(); + } +@@ -1007,15 +999,13 @@ static void hardpps_update_phase(long error) + * the time offset is updated. + */ + if (jitter > (pps_jitter << PPS_POPCORN)) { +- printk_deferred(KERN_WARNING +- "hardpps: PPSJITTER: jitter=%ld, limit=%ld\n", ++ printk_deferred(KERN_WARNING "hardpps: PPSJITTER: jitter=%ld, limit=%ld\n", + jitter, (pps_jitter << PPS_POPCORN)); + time_status |= STA_PPSJITTER; + pps_jitcnt++; + } else if (time_status & STA_PPSTIME) { + /* Correct the time using the phase offset */ +- time_offset = div_s64(((s64)correction) << NTP_SCALE_SHIFT, +- NTP_INTERVAL_FREQ); ++ time_offset = div_s64(((s64)correction) << NTP_SCALE_SHIFT, NTP_INTERVAL_FREQ); + /* Cancel running adjtime() */ + time_adjust = 0; + } +@@ -1064,9 +1054,8 @@ void __hardpps(const struct timespec64 *phase_ts, const struct timespec64 *raw_t + * Check that the signal is in the range + * [1s - MAXFREQ us, 1s + MAXFREQ us], otherwise reject it + */ +- if ((freq_norm.sec == 0) || +- (freq_norm.nsec > MAXFREQ * freq_norm.sec) || +- (freq_norm.nsec < -MAXFREQ * freq_norm.sec)) { ++ if ((freq_norm.sec == 0) || (freq_norm.nsec > MAXFREQ * freq_norm.sec) || ++ (freq_norm.nsec < -MAXFREQ * freq_norm.sec)) { + time_status |= STA_PPSJITTER; + /* Restart the frequency calibration interval */ + pps_fbase = *raw_ts; +-- +2.43.0 + diff --git a/queue-6.6/ntp-convert-functions-with-only-two-states-to-bool.patch b/queue-6.6/ntp-convert-functions-with-only-two-states-to-bool.patch new file mode 100644 index 00000000000..7e4e8f9641b --- /dev/null +++ b/queue-6.6/ntp-convert-functions-with-only-two-states-to-bool.patch @@ -0,0 +1,92 @@ +From 7066dbaf1f80ebb01a0858ac1700e39e5010bb3d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Sep 2024 15:17:41 +0200 +Subject: ntp: Convert functions with only two states to bool + +From: Thomas Gleixner + +[ Upstream commit 48c3c65f64b01164f1704b40b38f60837d484f13 ] + +is_error_status() and ntp_synced() return whether a state is set or +not. Both functions use unsigned int for it even if it would be a perfect +job for a bool. + +Use bool instead of unsigned int. And while at it, move ntp_synced() +function to the place where it is used. + +No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: Anna-Maria Behnsen +Signed-off-by: Thomas Gleixner +Acked-by: John Stultz +Link: https://lore.kernel.org/all/20240911-devel-anna-maria-b4-timers-ptp-ntp-v1-5-2d52f4e13476@linutronix.de +Stable-dep-of: f5807b0606da ("ntp: Remove invalid cast in time offset math") +Signed-off-by: Sasha Levin +--- + kernel/time/ntp.c | 28 +++++++++++----------------- + 1 file changed, 11 insertions(+), 17 deletions(-) + +diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c +index eca9de85b0a76..ef758aafdfd54 100644 +--- a/kernel/time/ntp.c ++++ b/kernel/time/ntp.c +@@ -171,7 +171,7 @@ static inline void pps_set_freq(s64 freq) + pps_freq = freq; + } + +-static inline int is_error_status(int status) ++static inline bool is_error_status(int status) + { + return (status & (STA_UNSYNC|STA_CLOCKERR)) + /* +@@ -221,7 +221,7 @@ static inline void pps_clear(void) {} + static inline void pps_dec_valid(void) {} + static inline void pps_set_freq(s64 freq) {} + +-static inline int is_error_status(int status) ++static inline bool is_error_status(int status) + { + return status & (STA_UNSYNC|STA_CLOCKERR); + } +@@ -241,21 +241,6 @@ static inline void pps_fill_timex(struct __kernel_timex *txc) + + #endif /* CONFIG_NTP_PPS */ + +- +-/** +- * ntp_synced - Returns 1 if the NTP status is not UNSYNC +- * +- */ +-static inline int ntp_synced(void) +-{ +- return !(time_status & STA_UNSYNC); +-} +- +- +-/* +- * NTP methods: +- */ +- + /* + * Update tick_length and tick_length_base, based on tick_usec, ntp_tick_adj and + * time_freq: +@@ -609,6 +594,15 @@ static inline int update_rtc(struct timespec64 *to_set, unsigned long *offset_ns + } + #endif + ++/** ++ * ntp_synced - Tells whether the NTP status is not UNSYNC ++ * Returns: true if not UNSYNC, false otherwise ++ */ ++static inline bool ntp_synced(void) ++{ ++ return !(time_status & STA_UNSYNC); ++} ++ + /* + * If we have an externally synchronized Linux clock, then update RTC clock + * accordingly every ~11 minutes. Generally RTCs can only store second +-- +2.43.0 + diff --git a/queue-6.6/ntp-introduce-struct-ntp_data.patch b/queue-6.6/ntp-introduce-struct-ntp_data.patch new file mode 100644 index 00000000000..00a66e2680c --- /dev/null +++ b/queue-6.6/ntp-introduce-struct-ntp_data.patch @@ -0,0 +1,220 @@ +From 6018e1b206968dd5a882e341c5582d81b808ffa5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Sep 2024 15:17:43 +0200 +Subject: ntp: Introduce struct ntp_data + +From: Thomas Gleixner + +[ Upstream commit 68f66f97c5689825012877f58df65964056d4b5d ] + +All NTP data is held in static variables. That prevents the NTP code from +being reuasble for non-system time timekeepers, e.g. per PTP clock +timekeeping. + +Introduce struct ntp_data and move tick_usec into it for a start. + +No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: Anna-Maria Behnsen +Signed-off-by: Thomas Gleixner +Acked-by: John Stultz +Link: https://lore.kernel.org/all/20240911-devel-anna-maria-b4-timers-ptp-ntp-v1-7-2d52f4e13476@linutronix.de +Stable-dep-of: f5807b0606da ("ntp: Remove invalid cast in time offset math") +Signed-off-by: Sasha Levin +--- + kernel/time/ntp.c | 65 ++++++++++++++++++++++++++--------------------- + 1 file changed, 36 insertions(+), 29 deletions(-) + +diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c +index 477cb08062bc5..0222f8e460810 100644 +--- a/kernel/time/ntp.c ++++ b/kernel/time/ntp.c +@@ -22,16 +22,19 @@ + #include "ntp_internal.h" + #include "timekeeping_internal.h" + +- +-/* +- * NTP timekeeping variables: ++/** ++ * struct ntp_data - Structure holding all NTP related state ++ * @tick_usec: USER_HZ period in microseconds + * +- * Note: All of the NTP state is protected by the timekeeping locks. ++ * Protected by the timekeeping locks. + */ ++struct ntp_data { ++ unsigned long tick_usec; ++}; + +- +-/* USER_HZ period (usecs): */ +-static unsigned long tick_usec = USER_TICK_USEC; ++static struct ntp_data tk_ntp_data = { ++ .tick_usec = USER_TICK_USEC, ++}; + + static u64 tick_length; + static u64 tick_length_base; +@@ -245,13 +248,11 @@ static inline void pps_fill_timex(struct __kernel_timex *txc) + * Update tick_length and tick_length_base, based on tick_usec, ntp_tick_adj and + * time_freq: + */ +-static void ntp_update_frequency(void) ++static void ntp_update_frequency(struct ntp_data *ntpdata) + { +- u64 second_length; +- u64 new_base; ++ u64 second_length, new_base, tick_usec = (u64)ntpdata->tick_usec; + +- second_length = (u64)(tick_usec * NSEC_PER_USEC * USER_HZ) +- << NTP_SCALE_SHIFT; ++ second_length = (u64)(tick_usec * NSEC_PER_USEC * USER_HZ) << NTP_SCALE_SHIFT; + + second_length += ntp_tick_adj; + second_length += time_freq; +@@ -330,10 +331,7 @@ static void ntp_update_offset(long offset) + time_offset = div_s64(offset64 << NTP_SCALE_SHIFT, NTP_INTERVAL_FREQ); + } + +-/** +- * ntp_clear - Clears the NTP state variables +- */ +-void ntp_clear(void) ++static void __ntp_clear(struct ntp_data *ntpdata) + { + /* Stop active adjtime() */ + time_adjust = 0; +@@ -341,7 +339,7 @@ void ntp_clear(void) + time_maxerror = NTP_PHASE_LIMIT; + time_esterror = NTP_PHASE_LIMIT; + +- ntp_update_frequency(); ++ ntp_update_frequency(ntpdata); + + tick_length = tick_length_base; + time_offset = 0; +@@ -351,6 +349,14 @@ void ntp_clear(void) + pps_clear(); + } + ++/** ++ * ntp_clear - Clears the NTP state variables ++ */ ++void ntp_clear(void) ++{ ++ __ntp_clear(&tk_ntp_data); ++} ++ + + u64 ntp_tick_length(void) + { +@@ -698,7 +704,7 @@ static inline void process_adj_status(const struct __kernel_timex *txc) + } + + +-static inline void process_adjtimex_modes(const struct __kernel_timex *txc, ++static inline void process_adjtimex_modes(struct ntp_data *ntpdata, const struct __kernel_timex *txc, + s32 *time_tai) + { + if (txc->modes & ADJ_STATUS) +@@ -739,13 +745,12 @@ static inline void process_adjtimex_modes(const struct __kernel_timex *txc, + ntp_update_offset(txc->offset); + + if (txc->modes & ADJ_TICK) +- tick_usec = txc->tick; ++ ntpdata->tick_usec = txc->tick; + + if (txc->modes & (ADJ_TICK|ADJ_FREQUENCY|ADJ_OFFSET)) +- ntp_update_frequency(); ++ ntp_update_frequency(ntpdata); + } + +- + /* + * adjtimex() mainly allows reading (and writing, if superuser) of + * kernel time-keeping variables. used by xntpd. +@@ -753,6 +758,7 @@ static inline void process_adjtimex_modes(const struct __kernel_timex *txc, + int __do_adjtimex(struct __kernel_timex *txc, const struct timespec64 *ts, + s32 *time_tai, struct audit_ntp_data *ad) + { ++ struct ntp_data *ntpdata = &tk_ntp_data; + int result; + + if (txc->modes & ADJ_ADJTIME) { +@@ -761,7 +767,7 @@ int __do_adjtimex(struct __kernel_timex *txc, const struct timespec64 *ts, + if (!(txc->modes & ADJ_OFFSET_READONLY)) { + /* adjtime() is independent from ntp_adjtime() */ + time_adjust = txc->offset; +- ntp_update_frequency(); ++ ntp_update_frequency(ntpdata); + + audit_ntp_set_old(ad, AUDIT_NTP_ADJUST, save_adjust); + audit_ntp_set_new(ad, AUDIT_NTP_ADJUST, time_adjust); +@@ -774,15 +780,15 @@ int __do_adjtimex(struct __kernel_timex *txc, const struct timespec64 *ts, + audit_ntp_set_old(ad, AUDIT_NTP_FREQ, time_freq); + audit_ntp_set_old(ad, AUDIT_NTP_STATUS, time_status); + audit_ntp_set_old(ad, AUDIT_NTP_TAI, *time_tai); +- audit_ntp_set_old(ad, AUDIT_NTP_TICK, tick_usec); ++ audit_ntp_set_old(ad, AUDIT_NTP_TICK, ntpdata->tick_usec); + +- process_adjtimex_modes(txc, time_tai); ++ process_adjtimex_modes(ntpdata, txc, time_tai); + + audit_ntp_set_new(ad, AUDIT_NTP_OFFSET, time_offset); + audit_ntp_set_new(ad, AUDIT_NTP_FREQ, time_freq); + audit_ntp_set_new(ad, AUDIT_NTP_STATUS, time_status); + audit_ntp_set_new(ad, AUDIT_NTP_TAI, *time_tai); +- audit_ntp_set_new(ad, AUDIT_NTP_TICK, tick_usec); ++ audit_ntp_set_new(ad, AUDIT_NTP_TICK, ntpdata->tick_usec); + } + + txc->offset = shift_right(time_offset * NTP_INTERVAL_FREQ, +@@ -803,7 +809,7 @@ int __do_adjtimex(struct __kernel_timex *txc, const struct timespec64 *ts, + txc->constant = time_constant; + txc->precision = 1; + txc->tolerance = MAXFREQ_SCALED / PPM_SCALE; +- txc->tick = tick_usec; ++ txc->tick = ntpdata->tick_usec; + txc->tai = *time_tai; + + /* Fill PPS status fields */ +@@ -924,7 +930,7 @@ static inline void pps_inc_freq_interval(void) + * too long, the data are discarded. + * Returns the difference between old and new frequency values. + */ +-static long hardpps_update_freq(struct pps_normtime freq_norm) ++static long hardpps_update_freq(struct ntp_data *ntpdata, struct pps_normtime freq_norm) + { + long delta, delta_mod; + s64 ftemp; +@@ -971,7 +977,7 @@ static long hardpps_update_freq(struct pps_normtime freq_norm) + /* If enabled, the system clock frequency is updated */ + if ((time_status & STA_PPSFREQ) && !(time_status & STA_FREQHOLD)) { + time_freq = pps_freq; +- ntp_update_frequency(); ++ ntp_update_frequency(ntpdata); + } + + return delta; +@@ -1022,6 +1028,7 @@ static void hardpps_update_phase(long error) + void __hardpps(const struct timespec64 *phase_ts, const struct timespec64 *raw_ts) + { + struct pps_normtime pts_norm, freq_norm; ++ struct ntp_data *ntpdata = &tk_ntp_data; + + pts_norm = pps_normalize_ts(*phase_ts); + +@@ -1062,7 +1069,7 @@ void __hardpps(const struct timespec64 *phase_ts, const struct timespec64 *raw_t + pps_calcnt++; + /* Restart the frequency calibration interval */ + pps_fbase = *raw_ts; +- hardpps_update_freq(freq_norm); ++ hardpps_update_freq(ntpdata, freq_norm); + } + + hardpps_update_phase(pts_norm.nsec); +-- +2.43.0 + diff --git a/queue-6.6/ntp-make-tick_usec-static.patch b/queue-6.6/ntp-make-tick_usec-static.patch new file mode 100644 index 00000000000..6611eec7ff1 --- /dev/null +++ b/queue-6.6/ntp-make-tick_usec-static.patch @@ -0,0 +1,68 @@ +From ed880bbf9b143c63503fc3517068434dee9d390f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Sep 2024 15:17:38 +0200 +Subject: ntp: Make tick_usec static + +From: Thomas Gleixner + +[ Upstream commit 66606a93849bfe3cbe9f0b801b40f60b87c54e11 ] + +There are no users of tick_usec outside of the NTP core code. Therefore +make tick_usec static. + +Signed-off-by: Thomas Gleixner +Signed-off-by: Anna-Maria Behnsen +Signed-off-by: Thomas Gleixner +Acked-by: John Stultz +Link: https://lore.kernel.org/all/20240911-devel-anna-maria-b4-timers-ptp-ntp-v1-2-2d52f4e13476@linutronix.de +Stable-dep-of: f5807b0606da ("ntp: Remove invalid cast in time offset math") +Signed-off-by: Sasha Levin +--- + include/linux/timex.h | 7 ------- + kernel/time/ntp.c | 5 ++++- + 2 files changed, 4 insertions(+), 8 deletions(-) + +diff --git a/include/linux/timex.h b/include/linux/timex.h +index 7f7a12fd8200c..4ee32eff3f221 100644 +--- a/include/linux/timex.h ++++ b/include/linux/timex.h +@@ -139,13 +139,6 @@ unsigned long random_get_entropy_fallback(void); + #define MAXSEC 2048 /* max interval between updates (s) */ + #define NTP_PHASE_LIMIT ((MAXPHASE / NSEC_PER_USEC) << 5) /* beyond max. dispersion */ + +-/* +- * kernel variables +- * Note: maximum error = NTP sync distance = dispersion + delay / 2; +- * estimated error = NTP dispersion. +- */ +-extern unsigned long tick_usec; /* USER_HZ period (usec) */ +- + /* Required to safely shift negative values */ + #define shift_right(x, s) ({ \ + __typeof__(x) __x = (x); \ +diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c +index 0dba1179d81d2..8e68a85996f7d 100644 +--- a/kernel/time/ntp.c ++++ b/kernel/time/ntp.c +@@ -31,7 +31,7 @@ + + + /* USER_HZ period (usecs): */ +-unsigned long tick_usec = USER_TICK_USEC; ++static unsigned long tick_usec = USER_TICK_USEC; + + static u64 tick_length; + static u64 tick_length_base; +@@ -44,6 +44,9 @@ static u64 tick_length_base; + + /* + * phase-lock loop variables ++ * ++ * Note: maximum error = NTP sync distance = dispersion + delay / 2; ++ * estimated error = NTP dispersion. + */ + + /* +-- +2.43.0 + diff --git a/queue-6.6/ntp-move-tick_length-into-ntp_data.patch b/queue-6.6/ntp-move-tick_length-into-ntp_data.patch new file mode 100644 index 00000000000..1f0d3ac170d --- /dev/null +++ b/queue-6.6/ntp-move-tick_length-into-ntp_data.patch @@ -0,0 +1,134 @@ +From 57c1e66e29a0a5d9499dfab702f04b00251e7e6f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Sep 2024 15:17:44 +0200 +Subject: ntp: Move tick_length* into ntp_data + +From: Thomas Gleixner + +[ Upstream commit ec93ec22aa10fb5311c0f068ee66c5b6d39788fe ] + +Continue the conversion from static variables to struct based data. + +No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: Anna-Maria Behnsen +Signed-off-by: Thomas Gleixner +Acked-by: John Stultz +Link: https://lore.kernel.org/all/20240911-devel-anna-maria-b4-timers-ptp-ntp-v1-8-2d52f4e13476@linutronix.de +Stable-dep-of: f5807b0606da ("ntp: Remove invalid cast in time offset math") +Signed-off-by: Sasha Levin +--- + kernel/time/ntp.c | 34 ++++++++++++++++++---------------- + 1 file changed, 18 insertions(+), 16 deletions(-) + +diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c +index 0222f8e460810..6c5f684328c82 100644 +--- a/kernel/time/ntp.c ++++ b/kernel/time/ntp.c +@@ -25,20 +25,21 @@ + /** + * struct ntp_data - Structure holding all NTP related state + * @tick_usec: USER_HZ period in microseconds ++ * @tick_length: Adjusted tick length ++ * @tick_length_base: Base value for @tick_length + * + * Protected by the timekeeping locks. + */ + struct ntp_data { + unsigned long tick_usec; ++ u64 tick_length; ++ u64 tick_length_base; + }; + + static struct ntp_data tk_ntp_data = { + .tick_usec = USER_TICK_USEC, + }; + +-static u64 tick_length; +-static u64 tick_length_base; +- + #define SECS_PER_DAY 86400 + #define MAX_TICKADJ 500LL /* usecs */ + #define MAX_TICKADJ_SCALED \ +@@ -263,8 +264,8 @@ static void ntp_update_frequency(struct ntp_data *ntpdata) + * Don't wait for the next second_overflow, apply the change to the + * tick length immediately: + */ +- tick_length += new_base - tick_length_base; +- tick_length_base = new_base; ++ ntpdata->tick_length += new_base - ntpdata->tick_length_base; ++ ntpdata->tick_length_base = new_base; + } + + static inline s64 ntp_update_offset_fll(s64 offset64, long secs) +@@ -341,8 +342,8 @@ static void __ntp_clear(struct ntp_data *ntpdata) + + ntp_update_frequency(ntpdata); + +- tick_length = tick_length_base; +- time_offset = 0; ++ ntpdata->tick_length = ntpdata->tick_length_base; ++ time_offset = 0; + + ntp_next_leap_sec = TIME64_MAX; + /* Clear PPS state variables */ +@@ -360,7 +361,7 @@ void ntp_clear(void) + + u64 ntp_tick_length(void) + { +- return tick_length; ++ return tk_ntp_data.tick_length; + } + + /** +@@ -391,6 +392,7 @@ ktime_t ntp_get_next_leap(void) + */ + int second_overflow(time64_t secs) + { ++ struct ntp_data *ntpdata = &tk_ntp_data; + s64 delta; + int leap = 0; + s32 rem; +@@ -451,11 +453,11 @@ int second_overflow(time64_t secs) + } + + /* Compute the phase adjustment for the next second */ +- tick_length = tick_length_base; ++ ntpdata->tick_length = ntpdata->tick_length_base; + +- delta = ntp_offset_chunk(time_offset); +- time_offset -= delta; +- tick_length += delta; ++ delta = ntp_offset_chunk(time_offset); ++ time_offset -= delta; ++ ntpdata->tick_length += delta; + + /* Check PPS signal */ + pps_dec_valid(); +@@ -465,18 +467,18 @@ int second_overflow(time64_t secs) + + if (time_adjust > MAX_TICKADJ) { + time_adjust -= MAX_TICKADJ; +- tick_length += MAX_TICKADJ_SCALED; ++ ntpdata->tick_length += MAX_TICKADJ_SCALED; + goto out; + } + + if (time_adjust < -MAX_TICKADJ) { + time_adjust += MAX_TICKADJ; +- tick_length -= MAX_TICKADJ_SCALED; ++ ntpdata->tick_length -= MAX_TICKADJ_SCALED; + goto out; + } + +- tick_length += (s64)(time_adjust * NSEC_PER_USEC / NTP_INTERVAL_FREQ) +- << NTP_SCALE_SHIFT; ++ ntpdata->tick_length += (s64)(time_adjust * NSEC_PER_USEC / NTP_INTERVAL_FREQ) ++ << NTP_SCALE_SHIFT; + time_adjust = 0; + + out: +-- +2.43.0 + diff --git a/queue-6.6/ntp-move-tick_stat-into-ntp_data.patch b/queue-6.6/ntp-move-tick_stat-into-ntp_data.patch new file mode 100644 index 00000000000..b09d17e61b4 --- /dev/null +++ b/queue-6.6/ntp-move-tick_stat-into-ntp_data.patch @@ -0,0 +1,539 @@ +From 69572175a7bf6c25a1cb294df994464fe1fd3467 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Sep 2024 15:17:45 +0200 +Subject: ntp: Move tick_stat* into ntp_data + +From: Thomas Gleixner + +[ Upstream commit bee18a2301f97465a464176767f3a3a64f900d93 ] + +Continue the conversion from static variables to struct based data. + +No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: Anna-Maria Behnsen +Signed-off-by: Thomas Gleixner +Acked-by: John Stultz +Link: https://lore.kernel.org/all/20240911-devel-anna-maria-b4-timers-ptp-ntp-v1-9-2d52f4e13476@linutronix.de +Stable-dep-of: f5807b0606da ("ntp: Remove invalid cast in time offset math") +Signed-off-by: Sasha Levin +--- + kernel/time/ntp.c | 175 ++++++++++++++++++++++------------------------ + 1 file changed, 85 insertions(+), 90 deletions(-) + +diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c +index 6c5f684328c82..6d87f9889b039 100644 +--- a/kernel/time/ntp.c ++++ b/kernel/time/ntp.c +@@ -27,6 +27,8 @@ + * @tick_usec: USER_HZ period in microseconds + * @tick_length: Adjusted tick length + * @tick_length_base: Base value for @tick_length ++ * @time_state: State of the clock synchronization ++ * @time_status: Clock status bits + * + * Protected by the timekeeping locks. + */ +@@ -34,10 +36,14 @@ struct ntp_data { + unsigned long tick_usec; + u64 tick_length; + u64 tick_length_base; ++ int time_state; ++ int time_status; + }; + + static struct ntp_data tk_ntp_data = { + .tick_usec = USER_TICK_USEC, ++ .time_state = TIME_OK, ++ .time_status = STA_UNSYNC, + }; + + #define SECS_PER_DAY 86400 +@@ -53,16 +59,6 @@ static struct ntp_data tk_ntp_data = { + * estimated error = NTP dispersion. + */ + +-/* +- * clock synchronization status +- * +- * (TIME_ERROR prevents overwriting the CMOS clock) +- */ +-static int time_state = TIME_OK; +- +-/* clock status bits: */ +-static int time_status = STA_UNSYNC; +- + /* time adjustment (nsecs): */ + static s64 time_offset; + +@@ -127,9 +123,9 @@ static long pps_errcnt; /* calibration errors */ + * PPS kernel consumer compensates the whole phase error immediately. + * Otherwise, reduce the offset by a fixed factor times the time constant. + */ +-static inline s64 ntp_offset_chunk(s64 offset) ++static inline s64 ntp_offset_chunk(struct ntp_data *ntpdata, s64 offset) + { +- if (time_status & STA_PPSTIME && time_status & STA_PPSSIGNAL) ++ if (ntpdata->time_status & STA_PPSTIME && ntpdata->time_status & STA_PPSSIGNAL) + return offset; + else + return shift_right(offset, SHIFT_PLL + time_constant); +@@ -159,13 +155,13 @@ static inline void pps_clear(void) + * Decrease pps_valid to indicate that another second has passed since the + * last PPS signal. When it reaches 0, indicate that PPS signal is missing. + */ +-static inline void pps_dec_valid(void) ++static inline void pps_dec_valid(struct ntp_data *ntpdata) + { + if (pps_valid > 0) + pps_valid--; + else { +- time_status &= ~(STA_PPSSIGNAL | STA_PPSJITTER | +- STA_PPSWANDER | STA_PPSERROR); ++ ntpdata->time_status &= ~(STA_PPSSIGNAL | STA_PPSJITTER | ++ STA_PPSWANDER | STA_PPSERROR); + pps_clear(); + } + } +@@ -198,12 +194,12 @@ static inline bool is_error_status(int status) + && (status & (STA_PPSWANDER|STA_PPSERROR))); + } + +-static inline void pps_fill_timex(struct __kernel_timex *txc) ++static inline void pps_fill_timex(struct ntp_data *ntpdata, struct __kernel_timex *txc) + { + txc->ppsfreq = shift_right((pps_freq >> PPM_SCALE_INV_SHIFT) * + PPM_SCALE_INV, NTP_SCALE_SHIFT); + txc->jitter = pps_jitter; +- if (!(time_status & STA_NANO)) ++ if (!(ntpdata->time_status & STA_NANO)) + txc->jitter = pps_jitter / NSEC_PER_USEC; + txc->shift = pps_shift; + txc->stabil = pps_stabil; +@@ -215,14 +211,14 @@ static inline void pps_fill_timex(struct __kernel_timex *txc) + + #else /* !CONFIG_NTP_PPS */ + +-static inline s64 ntp_offset_chunk(s64 offset) ++static inline s64 ntp_offset_chunk(struct ntp_data *ntp, s64 offset) + { + return shift_right(offset, SHIFT_PLL + time_constant); + } + + static inline void pps_reset_freq_interval(void) {} + static inline void pps_clear(void) {} +-static inline void pps_dec_valid(void) {} ++static inline void pps_dec_valid(struct ntp_data *ntpdata) {} + static inline void pps_set_freq(s64 freq) {} + + static inline bool is_error_status(int status) +@@ -230,7 +226,7 @@ static inline bool is_error_status(int status) + return status & (STA_UNSYNC|STA_CLOCKERR); + } + +-static inline void pps_fill_timex(struct __kernel_timex *txc) ++static inline void pps_fill_timex(struct ntp_data *ntpdata, struct __kernel_timex *txc) + { + /* PPS is not implemented, so these are zero */ + txc->ppsfreq = 0; +@@ -268,30 +264,30 @@ static void ntp_update_frequency(struct ntp_data *ntpdata) + ntpdata->tick_length_base = new_base; + } + +-static inline s64 ntp_update_offset_fll(s64 offset64, long secs) ++static inline s64 ntp_update_offset_fll(struct ntp_data *ntpdata, s64 offset64, long secs) + { +- time_status &= ~STA_MODE; ++ ntpdata->time_status &= ~STA_MODE; + + if (secs < MINSEC) + return 0; + +- if (!(time_status & STA_FLL) && (secs <= MAXSEC)) ++ if (!(ntpdata->time_status & STA_FLL) && (secs <= MAXSEC)) + return 0; + +- time_status |= STA_MODE; ++ ntpdata->time_status |= STA_MODE; + + return div64_long(offset64 << (NTP_SCALE_SHIFT - SHIFT_FLL), secs); + } + +-static void ntp_update_offset(long offset) ++static void ntp_update_offset(struct ntp_data *ntpdata, long offset) + { + s64 freq_adj, offset64; + long secs, real_secs; + +- if (!(time_status & STA_PLL)) ++ if (!(ntpdata->time_status & STA_PLL)) + return; + +- if (!(time_status & STA_NANO)) { ++ if (!(ntpdata->time_status & STA_NANO)) { + /* Make sure the multiplication below won't overflow */ + offset = clamp(offset, -USEC_PER_SEC, USEC_PER_SEC); + offset *= NSEC_PER_USEC; +@@ -306,13 +302,13 @@ static void ntp_update_offset(long offset) + */ + real_secs = __ktime_get_real_seconds(); + secs = (long)(real_secs - time_reftime); +- if (unlikely(time_status & STA_FREQHOLD)) ++ if (unlikely(ntpdata->time_status & STA_FREQHOLD)) + secs = 0; + + time_reftime = real_secs; + + offset64 = offset; +- freq_adj = ntp_update_offset_fll(offset64, secs); ++ freq_adj = ntp_update_offset_fll(ntpdata, offset64, secs); + + /* + * Clamp update interval to reduce PLL gain with low +@@ -335,10 +331,10 @@ static void ntp_update_offset(long offset) + static void __ntp_clear(struct ntp_data *ntpdata) + { + /* Stop active adjtime() */ +- time_adjust = 0; +- time_status |= STA_UNSYNC; +- time_maxerror = NTP_PHASE_LIMIT; +- time_esterror = NTP_PHASE_LIMIT; ++ time_adjust = 0; ++ ntpdata->time_status |= STA_UNSYNC; ++ time_maxerror = NTP_PHASE_LIMIT; ++ time_esterror = NTP_PHASE_LIMIT; + + ntp_update_frequency(ntpdata); + +@@ -372,9 +368,10 @@ u64 ntp_tick_length(void) + */ + ktime_t ntp_get_next_leap(void) + { ++ struct ntp_data *ntpdata = &tk_ntp_data; + ktime_t ret; + +- if ((time_state == TIME_INS) && (time_status & STA_INS)) ++ if ((ntpdata->time_state == TIME_INS) && (ntpdata->time_status & STA_INS)) + return ktime_set(ntp_next_leap_sec, 0); + ret = KTIME_MAX; + return ret; +@@ -402,46 +399,46 @@ int second_overflow(time64_t secs) + * day, the system clock is set back one second; if in leap-delete + * state, the system clock is set ahead one second. + */ +- switch (time_state) { ++ switch (ntpdata->time_state) { + case TIME_OK: +- if (time_status & STA_INS) { +- time_state = TIME_INS; ++ if (ntpdata->time_status & STA_INS) { ++ ntpdata->time_state = TIME_INS; + div_s64_rem(secs, SECS_PER_DAY, &rem); + ntp_next_leap_sec = secs + SECS_PER_DAY - rem; +- } else if (time_status & STA_DEL) { +- time_state = TIME_DEL; ++ } else if (ntpdata->time_status & STA_DEL) { ++ ntpdata->time_state = TIME_DEL; + div_s64_rem(secs + 1, SECS_PER_DAY, &rem); + ntp_next_leap_sec = secs + SECS_PER_DAY - rem; + } + break; + case TIME_INS: +- if (!(time_status & STA_INS)) { ++ if (!(ntpdata->time_status & STA_INS)) { + ntp_next_leap_sec = TIME64_MAX; +- time_state = TIME_OK; ++ ntpdata->time_state = TIME_OK; + } else if (secs == ntp_next_leap_sec) { + leap = -1; +- time_state = TIME_OOP; ++ ntpdata->time_state = TIME_OOP; + pr_notice("Clock: inserting leap second 23:59:60 UTC\n"); + } + break; + case TIME_DEL: +- if (!(time_status & STA_DEL)) { ++ if (!(ntpdata->time_status & STA_DEL)) { + ntp_next_leap_sec = TIME64_MAX; +- time_state = TIME_OK; ++ ntpdata->time_state = TIME_OK; + } else if (secs == ntp_next_leap_sec) { + leap = 1; + ntp_next_leap_sec = TIME64_MAX; +- time_state = TIME_WAIT; ++ ntpdata->time_state = TIME_WAIT; + pr_notice("Clock: deleting leap second 23:59:59 UTC\n"); + } + break; + case TIME_OOP: + ntp_next_leap_sec = TIME64_MAX; +- time_state = TIME_WAIT; ++ ntpdata->time_state = TIME_WAIT; + break; + case TIME_WAIT: +- if (!(time_status & (STA_INS | STA_DEL))) +- time_state = TIME_OK; ++ if (!(ntpdata->time_status & (STA_INS | STA_DEL))) ++ ntpdata->time_state = TIME_OK; + break; + } + +@@ -449,18 +446,18 @@ int second_overflow(time64_t secs) + time_maxerror += MAXFREQ / NSEC_PER_USEC; + if (time_maxerror > NTP_PHASE_LIMIT) { + time_maxerror = NTP_PHASE_LIMIT; +- time_status |= STA_UNSYNC; ++ ntpdata->time_status |= STA_UNSYNC; + } + + /* Compute the phase adjustment for the next second */ + ntpdata->tick_length = ntpdata->tick_length_base; + +- delta = ntp_offset_chunk(time_offset); ++ delta = ntp_offset_chunk(ntpdata, time_offset); + time_offset -= delta; + ntpdata->tick_length += delta; + + /* Check PPS signal */ +- pps_dec_valid(); ++ pps_dec_valid(ntpdata); + + if (!time_adjust) + goto out; +@@ -608,7 +605,7 @@ static inline int update_rtc(struct timespec64 *to_set, unsigned long *offset_ns + */ + static inline bool ntp_synced(void) + { +- return !(time_status & STA_UNSYNC); ++ return !(tk_ntp_data.time_status & STA_UNSYNC); + } + + /* +@@ -683,11 +680,11 @@ static inline void __init ntp_init_cmos_sync(void) { } + /* + * Propagate a new txc->status value into the NTP state: + */ +-static inline void process_adj_status(const struct __kernel_timex *txc) ++static inline void process_adj_status(struct ntp_data *ntpdata, const struct __kernel_timex *txc) + { +- if ((time_status & STA_PLL) && !(txc->status & STA_PLL)) { +- time_state = TIME_OK; +- time_status = STA_UNSYNC; ++ if ((ntpdata->time_status & STA_PLL) && !(txc->status & STA_PLL)) { ++ ntpdata->time_state = TIME_OK; ++ ntpdata->time_status = STA_UNSYNC; + ntp_next_leap_sec = TIME64_MAX; + /* Restart PPS frequency calibration */ + pps_reset_freq_interval(); +@@ -697,26 +694,25 @@ static inline void process_adj_status(const struct __kernel_timex *txc) + * If we turn on PLL adjustments then reset the + * reference time to current time. + */ +- if (!(time_status & STA_PLL) && (txc->status & STA_PLL)) ++ if (!(ntpdata->time_status & STA_PLL) && (txc->status & STA_PLL)) + time_reftime = __ktime_get_real_seconds(); + +- /* Only set allowed bits */ +- time_status &= STA_RONLY; +- time_status |= txc->status & ~STA_RONLY; ++ /* only set allowed bits */ ++ ntpdata->time_status &= STA_RONLY; ++ ntpdata->time_status |= txc->status & ~STA_RONLY; + } + +- + static inline void process_adjtimex_modes(struct ntp_data *ntpdata, const struct __kernel_timex *txc, + s32 *time_tai) + { + if (txc->modes & ADJ_STATUS) +- process_adj_status(txc); ++ process_adj_status(ntpdata, txc); + + if (txc->modes & ADJ_NANO) +- time_status |= STA_NANO; ++ ntpdata->time_status |= STA_NANO; + + if (txc->modes & ADJ_MICRO) +- time_status &= ~STA_NANO; ++ ntpdata->time_status &= ~STA_NANO; + + if (txc->modes & ADJ_FREQUENCY) { + time_freq = txc->freq * PPM_SCALE; +@@ -734,17 +730,16 @@ static inline void process_adjtimex_modes(struct ntp_data *ntpdata, const struct + + if (txc->modes & ADJ_TIMECONST) { + time_constant = clamp(txc->constant, 0, MAXTC); +- if (!(time_status & STA_NANO)) ++ if (!(ntpdata->time_status & STA_NANO)) + time_constant += 4; + time_constant = clamp(time_constant, 0, MAXTC); + } + +- if (txc->modes & ADJ_TAI && +- txc->constant >= 0 && txc->constant <= MAX_TAI_OFFSET) ++ if (txc->modes & ADJ_TAI && txc->constant >= 0 && txc->constant <= MAX_TAI_OFFSET) + *time_tai = txc->constant; + + if (txc->modes & ADJ_OFFSET) +- ntp_update_offset(txc->offset); ++ ntp_update_offset(ntpdata, txc->offset); + + if (txc->modes & ADJ_TICK) + ntpdata->tick_usec = txc->tick; +@@ -780,7 +775,7 @@ int __do_adjtimex(struct __kernel_timex *txc, const struct timespec64 *ts, + if (txc->modes) { + audit_ntp_set_old(ad, AUDIT_NTP_OFFSET, time_offset); + audit_ntp_set_old(ad, AUDIT_NTP_FREQ, time_freq); +- audit_ntp_set_old(ad, AUDIT_NTP_STATUS, time_status); ++ audit_ntp_set_old(ad, AUDIT_NTP_STATUS, ntpdata->time_status); + audit_ntp_set_old(ad, AUDIT_NTP_TAI, *time_tai); + audit_ntp_set_old(ad, AUDIT_NTP_TICK, ntpdata->tick_usec); + +@@ -788,26 +783,26 @@ int __do_adjtimex(struct __kernel_timex *txc, const struct timespec64 *ts, + + audit_ntp_set_new(ad, AUDIT_NTP_OFFSET, time_offset); + audit_ntp_set_new(ad, AUDIT_NTP_FREQ, time_freq); +- audit_ntp_set_new(ad, AUDIT_NTP_STATUS, time_status); ++ audit_ntp_set_new(ad, AUDIT_NTP_STATUS, ntpdata->time_status); + audit_ntp_set_new(ad, AUDIT_NTP_TAI, *time_tai); + audit_ntp_set_new(ad, AUDIT_NTP_TICK, ntpdata->tick_usec); + } + + txc->offset = shift_right(time_offset * NTP_INTERVAL_FREQ, + NTP_SCALE_SHIFT); +- if (!(time_status & STA_NANO)) ++ if (!(ntpdata->time_status & STA_NANO)) + txc->offset = (u32)txc->offset / NSEC_PER_USEC; + } + +- result = time_state; +- if (is_error_status(time_status)) ++ result = ntpdata->time_state; ++ if (is_error_status(ntpdata->time_status)) + result = TIME_ERROR; + + txc->freq = shift_right((time_freq >> PPM_SCALE_INV_SHIFT) * + PPM_SCALE_INV, NTP_SCALE_SHIFT); + txc->maxerror = time_maxerror; + txc->esterror = time_esterror; +- txc->status = time_status; ++ txc->status = ntpdata->time_status; + txc->constant = time_constant; + txc->precision = 1; + txc->tolerance = MAXFREQ_SCALED / PPM_SCALE; +@@ -815,26 +810,26 @@ int __do_adjtimex(struct __kernel_timex *txc, const struct timespec64 *ts, + txc->tai = *time_tai; + + /* Fill PPS status fields */ +- pps_fill_timex(txc); ++ pps_fill_timex(ntpdata, txc); + + txc->time.tv_sec = ts->tv_sec; + txc->time.tv_usec = ts->tv_nsec; +- if (!(time_status & STA_NANO)) ++ if (!(ntpdata->time_status & STA_NANO)) + txc->time.tv_usec = ts->tv_nsec / NSEC_PER_USEC; + + /* Handle leapsec adjustments */ + if (unlikely(ts->tv_sec >= ntp_next_leap_sec)) { +- if ((time_state == TIME_INS) && (time_status & STA_INS)) { ++ if ((ntpdata->time_state == TIME_INS) && (ntpdata->time_status & STA_INS)) { + result = TIME_OOP; + txc->tai++; + txc->time.tv_sec--; + } +- if ((time_state == TIME_DEL) && (time_status & STA_DEL)) { ++ if ((ntpdata->time_state == TIME_DEL) && (ntpdata->time_status & STA_DEL)) { + result = TIME_WAIT; + txc->tai--; + txc->time.tv_sec++; + } +- if ((time_state == TIME_OOP) && (ts->tv_sec == ntp_next_leap_sec)) ++ if ((ntpdata->time_state == TIME_OOP) && (ts->tv_sec == ntp_next_leap_sec)) + result = TIME_WAIT; + } + +@@ -939,7 +934,7 @@ static long hardpps_update_freq(struct ntp_data *ntpdata, struct pps_normtime fr + + /* Check if the frequency interval was too long */ + if (freq_norm.sec > (2 << pps_shift)) { +- time_status |= STA_PPSERROR; ++ ntpdata->time_status |= STA_PPSERROR; + pps_errcnt++; + pps_dec_freq_interval(); + printk_deferred(KERN_ERR "hardpps: PPSERROR: interval too long - %lld s\n", +@@ -958,7 +953,7 @@ static long hardpps_update_freq(struct ntp_data *ntpdata, struct pps_normtime fr + pps_freq = ftemp; + if (delta > PPS_MAXWANDER || delta < -PPS_MAXWANDER) { + printk_deferred(KERN_WARNING "hardpps: PPSWANDER: change=%ld\n", delta); +- time_status |= STA_PPSWANDER; ++ ntpdata->time_status |= STA_PPSWANDER; + pps_stbcnt++; + pps_dec_freq_interval(); + } else { +@@ -977,7 +972,7 @@ static long hardpps_update_freq(struct ntp_data *ntpdata, struct pps_normtime fr + NSEC_PER_USEC) - pps_stabil) >> PPS_INTMIN; + + /* If enabled, the system clock frequency is updated */ +- if ((time_status & STA_PPSFREQ) && !(time_status & STA_FREQHOLD)) { ++ if ((ntpdata->time_status & STA_PPSFREQ) && !(ntpdata->time_status & STA_FREQHOLD)) { + time_freq = pps_freq; + ntp_update_frequency(ntpdata); + } +@@ -986,7 +981,7 @@ static long hardpps_update_freq(struct ntp_data *ntpdata, struct pps_normtime fr + } + + /* Correct REALTIME clock phase error against PPS signal */ +-static void hardpps_update_phase(long error) ++static void hardpps_update_phase(struct ntp_data *ntpdata, long error) + { + long correction = -error; + long jitter; +@@ -1003,9 +998,9 @@ static void hardpps_update_phase(long error) + if (jitter > (pps_jitter << PPS_POPCORN)) { + printk_deferred(KERN_WARNING "hardpps: PPSJITTER: jitter=%ld, limit=%ld\n", + jitter, (pps_jitter << PPS_POPCORN)); +- time_status |= STA_PPSJITTER; ++ ntpdata->time_status |= STA_PPSJITTER; + pps_jitcnt++; +- } else if (time_status & STA_PPSTIME) { ++ } else if (ntpdata->time_status & STA_PPSTIME) { + /* Correct the time using the phase offset */ + time_offset = div_s64(((s64)correction) << NTP_SCALE_SHIFT, NTP_INTERVAL_FREQ); + /* Cancel running adjtime() */ +@@ -1035,10 +1030,10 @@ void __hardpps(const struct timespec64 *phase_ts, const struct timespec64 *raw_t + pts_norm = pps_normalize_ts(*phase_ts); + + /* Clear the error bits, they will be set again if needed */ +- time_status &= ~(STA_PPSJITTER | STA_PPSWANDER | STA_PPSERROR); ++ ntpdata->time_status &= ~(STA_PPSJITTER | STA_PPSWANDER | STA_PPSERROR); + +- /* Indicate signal presence */ +- time_status |= STA_PPSSIGNAL; ++ /* indicate signal presence */ ++ ntpdata->time_status |= STA_PPSSIGNAL; + pps_valid = PPS_VALID; + + /* +@@ -1059,7 +1054,7 @@ void __hardpps(const struct timespec64 *phase_ts, const struct timespec64 *raw_t + */ + if ((freq_norm.sec == 0) || (freq_norm.nsec > MAXFREQ * freq_norm.sec) || + (freq_norm.nsec < -MAXFREQ * freq_norm.sec)) { +- time_status |= STA_PPSJITTER; ++ ntpdata->time_status |= STA_PPSJITTER; + /* Restart the frequency calibration interval */ + pps_fbase = *raw_ts; + printk_deferred(KERN_ERR "hardpps: PPSJITTER: bad pulse\n"); +@@ -1074,7 +1069,7 @@ void __hardpps(const struct timespec64 *phase_ts, const struct timespec64 *raw_t + hardpps_update_freq(ntpdata, freq_norm); + } + +- hardpps_update_phase(pts_norm.nsec); ++ hardpps_update_phase(ntpdata, pts_norm.nsec); + + } + #endif /* CONFIG_NTP_PPS */ +-- +2.43.0 + diff --git a/queue-6.6/ntp-read-reference-time-only-once.patch b/queue-6.6/ntp-read-reference-time-only-once.patch new file mode 100644 index 00000000000..40c221440d5 --- /dev/null +++ b/queue-6.6/ntp-read-reference-time-only-once.patch @@ -0,0 +1,58 @@ +From 8e4573a49f37687504fff95d8733b62bdcf3afb0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Sep 2024 15:17:42 +0200 +Subject: ntp: Read reference time only once + +From: Thomas Gleixner + +[ Upstream commit 136bccbc2e78d3cd0bd8831e4c5a4509c0ddd945 ] + +The reference time is required twice in ntp_update_offset(). It will not +change in the meantime as the calling code holds the timekeeper lock. Read +it only once and store it into a local variable. + +Signed-off-by: Thomas Gleixner +Signed-off-by: Anna-Maria Behnsen +Signed-off-by: Thomas Gleixner +Acked-by: John Stultz +Link: https://lore.kernel.org/all/20240911-devel-anna-maria-b4-timers-ptp-ntp-v1-6-2d52f4e13476@linutronix.de +Stable-dep-of: f5807b0606da ("ntp: Remove invalid cast in time offset math") +Signed-off-by: Sasha Levin +--- + kernel/time/ntp.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c +index ef758aafdfd54..477cb08062bc5 100644 +--- a/kernel/time/ntp.c ++++ b/kernel/time/ntp.c +@@ -283,9 +283,8 @@ static inline s64 ntp_update_offset_fll(s64 offset64, long secs) + + static void ntp_update_offset(long offset) + { +- s64 freq_adj; +- s64 offset64; +- long secs; ++ s64 freq_adj, offset64; ++ long secs, real_secs; + + if (!(time_status & STA_PLL)) + return; +@@ -303,11 +302,12 @@ static void ntp_update_offset(long offset) + * Select how the frequency is to be controlled + * and in which mode (PLL or FLL). + */ +- secs = (long)(__ktime_get_real_seconds() - time_reftime); ++ real_secs = __ktime_get_real_seconds(); ++ secs = (long)(real_secs - time_reftime); + if (unlikely(time_status & STA_FREQHOLD)) + secs = 0; + +- time_reftime = __ktime_get_real_seconds(); ++ time_reftime = real_secs; + + offset64 = offset; + freq_adj = ntp_update_offset_fll(offset64, secs); +-- +2.43.0 + diff --git a/queue-6.6/ntp-remove-invalid-cast-in-time-offset-math.patch b/queue-6.6/ntp-remove-invalid-cast-in-time-offset-math.patch new file mode 100644 index 00000000000..b586571aee2 --- /dev/null +++ b/queue-6.6/ntp-remove-invalid-cast-in-time-offset-math.patch @@ -0,0 +1,52 @@ +From 48de567858d5dc7108ccecf728b033cf598093e5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Nov 2024 12:16:09 +0000 +Subject: ntp: Remove invalid cast in time offset math + +From: Marcelo Dalmas + +[ Upstream commit f5807b0606da7ac7c1b74a386b22134ec7702d05 ] + +Due to an unsigned cast, adjtimex() returns the wrong offest when using +ADJ_MICRO and the offset is negative. In this case a small negative offset +returns approximately 4.29 seconds (~ 2^32/1000 milliseconds) due to the +unsigned cast of the negative offset. + +This cast was added when the kernel internal struct timex was changed to +use type long long for the time offset value to address the problem of a +64bit/32bit division on 32bit systems. + +The correct cast would have been (s32), which is correct as time_offset can +only be in the range of [INT_MIN..INT_MAX] because the shift constant used +for calculating it is 32. But that's non-obvious. + +Remove the cast and use div_s64() to cure the issue. + +[ tglx: Fix white space damage, use div_s64() and amend the change log ] + +Fixes: ead25417f82e ("timex: use __kernel_timex internally") +Signed-off-by: Marcelo Dalmas +Signed-off-by: Thomas Gleixner +Cc: stable@vger.kernel.org +Link: https://lore.kernel.org/all/SJ0P101MB03687BF7D5A10FD3C49C51E5F42E2@SJ0P101MB0368.NAMP101.PROD.OUTLOOK.COM +Signed-off-by: Sasha Levin +--- + kernel/time/ntp.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c +index 6d87f9889b039..d1b7a3909de1d 100644 +--- a/kernel/time/ntp.c ++++ b/kernel/time/ntp.c +@@ -791,7 +791,7 @@ int __do_adjtimex(struct __kernel_timex *txc, const struct timespec64 *ts, + txc->offset = shift_right(time_offset * NTP_INTERVAL_FREQ, + NTP_SCALE_SHIFT); + if (!(ntpdata->time_status & STA_NANO)) +- txc->offset = (u32)txc->offset / NSEC_PER_USEC; ++ txc->offset = div_s64(txc->offset, NSEC_PER_USEC); + } + + result = ntpdata->time_state; +-- +2.43.0 + diff --git a/queue-6.6/ntp-remove-unused-tick_nsec.patch b/queue-6.6/ntp-remove-unused-tick_nsec.patch new file mode 100644 index 00000000000..80dab7e74b7 --- /dev/null +++ b/queue-6.6/ntp-remove-unused-tick_nsec.patch @@ -0,0 +1,87 @@ +From 06eb310a927bf861dd76379723b48d54b71b933a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Sep 2024 15:17:37 +0200 +Subject: ntp: Remove unused tick_nsec + +From: Thomas Gleixner + +[ Upstream commit a849a0273d0f73a252d14d31c5003a8059ea51fc ] + +tick_nsec is only updated in the NTP core, but there are no users. + +Remove it. + +Signed-off-by: Thomas Gleixner +Signed-off-by: Anna-Maria Behnsen +Signed-off-by: Thomas Gleixner +Acked-by: John Stultz +Link: https://lore.kernel.org/all/20240911-devel-anna-maria-b4-timers-ptp-ntp-v1-1-2d52f4e13476@linutronix.de +Stable-dep-of: f5807b0606da ("ntp: Remove invalid cast in time offset math") +Signed-off-by: Sasha Levin +--- + arch/x86/include/asm/timer.h | 2 -- + include/linux/timex.h | 1 - + kernel/time/ntp.c | 8 ++------ + 3 files changed, 2 insertions(+), 9 deletions(-) + +diff --git a/arch/x86/include/asm/timer.h b/arch/x86/include/asm/timer.h +index 7365dd4acffb6..23baf8c9b34ca 100644 +--- a/arch/x86/include/asm/timer.h ++++ b/arch/x86/include/asm/timer.h +@@ -6,8 +6,6 @@ + #include + #include + +-#define TICK_SIZE (tick_nsec / 1000) +- + unsigned long long native_sched_clock(void); + extern void recalibrate_cpu_khz(void); + +diff --git a/include/linux/timex.h b/include/linux/timex.h +index 3871b06bd302c..7f7a12fd8200c 100644 +--- a/include/linux/timex.h ++++ b/include/linux/timex.h +@@ -145,7 +145,6 @@ unsigned long random_get_entropy_fallback(void); + * estimated error = NTP dispersion. + */ + extern unsigned long tick_usec; /* USER_HZ period (usec) */ +-extern unsigned long tick_nsec; /* SHIFTED_HZ period (nsec) */ + + /* Required to safely shift negative values */ + #define shift_right(x, s) ({ \ +diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c +index 8d2dd214ec682..0dba1179d81d2 100644 +--- a/kernel/time/ntp.c ++++ b/kernel/time/ntp.c +@@ -33,9 +33,6 @@ + /* USER_HZ period (usecs): */ + unsigned long tick_usec = USER_TICK_USEC; + +-/* SHIFTED_HZ period (nsecs): */ +-unsigned long tick_nsec; +- + static u64 tick_length; + static u64 tick_length_base; + +@@ -253,8 +250,8 @@ static inline int ntp_synced(void) + */ + + /* +- * Update (tick_length, tick_length_base, tick_nsec), based +- * on (tick_usec, ntp_tick_adj, time_freq): ++ * Update tick_length and tick_length_base, based on tick_usec, ntp_tick_adj and ++ * time_freq: + */ + static void ntp_update_frequency(void) + { +@@ -267,7 +264,6 @@ static void ntp_update_frequency(void) + second_length += ntp_tick_adj; + second_length += time_freq; + +- tick_nsec = div_u64(second_length, HZ) >> NTP_SCALE_SHIFT; + new_base = div_u64(second_length, NTP_INTERVAL_FREQ); + + /* +-- +2.43.0 + diff --git a/queue-6.6/platform-x86-asus-wmi-add-support-for-vivobook-fan-p.patch b/queue-6.6/platform-x86-asus-wmi-add-support-for-vivobook-fan-p.patch new file mode 100644 index 00000000000..b9f8212b19d --- /dev/null +++ b/queue-6.6/platform-x86-asus-wmi-add-support-for-vivobook-fan-p.patch @@ -0,0 +1,305 @@ +From da670681422bd6f814f0ce671be9add30979c2dd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 9 Jun 2024 15:48:49 +0100 +Subject: platform/x86: asus-wmi: add support for vivobook fan profiles + +From: Mohamed Ghanmi + +[ Upstream commit bcbfcebda2cbc6a10a347d726e4a4f69e43a864e ] + +Add support for vivobook fan profiles wmi call on the ASUS VIVOBOOK +to adjust power limits. + +These fan profiles have a different device id than the ROG series +and different order. This reorders the existing modes. + +As part of keeping the patch clean the throttle_thermal_policy_available +boolean stored in the driver struct is removed and +throttle_thermal_policy_dev is used in place (as on init it is zeroed). + +Co-developed-by: Luke D. Jones +Signed-off-by: Luke D. Jones +Signed-off-by: Mohamed Ghanmi +Reviewed-by: Luke D. Jones +Link: https://lore.kernel.org/r/20240609144849.2532-2-mohamed.ghanmi@supcom.tn +Reviewed-by: Hans de Goede +Signed-off-by: Hans de Goede +Stable-dep-of: 25fb5f47f34d ("platform/x86: asus-wmi: Ignore return value when writing thermal policy") +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/asus-wmi.c | 120 ++++++++++++--------- + include/linux/platform_data/x86/asus-wmi.h | 1 + + 2 files changed, 71 insertions(+), 50 deletions(-) + +diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c +index 9c6321c2fc3c5..d0ba8bd83fc3d 100644 +--- a/drivers/platform/x86/asus-wmi.c ++++ b/drivers/platform/x86/asus-wmi.c +@@ -95,6 +95,12 @@ module_param(fnlock_default, bool, 0444); + #define ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST 1 + #define ASUS_THROTTLE_THERMAL_POLICY_SILENT 2 + ++#define ASUS_THROTTLE_THERMAL_POLICY_DEFAULT_VIVO 0 ++#define ASUS_THROTTLE_THERMAL_POLICY_SILENT_VIVO 1 ++#define ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST_VIVO 2 ++ ++#define PLATFORM_PROFILE_MAX 2 ++ + #define USB_INTEL_XUSB2PR 0xD0 + #define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31 + +@@ -269,8 +275,8 @@ struct asus_wmi { + bool kbd_rgb_mode_available; + bool kbd_rgb_state_available; + +- bool throttle_thermal_policy_available; + u8 throttle_thermal_policy_mode; ++ u32 throttle_thermal_policy_dev; + + bool cpu_fan_curve_available; + bool gpu_fan_curve_available; +@@ -2912,7 +2918,7 @@ static int fan_curve_get_factory_default(struct asus_wmi *asus, u32 fan_dev) + int err, fan_idx; + u8 mode = 0; + +- if (asus->throttle_thermal_policy_available) ++ if (asus->throttle_thermal_policy_dev) + mode = asus->throttle_thermal_policy_mode; + /* DEVID_PU_FAN_CURVE is switched for OVERBOOST vs SILENT */ + if (mode == 2) +@@ -3119,7 +3125,7 @@ static ssize_t fan_curve_enable_store(struct device *dev, + * For machines with throttle this is the only way to reset fans + * to default mode of operation (does not erase curve data). + */ +- if (asus->throttle_thermal_policy_available) { ++ if (asus->throttle_thermal_policy_dev) { + err = throttle_thermal_policy_write(asus); + if (err) + return err; +@@ -3336,8 +3342,8 @@ static const struct attribute_group asus_fan_curve_attr_group = { + __ATTRIBUTE_GROUPS(asus_fan_curve_attr); + + /* +- * Must be initialised after throttle_thermal_policy_check_present() as +- * we check the status of throttle_thermal_policy_available during init. ++ * Must be initialised after throttle_thermal_policy_dev is set as ++ * we check the status of throttle_thermal_policy_dev during init. + */ + static int asus_wmi_custom_fan_curve_init(struct asus_wmi *asus) + { +@@ -3378,38 +3384,13 @@ static int asus_wmi_custom_fan_curve_init(struct asus_wmi *asus) + } + + /* Throttle thermal policy ****************************************************/ +- +-static int throttle_thermal_policy_check_present(struct asus_wmi *asus) +-{ +- u32 result; +- int err; +- +- asus->throttle_thermal_policy_available = false; +- +- err = asus_wmi_get_devstate(asus, +- ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY, +- &result); +- if (err) { +- if (err == -ENODEV) +- return 0; +- return err; +- } +- +- if (result & ASUS_WMI_DSTS_PRESENCE_BIT) +- asus->throttle_thermal_policy_available = true; +- +- return 0; +-} +- + static int throttle_thermal_policy_write(struct asus_wmi *asus) + { +- int err; +- u8 value; ++ u8 value = asus->throttle_thermal_policy_mode; + u32 retval; ++ int err; + +- value = asus->throttle_thermal_policy_mode; +- +- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY, ++ err = asus_wmi_set_devstate(asus->throttle_thermal_policy_dev, + value, &retval); + + sysfs_notify(&asus->platform_device->dev.kobj, NULL, +@@ -3439,7 +3420,7 @@ static int throttle_thermal_policy_write(struct asus_wmi *asus) + + static int throttle_thermal_policy_set_default(struct asus_wmi *asus) + { +- if (!asus->throttle_thermal_policy_available) ++ if (!asus->throttle_thermal_policy_dev) + return 0; + + asus->throttle_thermal_policy_mode = ASUS_THROTTLE_THERMAL_POLICY_DEFAULT; +@@ -3451,7 +3432,7 @@ static int throttle_thermal_policy_switch_next(struct asus_wmi *asus) + u8 new_mode = asus->throttle_thermal_policy_mode + 1; + int err; + +- if (new_mode > ASUS_THROTTLE_THERMAL_POLICY_SILENT) ++ if (new_mode > PLATFORM_PROFILE_MAX) + new_mode = ASUS_THROTTLE_THERMAL_POLICY_DEFAULT; + + asus->throttle_thermal_policy_mode = new_mode; +@@ -3490,7 +3471,7 @@ static ssize_t throttle_thermal_policy_store(struct device *dev, + if (result < 0) + return result; + +- if (new_mode > ASUS_THROTTLE_THERMAL_POLICY_SILENT) ++ if (new_mode > PLATFORM_PROFILE_MAX) + return -EINVAL; + + asus->throttle_thermal_policy_mode = new_mode; +@@ -3507,10 +3488,52 @@ static ssize_t throttle_thermal_policy_store(struct device *dev, + return count; + } + +-// Throttle thermal policy: 0 - default, 1 - overboost, 2 - silent ++/* ++ * Throttle thermal policy: 0 - default, 1 - overboost, 2 - silent ++ */ + static DEVICE_ATTR_RW(throttle_thermal_policy); + + /* Platform profile ***********************************************************/ ++static int asus_wmi_platform_profile_to_vivo(struct asus_wmi *asus, int mode) ++{ ++ bool vivo; ++ ++ vivo = asus->throttle_thermal_policy_dev == ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO; ++ ++ if (vivo) { ++ switch (mode) { ++ case ASUS_THROTTLE_THERMAL_POLICY_DEFAULT: ++ return ASUS_THROTTLE_THERMAL_POLICY_DEFAULT_VIVO; ++ case ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST: ++ return ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST_VIVO; ++ case ASUS_THROTTLE_THERMAL_POLICY_SILENT: ++ return ASUS_THROTTLE_THERMAL_POLICY_SILENT_VIVO; ++ } ++ } ++ ++ return mode; ++} ++ ++static int asus_wmi_platform_profile_mode_from_vivo(struct asus_wmi *asus, int mode) ++{ ++ bool vivo; ++ ++ vivo = asus->throttle_thermal_policy_dev == ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO; ++ ++ if (vivo) { ++ switch (mode) { ++ case ASUS_THROTTLE_THERMAL_POLICY_DEFAULT_VIVO: ++ return ASUS_THROTTLE_THERMAL_POLICY_DEFAULT; ++ case ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST_VIVO: ++ return ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST; ++ case ASUS_THROTTLE_THERMAL_POLICY_SILENT_VIVO: ++ return ASUS_THROTTLE_THERMAL_POLICY_SILENT; ++ } ++ } ++ ++ return mode; ++} ++ + static int asus_wmi_platform_profile_get(struct platform_profile_handler *pprof, + enum platform_profile_option *profile) + { +@@ -3518,10 +3541,9 @@ static int asus_wmi_platform_profile_get(struct platform_profile_handler *pprof, + int tp; + + asus = container_of(pprof, struct asus_wmi, platform_profile_handler); +- + tp = asus->throttle_thermal_policy_mode; + +- switch (tp) { ++ switch (asus_wmi_platform_profile_mode_from_vivo(asus, tp)) { + case ASUS_THROTTLE_THERMAL_POLICY_DEFAULT: + *profile = PLATFORM_PROFILE_BALANCED; + break; +@@ -3560,7 +3582,7 @@ static int asus_wmi_platform_profile_set(struct platform_profile_handler *pprof, + return -EOPNOTSUPP; + } + +- asus->throttle_thermal_policy_mode = tp; ++ asus->throttle_thermal_policy_mode = asus_wmi_platform_profile_to_vivo(asus, tp); + return throttle_thermal_policy_write(asus); + } + +@@ -3573,7 +3595,7 @@ static int platform_profile_setup(struct asus_wmi *asus) + * Not an error if a component platform_profile relies on is unavailable + * so early return, skipping the setup of platform_profile. + */ +- if (!asus->throttle_thermal_policy_available) ++ if (!asus->throttle_thermal_policy_dev) + return 0; + + dev_info(dev, "Using throttle_thermal_policy for platform_profile support\n"); +@@ -3870,7 +3892,7 @@ static void asus_wmi_handle_event_code(int code, struct asus_wmi *asus) + if (code == NOTIFY_KBD_FBM || code == NOTIFY_KBD_TTP) { + if (asus->fan_boost_mode_available) + fan_boost_mode_switch_next(asus); +- if (asus->throttle_thermal_policy_available) ++ if (asus->throttle_thermal_policy_dev) + throttle_thermal_policy_switch_next(asus); + return; + +@@ -4075,7 +4097,7 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj, + else if (attr == &dev_attr_fan_boost_mode.attr) + ok = asus->fan_boost_mode_available; + else if (attr == &dev_attr_throttle_thermal_policy.attr) +- ok = asus->throttle_thermal_policy_available; ++ ok = asus->throttle_thermal_policy_dev != 0; + else if (attr == &dev_attr_ppt_pl2_sppt.attr) + ok = asus->ppt_pl2_sppt_available; + else if (attr == &dev_attr_ppt_pl1_spl.attr) +@@ -4365,16 +4387,15 @@ static int asus_wmi_add(struct platform_device *pdev) + asus->panel_overdrive_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PANEL_OD); + asus->mini_led_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MINI_LED_MODE); + ++ if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY)) ++ asus->throttle_thermal_policy_dev = ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY; ++ else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO)) ++ asus->throttle_thermal_policy_dev = ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO; ++ + err = fan_boost_mode_check_present(asus); + if (err) + goto fail_fan_boost_mode; + +- err = throttle_thermal_policy_check_present(asus); +- if (err) +- goto fail_throttle_thermal_policy; +- else +- throttle_thermal_policy_set_default(asus); +- + err = platform_profile_setup(asus); + if (err) + goto fail_platform_profile_setup; +@@ -4461,7 +4482,6 @@ static int asus_wmi_add(struct platform_device *pdev) + fail_input: + asus_wmi_sysfs_exit(asus->platform_device); + fail_sysfs: +-fail_throttle_thermal_policy: + fail_custom_fan_curve: + fail_platform_profile_setup: + if (asus->platform_profile_support) +diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h +index 16e99a1c37fc4..8e48bdeb55493 100644 +--- a/include/linux/platform_data/x86/asus-wmi.h ++++ b/include/linux/platform_data/x86/asus-wmi.h +@@ -60,6 +60,7 @@ + #define ASUS_WMI_DEVID_LIGHTBAR 0x00050025 + #define ASUS_WMI_DEVID_FAN_BOOST_MODE 0x00110018 + #define ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY 0x00120075 ++#define ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO 0x00110019 + + /* Misc */ + #define ASUS_WMI_DEVID_PANEL_OD 0x00050019 +-- +2.43.0 + diff --git a/queue-6.6/platform-x86-asus-wmi-fix-inconsistent-use-of-therma.patch b/queue-6.6/platform-x86-asus-wmi-fix-inconsistent-use-of-therma.patch new file mode 100644 index 00000000000..3a876257012 --- /dev/null +++ b/queue-6.6/platform-x86-asus-wmi-fix-inconsistent-use-of-therma.patch @@ -0,0 +1,139 @@ +From 08caab514c7f4b7fb20ffcf587b6497f7ee10b36 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 7 Nov 2024 01:38:10 +0100 +Subject: platform/x86: asus-wmi: Fix inconsistent use of thermal policies +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Armin Wolf + +[ Upstream commit 895085ec3f2ed7a26389943729e2904df1f88dc0 ] + +When changing the thermal policy using the platform profile API, +a Vivobook thermal policy is stored in throttle_thermal_policy_mode. + +However everywhere else a normal thermal policy is stored inside this +variable, potentially confusing the platform profile. + +Fix this by always storing normal thermal policy values inside +throttle_thermal_policy_mode and only do the conversion when writing +the thermal policy to hardware. This also fixes the order in which +throttle_thermal_policy_switch_next() steps through the thermal modes +on Vivobook machines. + +Tested-by: Casey G Bowman +Fixes: bcbfcebda2cb ("platform/x86: asus-wmi: add support for vivobook fan profiles") +Signed-off-by: Armin Wolf +Reviewed-by: Hans de Goede +Link: https://lore.kernel.org/r/20241107003811.615574-2-W_Armin@gmx.de +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Stable-dep-of: 25fb5f47f34d ("platform/x86: asus-wmi: Ignore return value when writing thermal policy") +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/asus-wmi.c | 64 +++++++++++---------------------- + 1 file changed, 21 insertions(+), 43 deletions(-) + +diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c +index d0ba8bd83fc3d..e36c299dcfb17 100644 +--- a/drivers/platform/x86/asus-wmi.c ++++ b/drivers/platform/x86/asus-wmi.c +@@ -3386,10 +3386,28 @@ static int asus_wmi_custom_fan_curve_init(struct asus_wmi *asus) + /* Throttle thermal policy ****************************************************/ + static int throttle_thermal_policy_write(struct asus_wmi *asus) + { +- u8 value = asus->throttle_thermal_policy_mode; + u32 retval; ++ u8 value; + int err; + ++ if (asus->throttle_thermal_policy_dev == ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO) { ++ switch (asus->throttle_thermal_policy_mode) { ++ case ASUS_THROTTLE_THERMAL_POLICY_DEFAULT: ++ value = ASUS_THROTTLE_THERMAL_POLICY_DEFAULT_VIVO; ++ break; ++ case ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST: ++ value = ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST_VIVO; ++ break; ++ case ASUS_THROTTLE_THERMAL_POLICY_SILENT: ++ value = ASUS_THROTTLE_THERMAL_POLICY_SILENT_VIVO; ++ break; ++ default: ++ return -EINVAL; ++ } ++ } else { ++ value = asus->throttle_thermal_policy_mode; ++ } ++ + err = asus_wmi_set_devstate(asus->throttle_thermal_policy_dev, + value, &retval); + +@@ -3494,46 +3512,6 @@ static ssize_t throttle_thermal_policy_store(struct device *dev, + static DEVICE_ATTR_RW(throttle_thermal_policy); + + /* Platform profile ***********************************************************/ +-static int asus_wmi_platform_profile_to_vivo(struct asus_wmi *asus, int mode) +-{ +- bool vivo; +- +- vivo = asus->throttle_thermal_policy_dev == ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO; +- +- if (vivo) { +- switch (mode) { +- case ASUS_THROTTLE_THERMAL_POLICY_DEFAULT: +- return ASUS_THROTTLE_THERMAL_POLICY_DEFAULT_VIVO; +- case ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST: +- return ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST_VIVO; +- case ASUS_THROTTLE_THERMAL_POLICY_SILENT: +- return ASUS_THROTTLE_THERMAL_POLICY_SILENT_VIVO; +- } +- } +- +- return mode; +-} +- +-static int asus_wmi_platform_profile_mode_from_vivo(struct asus_wmi *asus, int mode) +-{ +- bool vivo; +- +- vivo = asus->throttle_thermal_policy_dev == ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO; +- +- if (vivo) { +- switch (mode) { +- case ASUS_THROTTLE_THERMAL_POLICY_DEFAULT_VIVO: +- return ASUS_THROTTLE_THERMAL_POLICY_DEFAULT; +- case ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST_VIVO: +- return ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST; +- case ASUS_THROTTLE_THERMAL_POLICY_SILENT_VIVO: +- return ASUS_THROTTLE_THERMAL_POLICY_SILENT; +- } +- } +- +- return mode; +-} +- + static int asus_wmi_platform_profile_get(struct platform_profile_handler *pprof, + enum platform_profile_option *profile) + { +@@ -3543,7 +3521,7 @@ static int asus_wmi_platform_profile_get(struct platform_profile_handler *pprof, + asus = container_of(pprof, struct asus_wmi, platform_profile_handler); + tp = asus->throttle_thermal_policy_mode; + +- switch (asus_wmi_platform_profile_mode_from_vivo(asus, tp)) { ++ switch (tp) { + case ASUS_THROTTLE_THERMAL_POLICY_DEFAULT: + *profile = PLATFORM_PROFILE_BALANCED; + break; +@@ -3582,7 +3560,7 @@ static int asus_wmi_platform_profile_set(struct platform_profile_handler *pprof, + return -EOPNOTSUPP; + } + +- asus->throttle_thermal_policy_mode = asus_wmi_platform_profile_to_vivo(asus, tp); ++ asus->throttle_thermal_policy_mode = tp; + return throttle_thermal_policy_write(asus); + } + +-- +2.43.0 + diff --git a/queue-6.6/platform-x86-asus-wmi-ignore-return-value-when-writi.patch b/queue-6.6/platform-x86-asus-wmi-ignore-return-value-when-writi.patch new file mode 100644 index 00000000000..de520474854 --- /dev/null +++ b/queue-6.6/platform-x86-asus-wmi-ignore-return-value-when-writi.patch @@ -0,0 +1,71 @@ +From a0f791313f048d0d70e37282f90db23b9c523a09 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 24 Nov 2024 18:19:41 +0100 +Subject: platform/x86: asus-wmi: Ignore return value when writing thermal + policy +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Armin Wolf + +[ Upstream commit 25fb5f47f34d90aceda2c47a4230315536e97fa8 ] + +On some machines like the ASUS Vivobook S14 writing the thermal policy +returns the currently writen thermal policy instead of an error code. + +Ignore the return code to avoid falsely returning an error when the +thermal policy was written successfully. + +Reported-by: auslands-kv@gmx.de +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=219517 +Fixes: 2daa86e78c49 ("platform/x86: asus_wmi: Support throttle thermal policy") +Signed-off-by: Armin Wolf +Reviewed-by: Hans de Goede +Link: https://lore.kernel.org/r/20241124171941.29789-1-W_Armin@gmx.de +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/asus-wmi.c | 11 ++--------- + 1 file changed, 2 insertions(+), 9 deletions(-) + +diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c +index e36c299dcfb17..1bf6178a3a105 100644 +--- a/drivers/platform/x86/asus-wmi.c ++++ b/drivers/platform/x86/asus-wmi.c +@@ -3386,7 +3386,6 @@ static int asus_wmi_custom_fan_curve_init(struct asus_wmi *asus) + /* Throttle thermal policy ****************************************************/ + static int throttle_thermal_policy_write(struct asus_wmi *asus) + { +- u32 retval; + u8 value; + int err; + +@@ -3408,8 +3407,8 @@ static int throttle_thermal_policy_write(struct asus_wmi *asus) + value = asus->throttle_thermal_policy_mode; + } + +- err = asus_wmi_set_devstate(asus->throttle_thermal_policy_dev, +- value, &retval); ++ /* Some machines do not return an error code as a result, so we ignore it */ ++ err = asus_wmi_set_devstate(asus->throttle_thermal_policy_dev, value, NULL); + + sysfs_notify(&asus->platform_device->dev.kobj, NULL, + "throttle_thermal_policy"); +@@ -3419,12 +3418,6 @@ static int throttle_thermal_policy_write(struct asus_wmi *asus) + return err; + } + +- if (retval != 1) { +- pr_warn("Failed to set throttle thermal policy (retval): 0x%x\n", +- retval); +- return -EIO; +- } +- + /* Must set to disabled if mode is toggled */ + if (asus->cpu_fan_curve_available) + asus->custom_fan_curves[FAN_CURVE_DEV_CPU].enabled = false; +-- +2.43.0 + diff --git a/queue-6.6/powerpc-vdso-drop-mstack-protector-guard-flags-in-32.patch b/queue-6.6/powerpc-vdso-drop-mstack-protector-guard-flags-in-32.patch new file mode 100644 index 00000000000..3bec5b4aa02 --- /dev/null +++ b/queue-6.6/powerpc-vdso-drop-mstack-protector-guard-flags-in-32.patch @@ -0,0 +1,59 @@ +From 93646e2c580c33a9c5f77c0e5791d22c3b48ed8d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 30 Oct 2024 11:41:37 -0700 +Subject: powerpc/vdso: Drop -mstack-protector-guard flags in 32-bit files with + clang + +From: Nathan Chancellor + +[ Upstream commit d677ce521334d8f1f327cafc8b1b7854b0833158 ] + +Under certain conditions, the 64-bit '-mstack-protector-guard' flags may +end up in the 32-bit vDSO flags, resulting in build failures due to the +structure of clang's argument parsing of the stack protector options, +which validates the arguments of the stack protector guard flags +unconditionally in the frontend, choking on the 64-bit values when +targeting 32-bit: + + clang: error: invalid value 'r13' in 'mstack-protector-guard-reg=', expected one of: r2 + clang: error: invalid value 'r13' in 'mstack-protector-guard-reg=', expected one of: r2 + make[3]: *** [arch/powerpc/kernel/vdso/Makefile:85: arch/powerpc/kernel/vdso/vgettimeofday-32.o] Error 1 + make[3]: *** [arch/powerpc/kernel/vdso/Makefile:87: arch/powerpc/kernel/vdso/vgetrandom-32.o] Error 1 + +Remove these flags by adding them to the CC32FLAGSREMOVE variable, which +already handles situations similar to this. Additionally, reformat and +align a comment better for the expanding CONFIG_CC_IS_CLANG block. + +Cc: stable@vger.kernel.org # v6.1+ +Signed-off-by: Nathan Chancellor +Signed-off-by: Michael Ellerman +Link: https://patch.msgid.link/20241030-powerpc-vdso-drop-stackp-flags-clang-v1-1-d95e7376d29c@kernel.org +Signed-off-by: Sasha Levin +--- + arch/powerpc/kernel/vdso/Makefile | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/arch/powerpc/kernel/vdso/Makefile b/arch/powerpc/kernel/vdso/Makefile +index 5c7af93018865..d5defff8472da 100644 +--- a/arch/powerpc/kernel/vdso/Makefile ++++ b/arch/powerpc/kernel/vdso/Makefile +@@ -51,10 +51,14 @@ ldflags-y += $(filter-out $(CC_AUTO_VAR_INIT_ZERO_ENABLER) $(CC_FLAGS_FTRACE) -W + + CC32FLAGS := -m32 + CC32FLAGSREMOVE := -mcmodel=medium -mabi=elfv1 -mabi=elfv2 -mcall-aixdesc +- # This flag is supported by clang for 64-bit but not 32-bit so it will cause +- # an unused command line flag warning for this file. + ifdef CONFIG_CC_IS_CLANG ++# This flag is supported by clang for 64-bit but not 32-bit so it will cause ++# an unused command line flag warning for this file. + CC32FLAGSREMOVE += -fno-stack-clash-protection ++# -mstack-protector-guard values from the 64-bit build are not valid for the ++# 32-bit one. clang validates the values passed to these arguments during ++# parsing, even when -fno-stack-protector is passed afterwards. ++CC32FLAGSREMOVE += -mstack-protector-guard% + endif + LD32FLAGS := -Wl,-soname=linux-vdso32.so.1 + AS32FLAGS := -D__VDSO32__ +-- +2.43.0 + diff --git a/queue-6.6/powerpc-vdso-refactor-cflags-for-cvdso-build.patch b/queue-6.6/powerpc-vdso-refactor-cflags-for-cvdso-build.patch new file mode 100644 index 00000000000..81c08a2bf82 --- /dev/null +++ b/queue-6.6/powerpc-vdso-refactor-cflags-for-cvdso-build.patch @@ -0,0 +1,92 @@ +From 580f29b4880f364c6559caf60237a743ad33fa19 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Sep 2024 21:17:20 +0200 +Subject: powerpc/vdso: Refactor CFLAGS for CVDSO build + +From: Christophe Leroy + +[ Upstream commit a6b67eb09963af29991625862cbb4f56b85954ed ] + +In order to avoid two much duplication when we add new VDSO +functionnalities in C like getrandom, refactor common CFLAGS. + +Signed-off-by: Christophe Leroy +Acked-by: Michael Ellerman +Signed-off-by: Jason A. Donenfeld +Stable-dep-of: d677ce521334 ("powerpc/vdso: Drop -mstack-protector-guard flags in 32-bit files with clang") +Signed-off-by: Sasha Levin +--- + arch/powerpc/kernel/vdso/Makefile | 32 +++++++++++++------------------ + 1 file changed, 13 insertions(+), 19 deletions(-) + +diff --git a/arch/powerpc/kernel/vdso/Makefile b/arch/powerpc/kernel/vdso/Makefile +index 0c7d82c270c37..5c7af93018865 100644 +--- a/arch/powerpc/kernel/vdso/Makefile ++++ b/arch/powerpc/kernel/vdso/Makefile +@@ -10,28 +10,11 @@ obj-vdso64 = sigtramp64-64.o gettimeofday-64.o datapage-64.o cacheflush-64.o not + + ifneq ($(c-gettimeofday-y),) + CFLAGS_vgettimeofday-32.o += -include $(c-gettimeofday-y) +- CFLAGS_vgettimeofday-32.o += $(DISABLE_LATENT_ENTROPY_PLUGIN) +- CFLAGS_vgettimeofday-32.o += $(call cc-option, -fno-stack-protector) +- CFLAGS_vgettimeofday-32.o += -DDISABLE_BRANCH_PROFILING +- CFLAGS_vgettimeofday-32.o += -ffreestanding -fasynchronous-unwind-tables +- CFLAGS_REMOVE_vgettimeofday-32.o = $(CC_FLAGS_FTRACE) +- CFLAGS_REMOVE_vgettimeofday-32.o += -mcmodel=medium -mabi=elfv1 -mabi=elfv2 -mcall-aixdesc +- # This flag is supported by clang for 64-bit but not 32-bit so it will cause +- # an unused command line flag warning for this file. +- ifdef CONFIG_CC_IS_CLANG +- CFLAGS_REMOVE_vgettimeofday-32.o += -fno-stack-clash-protection +- endif +- CFLAGS_vgettimeofday-64.o += -include $(c-gettimeofday-y) +- CFLAGS_vgettimeofday-64.o += $(DISABLE_LATENT_ENTROPY_PLUGIN) +- CFLAGS_vgettimeofday-64.o += $(call cc-option, -fno-stack-protector) +- CFLAGS_vgettimeofday-64.o += -DDISABLE_BRANCH_PROFILING +- CFLAGS_vgettimeofday-64.o += -ffreestanding -fasynchronous-unwind-tables +- CFLAGS_REMOVE_vgettimeofday-64.o = $(CC_FLAGS_FTRACE) + # Go prior to 1.16.x assumes r30 is not clobbered by any VDSO code. That used to be true + # by accident when the VDSO was hand-written asm code, but may not be now that the VDSO is + # compiler generated. To avoid breaking Go tell GCC not to use r30. Impact on code + # generation is minimal, it will just use r29 instead. +- CFLAGS_vgettimeofday-64.o += $(call cc-option, -ffixed-r30) ++ CFLAGS_vgettimeofday-64.o += -include $(c-gettimeofday-y) $(call cc-option, -ffixed-r30) + endif + + # Build rules +@@ -54,6 +37,11 @@ KASAN_SANITIZE := n + KCSAN_SANITIZE := n + + ccflags-y := -fno-common -fno-builtin ++ccflags-y += $(DISABLE_LATENT_ENTROPY_PLUGIN) ++ccflags-y += $(call cc-option, -fno-stack-protector) ++ccflags-y += -DDISABLE_BRANCH_PROFILING ++ccflags-y += -ffreestanding -fasynchronous-unwind-tables ++ccflags-remove-y := $(CC_FLAGS_FTRACE) + ldflags-y := -Wl,--hash-style=both -nostdlib -shared -z noexecstack $(CLANG_FLAGS) + ldflags-$(CONFIG_LD_IS_LLD) += $(call cc-option,--ld-path=$(LD),-fuse-ld=lld) + ldflags-$(CONFIG_LD_ORPHAN_WARN) += -Wl,--orphan-handling=$(CONFIG_LD_ORPHAN_WARN_LEVEL) +@@ -62,6 +50,12 @@ ldflags-$(CONFIG_LD_ORPHAN_WARN) += -Wl,--orphan-handling=$(CONFIG_LD_ORPHAN_WAR + ldflags-y += $(filter-out $(CC_AUTO_VAR_INIT_ZERO_ENABLER) $(CC_FLAGS_FTRACE) -Wa$(comma)%, $(KBUILD_CFLAGS)) + + CC32FLAGS := -m32 ++CC32FLAGSREMOVE := -mcmodel=medium -mabi=elfv1 -mabi=elfv2 -mcall-aixdesc ++ # This flag is supported by clang for 64-bit but not 32-bit so it will cause ++ # an unused command line flag warning for this file. ++ifdef CONFIG_CC_IS_CLANG ++CC32FLAGSREMOVE += -fno-stack-clash-protection ++endif + LD32FLAGS := -Wl,-soname=linux-vdso32.so.1 + AS32FLAGS := -D__VDSO32__ + +@@ -108,7 +102,7 @@ quiet_cmd_vdso32ld_and_check = VDSO32L $@ + quiet_cmd_vdso32as = VDSO32A $@ + cmd_vdso32as = $(VDSOCC) $(a_flags) $(CC32FLAGS) $(AS32FLAGS) -c -o $@ $< + quiet_cmd_vdso32cc = VDSO32C $@ +- cmd_vdso32cc = $(VDSOCC) $(c_flags) $(CC32FLAGS) -c -o $@ $< ++ cmd_vdso32cc = $(VDSOCC) $(filter-out $(CC32FLAGSREMOVE), $(c_flags)) $(CC32FLAGS) -c -o $@ $< + + quiet_cmd_vdso64ld_and_check = VDSO64L $@ + cmd_vdso64ld_and_check = $(VDSOCC) $(ldflags-y) $(LD64FLAGS) -o $@ -Wl,-T$(filter %.lds,$^) $(filter %.o,$^); $(cmd_vdso_check) +-- +2.43.0 + diff --git a/queue-6.6/ptp-add-error-handling-for-adjfine-callback-in-ptp_c.patch b/queue-6.6/ptp-add-error-handling-for-adjfine-callback-in-ptp_c.patch new file mode 100644 index 00000000000..5ebb5237b76 --- /dev/null +++ b/queue-6.6/ptp-add-error-handling-for-adjfine-callback-in-ptp_c.patch @@ -0,0 +1,42 @@ +From b10746fc5c7428f78f631a4c8bdfc34ff4e40eb8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Nov 2024 10:59:54 +0000 +Subject: ptp: Add error handling for adjfine callback in ptp_clock_adjtime + +From: Ajay Kaher + +[ Upstream commit 98337d7c87577ded71114f6976edb70a163e27bc ] + +ptp_clock_adjtime sets ptp->dialed_frequency even when adjfine +callback returns an error. This causes subsequent reads to return +an incorrect value. + +Fix this by adding error check before ptp->dialed_frequency is set. + +Fixes: 39a8cbd9ca05 ("ptp: remember the adjusted frequency") +Signed-off-by: Ajay Kaher +Acked-by: Richard Cochran +Link: https://patch.msgid.link/20241125105954.1509971-1-ajay.kaher@broadcom.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/ptp/ptp_clock.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c +index 9a50bfb56453c..b586da2e30023 100644 +--- a/drivers/ptp/ptp_clock.c ++++ b/drivers/ptp/ptp_clock.c +@@ -133,7 +133,8 @@ static int ptp_clock_adjtime(struct posix_clock *pc, struct __kernel_timex *tx) + if (ppb > ops->max_adj || ppb < -ops->max_adj) + return -ERANGE; + err = ops->adjfine(ops, tx->freq); +- ptp->dialed_frequency = tx->freq; ++ if (!err) ++ ptp->dialed_frequency = tx->freq; + } else if (tx->modes & ADJ_OFFSET) { + if (ops->adjphase) { + s32 max_phase_adj = ops->getmaxphase(ops); +-- +2.43.0 + diff --git a/queue-6.6/selftests-hid-fix-typo-and-exit-code.patch b/queue-6.6/selftests-hid-fix-typo-and-exit-code.patch new file mode 100644 index 00000000000..e6e3c1e288c --- /dev/null +++ b/queue-6.6/selftests-hid-fix-typo-and-exit-code.patch @@ -0,0 +1,61 @@ +From b5f3836091cad9646a40956d6904090e7979b797 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 Nov 2024 13:58:50 +0000 +Subject: selftests: hid: fix typo and exit code + +From: Maximilian Heyne + +[ Upstream commit e8f34747bddedaf3895e5d5066e0f71713fff811 ] + +The correct exit code to mark a test as skipped is 4. + +Fixes: ffb85d5c9e80 ("selftests: hid: import hid-tools hid-core tests") +Signed-off-by: Maximilian Heyne +Link: https://patch.msgid.link/20241126135850.76493-1-mheyne@amazon.de +Signed-off-by: Benjamin Tissoires +Signed-off-by: Sasha Levin +--- + .../testing/selftests/hid/run-hid-tools-tests.sh | 16 +++++++++------- + 1 file changed, 9 insertions(+), 7 deletions(-) + +diff --git a/tools/testing/selftests/hid/run-hid-tools-tests.sh b/tools/testing/selftests/hid/run-hid-tools-tests.sh +index bdae8464da865..af1682a53c27e 100755 +--- a/tools/testing/selftests/hid/run-hid-tools-tests.sh ++++ b/tools/testing/selftests/hid/run-hid-tools-tests.sh +@@ -2,24 +2,26 @@ + # SPDX-License-Identifier: GPL-2.0 + # Runs tests for the HID subsystem + ++KSELFTEST_SKIP_TEST=4 ++ + if ! command -v python3 > /dev/null 2>&1; then + echo "hid-tools: [SKIP] python3 not installed" +- exit 77 ++ exit $KSELFTEST_SKIP_TEST + fi + + if ! python3 -c "import pytest" > /dev/null 2>&1; then +- echo "hid: [SKIP/ pytest module not installed" +- exit 77 ++ echo "hid: [SKIP] pytest module not installed" ++ exit $KSELFTEST_SKIP_TEST + fi + + if ! python3 -c "import pytest_tap" > /dev/null 2>&1; then +- echo "hid: [SKIP/ pytest_tap module not installed" +- exit 77 ++ echo "hid: [SKIP] pytest_tap module not installed" ++ exit $KSELFTEST_SKIP_TEST + fi + + if ! python3 -c "import hidtools" > /dev/null 2>&1; then +- echo "hid: [SKIP/ hid-tools module not installed" +- exit 77 ++ echo "hid: [SKIP] hid-tools module not installed" ++ exit $KSELFTEST_SKIP_TEST + fi + + TARGET=${TARGET:=.} +-- +2.43.0 + diff --git a/queue-6.6/serial-amba-pl011-fix-rx-stall-when-dma-is-used.patch b/queue-6.6/serial-amba-pl011-fix-rx-stall-when-dma-is-used.patch new file mode 100644 index 00000000000..5117b0ea50f --- /dev/null +++ b/queue-6.6/serial-amba-pl011-fix-rx-stall-when-dma-is-used.patch @@ -0,0 +1,49 @@ +From 0479945f2554582f2418bd6efc486d28d831981a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 Nov 2024 14:56:29 +0530 +Subject: serial: amba-pl011: Fix RX stall when DMA is used + +From: Kartik Rajput + +[ Upstream commit 2bcacc1c87acf9a8ebc17de18cb2b3cfeca547cf ] + +Function pl011_throttle_rx() calls pl011_stop_rx() to disable RX, which +also disables the RX DMA by clearing the RXDMAE bit of the DMACR +register. However, to properly unthrottle RX when DMA is used, the +function pl011_unthrottle_rx() is expected to set the RXDMAE bit of +the DMACR register, which it currently lacks. This causes RX to stall +after the throttle API is called. + +Set RXDMAE bit in the DMACR register while unthrottling RX if RX DMA is +used. + +Fixes: 211565b10099 ("serial: pl011: UPSTAT_AUTORTS requires .throttle/unthrottle") +Cc: stable@vger.kernel.org +Signed-off-by: Kartik Rajput +Reviewed-by: Linus Walleij +Link: https://lore.kernel.org/r/20241113092629.60226-1-kkartik@nvidia.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/amba-pl011.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c +index 16c7703110694..08f80188f73dd 100644 +--- a/drivers/tty/serial/amba-pl011.c ++++ b/drivers/tty/serial/amba-pl011.c +@@ -1837,6 +1837,11 @@ static void pl011_unthrottle_rx(struct uart_port *port) + + pl011_write(uap->im, uap, REG_IMSC); + ++ if (uap->using_rx_dma) { ++ uap->dmacr |= UART011_RXDMAE; ++ pl011_write(uap->dmacr, uap, REG_DMACR); ++ } ++ + uart_port_unlock_irqrestore(&uap->port, flags); + } + +-- +2.43.0 + diff --git a/queue-6.6/serial-amba-pl011-use-port-lock-wrappers.patch b/queue-6.6/serial-amba-pl011-use-port-lock-wrappers.patch new file mode 100644 index 00000000000..546f3624159 --- /dev/null +++ b/queue-6.6/serial-amba-pl011-use-port-lock-wrappers.patch @@ -0,0 +1,337 @@ +From 329f90d25af129dbcf4fdfbc3c5a7ed85f76764b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 14 Sep 2023 20:43:34 +0206 +Subject: serial: amba-pl011: Use port lock wrappers + +From: Thomas Gleixner + +[ Upstream commit 68ca3e72d7463d79d29b6e4961d6028df2a88e25 ] + +When a serial port is used for kernel console output, then all +modifications to the UART registers which are done from other contexts, +e.g. getty, termios, are interference points for the kernel console. + +So far this has been ignored and the printk output is based on the +principle of hope. The rework of the console infrastructure which aims to +support threaded and atomic consoles, requires to mark sections which +modify the UART registers as unsafe. This allows the atomic write function +to make informed decisions and eventually to restore operational state. It +also allows to prevent the regular UART code from modifying UART registers +while printk output is in progress. + +All modifications of UART registers are guarded by the UART port lock, +which provides an obvious synchronization point with the console +infrastructure. + +To avoid adding this functionality to all UART drivers, wrap the +spin_[un]lock*() invocations for uart_port::lock into helper functions +which just contain the spin_[un]lock*() invocations for now. In a +subsequent step these helpers will gain the console synchronization +mechanisms. + +Converted with coccinelle. No functional change. + +Signed-off-by: Thomas Gleixner +Signed-off-by: John Ogness +Link: https://lore.kernel.org/r/20230914183831.587273-18-john.ogness@linutronix.de +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: 2bcacc1c87ac ("serial: amba-pl011: Fix RX stall when DMA is used") +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/amba-pl011.c | 72 ++++++++++++++++----------------- + 1 file changed, 36 insertions(+), 36 deletions(-) + +diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c +index 362bbcdece0d7..16c7703110694 100644 +--- a/drivers/tty/serial/amba-pl011.c ++++ b/drivers/tty/serial/amba-pl011.c +@@ -347,9 +347,9 @@ static int pl011_fifo_to_tty(struct uart_amba_port *uap) + flag = TTY_FRAME; + } + +- spin_unlock(&uap->port.lock); ++ uart_port_unlock(&uap->port); + sysrq = uart_handle_sysrq_char(&uap->port, ch & 255); +- spin_lock(&uap->port.lock); ++ uart_port_lock(&uap->port); + + if (!sysrq) + uart_insert_char(&uap->port, ch, UART011_DR_OE, ch, flag); +@@ -544,7 +544,7 @@ static void pl011_dma_tx_callback(void *data) + unsigned long flags; + u16 dmacr; + +- spin_lock_irqsave(&uap->port.lock, flags); ++ uart_port_lock_irqsave(&uap->port, &flags); + if (uap->dmatx.queued) + dma_unmap_single(dmatx->chan->device->dev, dmatx->dma, + dmatx->len, DMA_TO_DEVICE); +@@ -565,7 +565,7 @@ static void pl011_dma_tx_callback(void *data) + if (!(dmacr & UART011_TXDMAE) || uart_tx_stopped(&uap->port) || + uart_circ_empty(&uap->port.state->xmit)) { + uap->dmatx.queued = false; +- spin_unlock_irqrestore(&uap->port.lock, flags); ++ uart_port_unlock_irqrestore(&uap->port, flags); + return; + } + +@@ -576,7 +576,7 @@ static void pl011_dma_tx_callback(void *data) + */ + pl011_start_tx_pio(uap); + +- spin_unlock_irqrestore(&uap->port.lock, flags); ++ uart_port_unlock_irqrestore(&uap->port, flags); + } + + /* +@@ -1004,7 +1004,7 @@ static void pl011_dma_rx_callback(void *data) + * routine to flush out the secondary DMA buffer while + * we immediately trigger the next DMA job. + */ +- spin_lock_irq(&uap->port.lock); ++ uart_port_lock_irq(&uap->port); + /* + * Rx data can be taken by the UART interrupts during + * the DMA irq handler. So we check the residue here. +@@ -1020,7 +1020,7 @@ static void pl011_dma_rx_callback(void *data) + ret = pl011_dma_rx_trigger_dma(uap); + + pl011_dma_rx_chars(uap, pending, lastbuf, false); +- spin_unlock_irq(&uap->port.lock); ++ uart_port_unlock_irq(&uap->port); + /* + * Do this check after we picked the DMA chars so we don't + * get some IRQ immediately from RX. +@@ -1086,11 +1086,11 @@ static void pl011_dma_rx_poll(struct timer_list *t) + if (jiffies_to_msecs(jiffies - dmarx->last_jiffies) + > uap->dmarx.poll_timeout) { + +- spin_lock_irqsave(&uap->port.lock, flags); ++ uart_port_lock_irqsave(&uap->port, &flags); + pl011_dma_rx_stop(uap); + uap->im |= UART011_RXIM; + pl011_write(uap->im, uap, REG_IMSC); +- spin_unlock_irqrestore(&uap->port.lock, flags); ++ uart_port_unlock_irqrestore(&uap->port, flags); + + uap->dmarx.running = false; + dmaengine_terminate_all(rxchan); +@@ -1186,10 +1186,10 @@ static void pl011_dma_shutdown(struct uart_amba_port *uap) + while (pl011_read(uap, REG_FR) & uap->vendor->fr_busy) + cpu_relax(); + +- spin_lock_irq(&uap->port.lock); ++ uart_port_lock_irq(&uap->port); + uap->dmacr &= ~(UART011_DMAONERR | UART011_RXDMAE | UART011_TXDMAE); + pl011_write(uap->dmacr, uap, REG_DMACR); +- spin_unlock_irq(&uap->port.lock); ++ uart_port_unlock_irq(&uap->port); + + if (uap->using_tx_dma) { + /* In theory, this should already be done by pl011_dma_flush_buffer */ +@@ -1400,9 +1400,9 @@ static void pl011_throttle_rx(struct uart_port *port) + { + unsigned long flags; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + pl011_stop_rx(port); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static void pl011_enable_ms(struct uart_port *port) +@@ -1420,7 +1420,7 @@ __acquires(&uap->port.lock) + { + pl011_fifo_to_tty(uap); + +- spin_unlock(&uap->port.lock); ++ uart_port_unlock(&uap->port); + tty_flip_buffer_push(&uap->port.state->port); + /* + * If we were temporarily out of DMA mode for a while, +@@ -1445,7 +1445,7 @@ __acquires(&uap->port.lock) + #endif + } + } +- spin_lock(&uap->port.lock); ++ uart_port_lock(&uap->port); + } + + static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c, +@@ -1551,7 +1551,7 @@ static irqreturn_t pl011_int(int irq, void *dev_id) + unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT; + int handled = 0; + +- spin_lock_irqsave(&uap->port.lock, flags); ++ uart_port_lock_irqsave(&uap->port, &flags); + status = pl011_read(uap, REG_RIS) & uap->im; + if (status) { + do { +@@ -1581,7 +1581,7 @@ static irqreturn_t pl011_int(int irq, void *dev_id) + handled = 1; + } + +- spin_unlock_irqrestore(&uap->port.lock, flags); ++ uart_port_unlock_irqrestore(&uap->port, flags); + + return IRQ_RETVAL(handled); + } +@@ -1653,14 +1653,14 @@ static void pl011_break_ctl(struct uart_port *port, int break_state) + unsigned long flags; + unsigned int lcr_h; + +- spin_lock_irqsave(&uap->port.lock, flags); ++ uart_port_lock_irqsave(&uap->port, &flags); + lcr_h = pl011_read(uap, REG_LCRH_TX); + if (break_state == -1) + lcr_h |= UART01x_LCRH_BRK; + else + lcr_h &= ~UART01x_LCRH_BRK; + pl011_write(lcr_h, uap, REG_LCRH_TX); +- spin_unlock_irqrestore(&uap->port.lock, flags); ++ uart_port_unlock_irqrestore(&uap->port, flags); + } + + #ifdef CONFIG_CONSOLE_POLL +@@ -1799,7 +1799,7 @@ static void pl011_enable_interrupts(struct uart_amba_port *uap) + unsigned long flags; + unsigned int i; + +- spin_lock_irqsave(&uap->port.lock, flags); ++ uart_port_lock_irqsave(&uap->port, &flags); + + /* Clear out any spuriously appearing RX interrupts */ + pl011_write(UART011_RTIS | UART011_RXIS, uap, REG_ICR); +@@ -1821,7 +1821,7 @@ static void pl011_enable_interrupts(struct uart_amba_port *uap) + if (!pl011_dma_rx_running(uap)) + uap->im |= UART011_RXIM; + pl011_write(uap->im, uap, REG_IMSC); +- spin_unlock_irqrestore(&uap->port.lock, flags); ++ uart_port_unlock_irqrestore(&uap->port, flags); + } + + static void pl011_unthrottle_rx(struct uart_port *port) +@@ -1829,7 +1829,7 @@ static void pl011_unthrottle_rx(struct uart_port *port) + struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); + unsigned long flags; + +- spin_lock_irqsave(&uap->port.lock, flags); ++ uart_port_lock_irqsave(&uap->port, &flags); + + uap->im = UART011_RTIM; + if (!pl011_dma_rx_running(uap)) +@@ -1837,7 +1837,7 @@ static void pl011_unthrottle_rx(struct uart_port *port) + + pl011_write(uap->im, uap, REG_IMSC); + +- spin_unlock_irqrestore(&uap->port.lock, flags); ++ uart_port_unlock_irqrestore(&uap->port, flags); + } + + static int pl011_startup(struct uart_port *port) +@@ -1857,7 +1857,7 @@ static int pl011_startup(struct uart_port *port) + + pl011_write(uap->vendor->ifls, uap, REG_IFLS); + +- spin_lock_irq(&uap->port.lock); ++ uart_port_lock_irq(&uap->port); + + cr = pl011_read(uap, REG_CR); + cr &= UART011_CR_RTS | UART011_CR_DTR; +@@ -1868,7 +1868,7 @@ static int pl011_startup(struct uart_port *port) + + pl011_write(cr, uap, REG_CR); + +- spin_unlock_irq(&uap->port.lock); ++ uart_port_unlock_irq(&uap->port); + + /* + * initialise the old status of the modem signals +@@ -1929,12 +1929,12 @@ static void pl011_disable_uart(struct uart_amba_port *uap) + unsigned int cr; + + uap->port.status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS); +- spin_lock_irq(&uap->port.lock); ++ uart_port_lock_irq(&uap->port); + cr = pl011_read(uap, REG_CR); + cr &= UART011_CR_RTS | UART011_CR_DTR; + cr |= UART01x_CR_UARTEN | UART011_CR_TXE; + pl011_write(cr, uap, REG_CR); +- spin_unlock_irq(&uap->port.lock); ++ uart_port_unlock_irq(&uap->port); + + /* + * disable break condition and fifos +@@ -1946,14 +1946,14 @@ static void pl011_disable_uart(struct uart_amba_port *uap) + + static void pl011_disable_interrupts(struct uart_amba_port *uap) + { +- spin_lock_irq(&uap->port.lock); ++ uart_port_lock_irq(&uap->port); + + /* mask all interrupts and clear all pending ones */ + uap->im = 0; + pl011_write(uap->im, uap, REG_IMSC); + pl011_write(0xffff, uap, REG_ICR); + +- spin_unlock_irq(&uap->port.lock); ++ uart_port_unlock_irq(&uap->port); + } + + static void pl011_shutdown(struct uart_port *port) +@@ -2098,7 +2098,7 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, + + bits = tty_get_frame_size(termios->c_cflag); + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + + /* + * Update the per-port timeout. +@@ -2172,7 +2172,7 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, + old_cr |= UART011_CR_RXE; + pl011_write(old_cr, uap, REG_CR); + +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static void +@@ -2190,10 +2190,10 @@ sbsa_uart_set_termios(struct uart_port *port, struct ktermios *termios, + termios->c_cflag &= ~(CMSPAR | CRTSCTS); + termios->c_cflag |= CS8 | CLOCAL; + +- spin_lock_irqsave(&port->lock, flags); ++ uart_port_lock_irqsave(port, &flags); + uart_update_timeout(port, CS8, uap->fixed_baud); + pl011_setup_status_masks(port, termios); +- spin_unlock_irqrestore(&port->lock, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static const char *pl011_type(struct uart_port *port) +@@ -2332,9 +2332,9 @@ pl011_console_write(struct console *co, const char *s, unsigned int count) + if (uap->port.sysrq) + locked = 0; + else if (oops_in_progress) +- locked = spin_trylock(&uap->port.lock); ++ locked = uart_port_trylock(&uap->port); + else +- spin_lock(&uap->port.lock); ++ uart_port_lock(&uap->port); + + /* + * First save the CR then disable the interrupts +@@ -2360,7 +2360,7 @@ pl011_console_write(struct console *co, const char *s, unsigned int count) + pl011_write(old_cr, uap, REG_CR); + + if (locked) +- spin_unlock(&uap->port.lock); ++ uart_port_unlock(&uap->port); + local_irq_restore(flags); + + clk_disable(uap->clk); +-- +2.43.0 + diff --git a/queue-6.6/series b/queue-6.6/series index e69de29bb2d..5faf393c059 100644 --- a/queue-6.6/series +++ b/queue-6.6/series @@ -0,0 +1,120 @@ +itco_wdt-mask-nmi_now-bit-for-update_no_reboot_bit-c.patch +watchdog-xilinx_wwdt-calculate-max_hw_heartbeat_ms-u.patch +watchdog-apple-actually-flush-writes-after-requestin.patch +watchdog-mediatek-make-sure-system-reset-gets-assert.patch +can-gs_usb-add-vid-pid-for-xylanta-saint3-product-fa.patch +can-gs_usb-add-usb-endpoint-address-detection-at-dri.patch +can-c_can-c_can_handle_bus_err-update-statistics-if-.patch +can-sun4i_can-sun4i_can_err-call-can_change_state-ev.patch +can-hi311x-hi3110_can_ist-fix-potential-use-after-fr.patch +can-m_can-m_can_handle_lec_err-fix-rx-tx-_errors-sta.patch +can-ifi_canfd-ifi_canfd_handle_lec_err-fix-rx-tx-_er.patch +can-hi311x-hi3110_can_ist-fix-rx-tx-_errors-statisti.patch +can-sja1000-sja1000_err-fix-rx-tx-_errors-statistics.patch +can-sun4i_can-sun4i_can_err-fix-rx-tx-_errors-statis.patch +can-ems_usb-ems_usb_rx_err-fix-rx-tx-_errors-statist.patch +can-f81604-f81604_handle_can_bus_errors-fix-rx-tx-_e.patch +ipvs-fix-ub-due-to-uninitialized-stack-access-in-ip_.patch +netfilter-x_tables-fix-led-id-check-in-led_tg_check.patch +netfilter-nft_socket-remove-warn_on_once-on-maximum-.patch +selftests-hid-fix-typo-and-exit-code.patch +net-enetc-do-not-configure-preemptible-tcs-if-sis-do.patch +ptp-add-error-handling-for-adjfine-callback-in-ptp_c.patch +net-sched-tbf-correct-backlog-statistic-for-gso-pack.patch +net-hsr-avoid-potential-out-of-bound-access-in-fill_.patch +can-j1939-j1939_session_new-fix-skb-reference-counti.patch +platform-x86-asus-wmi-add-support-for-vivobook-fan-p.patch +platform-x86-asus-wmi-fix-inconsistent-use-of-therma.patch +platform-x86-asus-wmi-ignore-return-value-when-writi.patch +net-timestamp-make-sk_tskey-more-predictable-in-erro.patch +ipv6-introduce-dst_rt6_info-helper.patch +net-ipv6-release-expired-exception-dst-cached-in-soc.patch +dccp-fix-memory-leak-in-dccp_feat_change_recv.patch +tipc-fix-use-after-free-of-kernel-socket-in-cleanup_.patch +net-smc-rename-some-fce-to-fce_v2x-for-clarity.patch +net-smc-introduce-sub-functions-for-smc_clc_send_con.patch +net-smc-unify-the-structs-of-accept-or-confirm-messa.patch +net-smc-define-a-reserved-chid-range-for-virtual-ism.patch +net-smc-compatible-with-128-bits-extended-gid-of-vir.patch +net-smc-mark-optional-smcd_ops-and-check-for-support.patch +net-smc-add-operations-to-merge-sndbuf-with-peer-dmb.patch +net-smc-at-de-tach-sndbuf-to-peer-dmb-if-supported.patch +net-smc-refactoring-initialization-of-smc-sock.patch +net-smc-initialize-close_work-early-to-avoid-warning.patch +net-smc-fix-lgr-and-link-use-after-free-issue.patch +net-qed-allow-old-cards-not-supporting-num_images-to.patch +ixgbevf-stop-attempting-ipsec-offload-on-mailbox-api.patch +ixgbe-downgrade-logging-of-unsupported-vf-api-versio.patch +igb-fix-potential-invalid-memory-access-in-igb_init_.patch +netfilter-nft_inner-incorrect-percpu-area-handling-u.patch +net-sched-fix-erspan_opt-settings-in-cls_flower.patch +netfilter-ipset-hold-module-reference-while-requesti.patch +netfilter-nft_set_hash-skip-duplicated-elements-pend.patch +ethtool-fix-wrong-mod-state-in-case-of-verbose-and-n.patch +mlxsw-add-ipv4_5-flex-key.patch +mlxsw-spectrum_acl_flex_keys-add-ipv4_5b-flex-key.patch +mlxsw-edit-ipv6-key-blocks-to-use-one-less-block-for.patch +mlxsw-mark-high-entropy-key-blocks.patch +mlxsw-spectrum_acl_flex_keys-constify-struct-mlxsw_a.patch +mlxsw-spectrum_acl_flex_keys-use-correct-key-block-o.patch +geneve-do-not-assume-mac-header-is-set-in-geneve_xmi.patch +net-mlx5e-remove-workaround-to-avoid-syndrome-for-in.patch +net-avoid-potential-uaf-in-default_operstate.patch +kvm-arm64-change-kvm_handle_mmio_return-return-polar.patch +kvm-arm64-don-t-retire-aborted-mmio-instruction.patch +xhci-allow-rpm-on-the-usb-controller-1022-43f7-by-de.patch +xhci-remove-xhci_trust_tx_length-quirk.patch +xhci-combine-two-if-statements-for-etron-xhci-host.patch +xhci-don-t-issue-reset-device-command-to-etron-xhci-.patch +xhci-fix-control-transfer-error-on-etron-xhci-host.patch +gpio-grgpio-use-a-helper-variable-to-store-the-addre.patch +gpio-grgpio-add-null-check-in-grgpio_probe.patch +serial-amba-pl011-use-port-lock-wrappers.patch +serial-amba-pl011-fix-rx-stall-when-dma-is-used.patch +soc-fsl-cpm-qmc-convert-to-platform-remove-callback-.patch +soc-fsl-cpm1-qmc-fix-blank-line-and-spaces.patch +soc-fsl-cpm1-qmc-re-order-probe-operations.patch +soc-fsl-cpm1-qmc-introduce-qmc_init_resource-and-its.patch +soc-fsl-cpm1-qmc-introduce-qmc_-init-exit-_xcc-and-t.patch +soc-fsl-cpm1-qmc-set-the-ret-error-code-on-platform_.patch +usb-dwc3-gadget-rewrite-endpoint-allocation-flow.patch +usb-dwc3-ep0-don-t-reset-resource-alloc-flag-includi.patch +usb-dwc3-ep0-don-t-clear-ep0-dwc3_ep_transfer_starte.patch +mmc-mtk-sd-use-devm_mmc_alloc_host.patch +mmc-mtk-sd-fix-error-handle-of-probe-function.patch +mmc-mtk-sd-fix-devm_clk_get_optional-usage.patch +mmc-mtk-sd-fix-mmc_cap2_crypto-flag-setting.patch +zram-split-memory-tracking-and-ac-time-tracking.patch +zram-do-not-mark-idle-slots-that-cannot-be-idle.patch +zram-clear-idle-flag-in-mark_idle.patch +iommu-add-iommu_ops-identity_domain.patch +iommu-qcom_iommu-add-an-iommu_identitiy_domain.patch +iommu-clean-up-open-coded-ownership-checks.patch +iommu-arm-smmu-defer-probe-of-clients-after-smmu-dev.patch +powerpc-vdso-refactor-cflags-for-cvdso-build.patch +powerpc-vdso-drop-mstack-protector-guard-flags-in-32.patch +ntp-remove-unused-tick_nsec.patch +ntp-make-tick_usec-static.patch +ntp-clean-up-comments.patch +ntp-cleanup-formatting-of-code.patch +ntp-convert-functions-with-only-two-states-to-bool.patch +ntp-read-reference-time-only-once.patch +ntp-introduce-struct-ntp_data.patch +ntp-move-tick_length-into-ntp_data.patch +ntp-move-tick_stat-into-ntp_data.patch +ntp-remove-invalid-cast-in-time-offset-math.patch +driver-core-fw_devlink-improve-logs-for-cycle-detect.patch +driver-core-add-fwlink_flag_ignore-to-completely-ign.patch +driver-core-fw_devlink-stop-trying-to-optimize-cycle.patch +f2fs-fix-to-drop-all-discards-after-creating-snapsho.patch +i3c-master-add-enable-disable-hot-join-in-sys-entry.patch +i3c-master-svc-add-hot-join-support.patch +i3c-master-fix-kernel-doc-check-warning.patch +i3c-master-support-to-adjust-first-broadcast-address.patch +i3c-master-svc-use-slow-speed-for-first-broadcast-ad.patch +i3c-master-svc-modify-enabled_events-bit-7-0-to-act-.patch +i3c-master-replace-hard-code-2-with-macro-i3c_addr_s.patch +i3c-master-extend-address-status-bit-to-4-and-add-i3.patch +i3c-master-fix-dynamic-address-leak-when-assigned-ad.patch +drm-bridge-it6505-update-usleep_range-for-rc-circuit.patch +drm-bridge-it6505-fix-inverted-reset-polarity.patch diff --git a/queue-6.6/soc-fsl-cpm-qmc-convert-to-platform-remove-callback-.patch b/queue-6.6/soc-fsl-cpm-qmc-convert-to-platform-remove-callback-.patch new file mode 100644 index 00000000000..7086f70a656 --- /dev/null +++ b/queue-6.6/soc-fsl-cpm-qmc-convert-to-platform-remove-callback-.patch @@ -0,0 +1,67 @@ +From d918e1a9cde7abbf883db7d18903ba3c00b5f8fe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Sep 2023 11:54:57 +0200 +Subject: soc/fsl: cpm: qmc: Convert to platform remove callback returning void +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Uwe Kleine-König + +[ Upstream commit 14914a115e807aa2f8025e451133627a64120ac3 ] + +The .remove() callback for a platform driver returns an int which makes +many driver authors wrongly assume it's possible to do error handling by +returning an error code. However the value returned is ignored (apart +from emitting a warning) and this typically results in resource leaks. +To improve here there is a quest to make the remove callback return +void. In the first step of this quest all drivers are converted to +.remove_new() which already returns void. Eventually after all drivers +are converted, .remove_new() will be renamed to .remove(). + +Trivially convert this driver from always returning zero in the remove +callback to the void returning variant. + +Acked-by: Herve Codina +Link: https://lore.kernel.org/r/20230925095532.1984344-7-u.kleine-koenig@pengutronix.de +Signed-off-by: Uwe Kleine-König +Stable-dep-of: cb3daa51db81 ("soc: fsl: cpm1: qmc: Set the ret error code on platform_get_irq() failure") +Signed-off-by: Sasha Levin +--- + drivers/soc/fsl/qe/qmc.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c +index 8dc73cc1a83b1..2312152a44b3e 100644 +--- a/drivers/soc/fsl/qe/qmc.c ++++ b/drivers/soc/fsl/qe/qmc.c +@@ -1414,7 +1414,7 @@ static int qmc_probe(struct platform_device *pdev) + return ret; + } + +-static int qmc_remove(struct platform_device *pdev) ++static void qmc_remove(struct platform_device *pdev) + { + struct qmc *qmc = platform_get_drvdata(pdev); + +@@ -1426,8 +1426,6 @@ static int qmc_remove(struct platform_device *pdev) + + /* Disconnect the serial from TSA */ + tsa_serial_disconnect(qmc->tsa_serial); +- +- return 0; + } + + static const struct of_device_id qmc_id_table[] = { +@@ -1442,7 +1440,7 @@ static struct platform_driver qmc_driver = { + .of_match_table = of_match_ptr(qmc_id_table), + }, + .probe = qmc_probe, +- .remove = qmc_remove, ++ .remove_new = qmc_remove, + }; + module_platform_driver(qmc_driver); + +-- +2.43.0 + diff --git a/queue-6.6/soc-fsl-cpm1-qmc-fix-blank-line-and-spaces.patch b/queue-6.6/soc-fsl-cpm1-qmc-fix-blank-line-and-spaces.patch new file mode 100644 index 00000000000..d7e1f3d508b --- /dev/null +++ b/queue-6.6/soc-fsl-cpm1-qmc-fix-blank-line-and-spaces.patch @@ -0,0 +1,84 @@ +From 0df2e58d2e560b5c9999925049895b663713d9ee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Aug 2024 09:11:12 +0200 +Subject: soc: fsl: cpm1: qmc: Fix blank line and spaces + +From: Herve Codina + +[ Upstream commit f06ab938bcddcb3c3a0b458b03a827c701919c9e ] + +checkpatch.pl raises the following issues + CHECK: Please don't use multiple blank lines + CHECK: Alignment should match open parenthesis + +Fix them. + +Signed-off-by: Herve Codina +Reviewed-by: Christophe Leroy +Link: https://lore.kernel.org/r/20240808071132.149251-20-herve.codina@bootlin.com +Signed-off-by: Christophe Leroy +Stable-dep-of: cb3daa51db81 ("soc: fsl: cpm1: qmc: Set the ret error code on platform_get_irq() failure") +Signed-off-by: Sasha Levin +--- + drivers/soc/fsl/qe/qmc.c | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c +index 2312152a44b3e..f22d1d85d1021 100644 +--- a/drivers/soc/fsl/qe/qmc.c ++++ b/drivers/soc/fsl/qe/qmc.c +@@ -253,7 +253,6 @@ static inline void qmc_setbits32(void __iomem *addr, u32 set) + qmc_write32(addr, qmc_read32(addr) | set); + } + +- + int qmc_chan_get_info(struct qmc_chan *chan, struct qmc_chan_info *info) + { + struct tsa_serial_info tsa_info; +@@ -1093,7 +1092,7 @@ static int qmc_setup_chan(struct qmc *qmc, struct qmc_chan *chan) + qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x00000080); + qmc_write16(chan->s_param + QMC_SPE_MFLR, 60); + qmc_write16(chan->s_param + QMC_SPE_CHAMR, +- QMC_SPE_CHAMR_MODE_HDLC | QMC_SPE_CHAMR_HDLC_IDLM); ++ QMC_SPE_CHAMR_MODE_HDLC | QMC_SPE_CHAMR_HDLC_IDLM); + } + + /* Do not enable interrupts now. They will be enabled later */ +@@ -1286,7 +1285,6 @@ static int qmc_probe(struct platform_device *pdev) + if (IS_ERR(qmc->scc_regs)) + return PTR_ERR(qmc->scc_regs); + +- + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "scc_pram"); + if (!res) + return -EINVAL; +@@ -1332,7 +1330,7 @@ static int qmc_probe(struct platform_device *pdev) + */ + qmc->bd_size = (nb_chans * (QMC_NB_TXBDS + QMC_NB_RXBDS)) * sizeof(cbd_t); + qmc->bd_table = dmam_alloc_coherent(qmc->dev, qmc->bd_size, +- &qmc->bd_dma_addr, GFP_KERNEL); ++ &qmc->bd_dma_addr, GFP_KERNEL); + if (!qmc->bd_table) { + dev_err(qmc->dev, "Failed to allocate bd table\n"); + ret = -ENOMEM; +@@ -1345,7 +1343,7 @@ static int qmc_probe(struct platform_device *pdev) + /* Allocate the interrupt table */ + qmc->int_size = QMC_NB_INTS * sizeof(u16); + qmc->int_table = dmam_alloc_coherent(qmc->dev, qmc->int_size, +- &qmc->int_dma_addr, GFP_KERNEL); ++ &qmc->int_dma_addr, GFP_KERNEL); + if (!qmc->int_table) { + dev_err(qmc->dev, "Failed to allocate interrupt table\n"); + ret = -ENOMEM; +@@ -1393,7 +1391,7 @@ static int qmc_probe(struct platform_device *pdev) + + /* Enable interrupts */ + qmc_write16(qmc->scc_regs + SCC_SCCM, +- SCC_SCCE_IQOV | SCC_SCCE_GINT | SCC_SCCE_GUN | SCC_SCCE_GOV); ++ SCC_SCCE_IQOV | SCC_SCCE_GINT | SCC_SCCE_GUN | SCC_SCCE_GOV); + + ret = qmc_finalize_chans(qmc); + if (ret < 0) +-- +2.43.0 + diff --git a/queue-6.6/soc-fsl-cpm1-qmc-introduce-qmc_-init-exit-_xcc-and-t.patch b/queue-6.6/soc-fsl-cpm1-qmc-introduce-qmc_-init-exit-_xcc-and-t.patch new file mode 100644 index 00000000000..8ea5fbea289 --- /dev/null +++ b/queue-6.6/soc-fsl-cpm1-qmc-introduce-qmc_-init-exit-_xcc-and-t.patch @@ -0,0 +1,141 @@ +From ba2f18acd4f04784551e645d8809c27f0f0c0342 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Aug 2024 09:11:20 +0200 +Subject: soc: fsl: cpm1: qmc: Introduce qmc_{init,exit}_xcc() and their CPM1 + version + +From: Herve Codina + +[ Upstream commit de5fdb7d14b34f7fea930f2d72cf0241ec679e72 ] + +Current code handles the CPM1 version of QMC and initialize the QMC used +SCC. The QUICC Engine (QE) version uses an UCC (Unified Communication +Controllers) instead of the SCC (Serial Communication Controllers) used +in the CPM1 version. These controllers serve the same purpose and are +used in the same way but their inializations are slightly different. + +In order to prepare the support for QE version of QMC, introduce +qmc_init_xcc() to initialize theses controllers (UCC in QE and SCC in +CPM1) and isolate the CPM1 specific SCC initialization in a specific +function. + +Also introduce qmc_exit_xcc() for consistency to revert operations done +in qmc_init_xcc(). + +Signed-off-by: Herve Codina +Reviewed-by: Christophe Leroy +Link: https://lore.kernel.org/r/20240808071132.149251-28-herve.codina@bootlin.com +Signed-off-by: Christophe Leroy +Stable-dep-of: cb3daa51db81 ("soc: fsl: cpm1: qmc: Set the ret error code on platform_get_irq() failure") +Signed-off-by: Sasha Levin +--- + drivers/soc/fsl/qe/qmc.c | 66 +++++++++++++++++++++++++++------------- + 1 file changed, 45 insertions(+), 21 deletions(-) + +diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c +index f2bda8658e034..9fa75effcfc06 100644 +--- a/drivers/soc/fsl/qe/qmc.c ++++ b/drivers/soc/fsl/qe/qmc.c +@@ -1293,6 +1293,41 @@ static int qmc_init_resources(struct qmc *qmc, struct platform_device *pdev) + return qmc_cpm1_init_resources(qmc, pdev); + } + ++static int qmc_cpm1_init_scc(struct qmc *qmc) ++{ ++ u32 val; ++ int ret; ++ ++ /* Connect the serial (SCC) to TSA */ ++ ret = tsa_serial_connect(qmc->tsa_serial); ++ if (ret) ++ return dev_err_probe(qmc->dev, ret, "Failed to connect TSA serial\n"); ++ ++ /* Init GMSR_H and GMSR_L registers */ ++ val = SCC_GSMRH_CDS | SCC_GSMRH_CTSS | SCC_GSMRH_CDP | SCC_GSMRH_CTSP; ++ qmc_write32(qmc->scc_regs + SCC_GSMRH, val); ++ ++ /* enable QMC mode */ ++ qmc_write32(qmc->scc_regs + SCC_GSMRL, SCC_GSMRL_MODE_QMC); ++ ++ /* Disable and clear interrupts */ ++ qmc_write16(qmc->scc_regs + SCC_SCCM, 0x0000); ++ qmc_write16(qmc->scc_regs + SCC_SCCE, 0x000F); ++ ++ return 0; ++} ++ ++static int qmc_init_xcc(struct qmc *qmc) ++{ ++ return qmc_cpm1_init_scc(qmc); ++} ++ ++static void qmc_exit_xcc(struct qmc *qmc) ++{ ++ /* Disconnect the serial from TSA */ ++ tsa_serial_disconnect(qmc->tsa_serial); ++} ++ + static int qmc_probe(struct platform_device *pdev) + { + struct device_node *np = pdev->dev.of_node; +@@ -1378,29 +1413,18 @@ static int qmc_probe(struct platform_device *pdev) + if (ret) + return ret; + +- /* Connect the serial (SCC) to TSA */ +- ret = tsa_serial_connect(qmc->tsa_serial); +- if (ret) { +- dev_err(qmc->dev, "Failed to connect TSA serial\n"); ++ /* Init SCC */ ++ ret = qmc_init_xcc(qmc); ++ if (ret) + return ret; +- } + +- /* Init GMSR_H and GMSR_L registers */ +- qmc_write32(qmc->scc_regs + SCC_GSMRH, +- SCC_GSMRH_CDS | SCC_GSMRH_CTSS | SCC_GSMRH_CDP | SCC_GSMRH_CTSP); +- +- /* enable QMC mode */ +- qmc_write32(qmc->scc_regs + SCC_GSMRL, SCC_GSMRL_MODE_QMC); +- +- /* Disable and clear interrupts, set the irq handler */ +- qmc_write16(qmc->scc_regs + SCC_SCCM, 0x0000); +- qmc_write16(qmc->scc_regs + SCC_SCCE, 0x000F); ++ /* Set the irq handler */ + irq = platform_get_irq(pdev, 0); + if (irq < 0) +- goto err_tsa_serial_disconnect; ++ goto err_exit_xcc; + ret = devm_request_irq(qmc->dev, irq, qmc_irq_handler, 0, "qmc", qmc); + if (ret < 0) +- goto err_tsa_serial_disconnect; ++ goto err_exit_xcc; + + /* Enable interrupts */ + qmc_write16(qmc->scc_regs + SCC_SCCM, +@@ -1420,8 +1444,8 @@ static int qmc_probe(struct platform_device *pdev) + err_disable_intr: + qmc_write16(qmc->scc_regs + SCC_SCCM, 0); + +-err_tsa_serial_disconnect: +- tsa_serial_disconnect(qmc->tsa_serial); ++err_exit_xcc: ++ qmc_exit_xcc(qmc); + return ret; + } + +@@ -1435,8 +1459,8 @@ static void qmc_remove(struct platform_device *pdev) + /* Disable interrupts */ + qmc_write16(qmc->scc_regs + SCC_SCCM, 0); + +- /* Disconnect the serial from TSA */ +- tsa_serial_disconnect(qmc->tsa_serial); ++ /* Exit SCC */ ++ qmc_exit_xcc(qmc); + } + + static const struct of_device_id qmc_id_table[] = { +-- +2.43.0 + diff --git a/queue-6.6/soc-fsl-cpm1-qmc-introduce-qmc_init_resource-and-its.patch b/queue-6.6/soc-fsl-cpm1-qmc-introduce-qmc_init_resource-and-its.patch new file mode 100644 index 00000000000..a2c180478a9 --- /dev/null +++ b/queue-6.6/soc-fsl-cpm1-qmc-introduce-qmc_init_resource-and-its.patch @@ -0,0 +1,102 @@ +From 91a5255d35bb3183a4467d42bece0c02ee1f9485 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Aug 2024 09:11:19 +0200 +Subject: soc: fsl: cpm1: qmc: Introduce qmc_init_resource() and its CPM1 + version + +From: Herve Codina + +[ Upstream commit 727b3ab490a5f5e74fb3f246c9fdfb339d309950 ] + +Current code handles the CPM1 version of QMC. Resources initialisations +(i.e. retrieving base addresses and offsets of different parts) will +be slightly different in the QUICC Engine (QE) version. Indeed, in QE +version, some resources need to be allocated and are no more "staticaly" +defined. + +In order to prepare the support for QE version, introduce +qmc_init_resource() to initialize those resources and isolate the CPM1 +specific operations in a specific function. + +Signed-off-by: Herve Codina +Reviewed-by: Christophe Leroy +Link: https://lore.kernel.org/r/20240808071132.149251-27-herve.codina@bootlin.com +Signed-off-by: Christophe Leroy +Stable-dep-of: cb3daa51db81 ("soc: fsl: cpm1: qmc: Set the ret error code on platform_get_irq() failure") +Signed-off-by: Sasha Levin +--- + drivers/soc/fsl/qe/qmc.c | 47 ++++++++++++++++++++++++++-------------- + 1 file changed, 31 insertions(+), 16 deletions(-) + +diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c +index a5c9cbb99600e..f2bda8658e034 100644 +--- a/drivers/soc/fsl/qe/qmc.c ++++ b/drivers/soc/fsl/qe/qmc.c +@@ -1265,11 +1265,38 @@ static irqreturn_t qmc_irq_handler(int irq, void *priv) + return IRQ_HANDLED; + } + ++static int qmc_cpm1_init_resources(struct qmc *qmc, struct platform_device *pdev) ++{ ++ struct resource *res; ++ ++ qmc->scc_regs = devm_platform_ioremap_resource_byname(pdev, "scc_regs"); ++ if (IS_ERR(qmc->scc_regs)) ++ return PTR_ERR(qmc->scc_regs); ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "scc_pram"); ++ if (!res) ++ return -EINVAL; ++ qmc->scc_pram_offset = res->start - get_immrbase(); ++ qmc->scc_pram = devm_ioremap_resource(qmc->dev, res); ++ if (IS_ERR(qmc->scc_pram)) ++ return PTR_ERR(qmc->scc_pram); ++ ++ qmc->dpram = devm_platform_ioremap_resource_byname(pdev, "dpram"); ++ if (IS_ERR(qmc->dpram)) ++ return PTR_ERR(qmc->dpram); ++ ++ return 0; ++} ++ ++static int qmc_init_resources(struct qmc *qmc, struct platform_device *pdev) ++{ ++ return qmc_cpm1_init_resources(qmc, pdev); ++} ++ + static int qmc_probe(struct platform_device *pdev) + { + struct device_node *np = pdev->dev.of_node; + unsigned int nb_chans; +- struct resource *res; + struct qmc *qmc; + int irq; + int ret; +@@ -1287,21 +1314,9 @@ static int qmc_probe(struct platform_device *pdev) + "Failed to get TSA serial\n"); + } + +- qmc->scc_regs = devm_platform_ioremap_resource_byname(pdev, "scc_regs"); +- if (IS_ERR(qmc->scc_regs)) +- return PTR_ERR(qmc->scc_regs); +- +- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "scc_pram"); +- if (!res) +- return -EINVAL; +- qmc->scc_pram_offset = res->start - get_immrbase(); +- qmc->scc_pram = devm_ioremap_resource(qmc->dev, res); +- if (IS_ERR(qmc->scc_pram)) +- return PTR_ERR(qmc->scc_pram); +- +- qmc->dpram = devm_platform_ioremap_resource_byname(pdev, "dpram"); +- if (IS_ERR(qmc->dpram)) +- return PTR_ERR(qmc->dpram); ++ ret = qmc_init_resources(qmc, pdev); ++ if (ret) ++ return ret; + + /* Parse channels informationss */ + ret = qmc_of_parse_chans(qmc, np); +-- +2.43.0 + diff --git a/queue-6.6/soc-fsl-cpm1-qmc-re-order-probe-operations.patch b/queue-6.6/soc-fsl-cpm1-qmc-re-order-probe-operations.patch new file mode 100644 index 00000000000..1ba792f00ad --- /dev/null +++ b/queue-6.6/soc-fsl-cpm1-qmc-re-order-probe-operations.patch @@ -0,0 +1,143 @@ +From e9e959b27f87d7d92548a561e93742159d86bab8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Aug 2024 09:11:18 +0200 +Subject: soc: fsl: cpm1: qmc: Re-order probe() operations + +From: Herve Codina + +[ Upstream commit a13bf605342ea9df492b8159cadaa41862b53e15 ] + +Current code handles CPM1 version of QMC. In the QUICC Engine (QE) +version, some operations done at probe() need to be done in a different +order. + +In order to prepare the support for the QE version, changed the sequence +of operation done at probe(): +- Retrieve the tsa_serial earlier, before initializing resources. +- Group SCC initialisation and do this initialization when it is really + needed in the probe() sequence. + +Having the QE compatible sequence in the CPM1 version does not lead to +any issue and works correctly without any regressions. + +Signed-off-by: Herve Codina +Reviewed-by: Christophe Leroy +Link: https://lore.kernel.org/r/20240808071132.149251-26-herve.codina@bootlin.com +Signed-off-by: Christophe Leroy +Stable-dep-of: cb3daa51db81 ("soc: fsl: cpm1: qmc: Set the ret error code on platform_get_irq() failure") +Signed-off-by: Sasha Levin +--- + drivers/soc/fsl/qe/qmc.c | 54 +++++++++++++++++++--------------------- + 1 file changed, 26 insertions(+), 28 deletions(-) + +diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c +index f22d1d85d1021..a5c9cbb99600e 100644 +--- a/drivers/soc/fsl/qe/qmc.c ++++ b/drivers/soc/fsl/qe/qmc.c +@@ -1281,6 +1281,12 @@ static int qmc_probe(struct platform_device *pdev) + qmc->dev = &pdev->dev; + INIT_LIST_HEAD(&qmc->chan_head); + ++ qmc->tsa_serial = devm_tsa_serial_get_byphandle(qmc->dev, np, "fsl,tsa-serial"); ++ if (IS_ERR(qmc->tsa_serial)) { ++ return dev_err_probe(qmc->dev, PTR_ERR(qmc->tsa_serial), ++ "Failed to get TSA serial\n"); ++ } ++ + qmc->scc_regs = devm_platform_ioremap_resource_byname(pdev, "scc_regs"); + if (IS_ERR(qmc->scc_regs)) + return PTR_ERR(qmc->scc_regs); +@@ -1297,33 +1303,13 @@ static int qmc_probe(struct platform_device *pdev) + if (IS_ERR(qmc->dpram)) + return PTR_ERR(qmc->dpram); + +- qmc->tsa_serial = devm_tsa_serial_get_byphandle(qmc->dev, np, "fsl,tsa-serial"); +- if (IS_ERR(qmc->tsa_serial)) { +- return dev_err_probe(qmc->dev, PTR_ERR(qmc->tsa_serial), +- "Failed to get TSA serial\n"); +- } +- +- /* Connect the serial (SCC) to TSA */ +- ret = tsa_serial_connect(qmc->tsa_serial); +- if (ret) { +- dev_err(qmc->dev, "Failed to connect TSA serial\n"); +- return ret; +- } +- + /* Parse channels informationss */ + ret = qmc_of_parse_chans(qmc, np); + if (ret) +- goto err_tsa_serial_disconnect; ++ return ret; + + nb_chans = qmc_nb_chans(qmc); + +- /* Init GMSR_H and GMSR_L registers */ +- qmc_write32(qmc->scc_regs + SCC_GSMRH, +- SCC_GSMRH_CDS | SCC_GSMRH_CTSS | SCC_GSMRH_CDP | SCC_GSMRH_CTSP); +- +- /* enable QMC mode */ +- qmc_write32(qmc->scc_regs + SCC_GSMRL, SCC_GSMRL_MODE_QMC); +- + /* + * Allocate the buffer descriptor table + * 8 rx and 8 tx descriptors per channel +@@ -1333,8 +1319,7 @@ static int qmc_probe(struct platform_device *pdev) + &qmc->bd_dma_addr, GFP_KERNEL); + if (!qmc->bd_table) { + dev_err(qmc->dev, "Failed to allocate bd table\n"); +- ret = -ENOMEM; +- goto err_tsa_serial_disconnect; ++ return -ENOMEM; + } + memset(qmc->bd_table, 0, qmc->bd_size); + +@@ -1346,8 +1331,7 @@ static int qmc_probe(struct platform_device *pdev) + &qmc->int_dma_addr, GFP_KERNEL); + if (!qmc->int_table) { + dev_err(qmc->dev, "Failed to allocate interrupt table\n"); +- ret = -ENOMEM; +- goto err_tsa_serial_disconnect; ++ return -ENOMEM; + } + memset(qmc->int_table, 0, qmc->int_size); + +@@ -1366,18 +1350,32 @@ static int qmc_probe(struct platform_device *pdev) + + ret = qmc_setup_tsa(qmc); + if (ret) +- goto err_tsa_serial_disconnect; ++ return ret; + + qmc_write16(qmc->scc_pram + QMC_GBL_QMCSTATE, 0x8000); + + ret = qmc_setup_chans(qmc); + if (ret) +- goto err_tsa_serial_disconnect; ++ return ret; + + /* Init interrupts table */ + ret = qmc_setup_ints(qmc); + if (ret) +- goto err_tsa_serial_disconnect; ++ return ret; ++ ++ /* Connect the serial (SCC) to TSA */ ++ ret = tsa_serial_connect(qmc->tsa_serial); ++ if (ret) { ++ dev_err(qmc->dev, "Failed to connect TSA serial\n"); ++ return ret; ++ } ++ ++ /* Init GMSR_H and GMSR_L registers */ ++ qmc_write32(qmc->scc_regs + SCC_GSMRH, ++ SCC_GSMRH_CDS | SCC_GSMRH_CTSS | SCC_GSMRH_CDP | SCC_GSMRH_CTSP); ++ ++ /* enable QMC mode */ ++ qmc_write32(qmc->scc_regs + SCC_GSMRL, SCC_GSMRL_MODE_QMC); + + /* Disable and clear interrupts, set the irq handler */ + qmc_write16(qmc->scc_regs + SCC_SCCM, 0x0000); +-- +2.43.0 + diff --git a/queue-6.6/soc-fsl-cpm1-qmc-set-the-ret-error-code-on-platform_.patch b/queue-6.6/soc-fsl-cpm1-qmc-set-the-ret-error-code-on-platform_.patch new file mode 100644 index 00000000000..63e2bc89012 --- /dev/null +++ b/queue-6.6/soc-fsl-cpm1-qmc-set-the-ret-error-code-on-platform_.patch @@ -0,0 +1,51 @@ +From 36ba7e5a0bbdd15fe5778e1b1b4ddd555930e0f7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 5 Nov 2024 15:56:23 +0100 +Subject: soc: fsl: cpm1: qmc: Set the ret error code on platform_get_irq() + failure + +From: Herve Codina + +[ Upstream commit cb3daa51db819a172e9524e96e2ed96b4237e51a ] + +A kernel test robot detected a missing error code: + qmc.c:1942 qmc_probe() warn: missing error code 'ret' + +Indeed, the error returned by platform_get_irq() is checked and the +operation is aborted in case of failure but the ret error code is +not set in that case. + +Set the ret error code. + +Reported-by: kernel test robot +Reported-by: Dan Carpenter +Closes: https://lore.kernel.org/r/202411051350.KNy6ZIWA-lkp@intel.com/ +Fixes: 3178d58e0b97 ("soc: fsl: cpm1: Add support for QMC") +Cc: stable@vger.kernel.org +Signed-off-by: Herve Codina +Link: https://lore.kernel.org/r/20241105145623.401528-1-herve.codina@bootlin.com +Signed-off-by: Christophe Leroy +Signed-off-by: Sasha Levin +--- + drivers/soc/fsl/qe/qmc.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c +index 9fa75effcfc06..f1720c7cbe063 100644 +--- a/drivers/soc/fsl/qe/qmc.c ++++ b/drivers/soc/fsl/qe/qmc.c +@@ -1420,8 +1420,10 @@ static int qmc_probe(struct platform_device *pdev) + + /* Set the irq handler */ + irq = platform_get_irq(pdev, 0); +- if (irq < 0) ++ if (irq < 0) { ++ ret = irq; + goto err_exit_xcc; ++ } + ret = devm_request_irq(qmc->dev, irq, qmc_irq_handler, 0, "qmc", qmc); + if (ret < 0) + goto err_exit_xcc; +-- +2.43.0 + diff --git a/queue-6.6/tipc-fix-use-after-free-of-kernel-socket-in-cleanup_.patch b/queue-6.6/tipc-fix-use-after-free-of-kernel-socket-in-cleanup_.patch new file mode 100644 index 00000000000..1541445c234 --- /dev/null +++ b/queue-6.6/tipc-fix-use-after-free-of-kernel-socket-in-cleanup_.patch @@ -0,0 +1,107 @@ +From 8a129f26bc6fb44f8555a1d094e5c1a1071363da Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 Nov 2024 14:05:12 +0900 +Subject: tipc: Fix use-after-free of kernel socket in cleanup_bearer(). + +From: Kuniyuki Iwashima + +[ Upstream commit 6a2fa13312e51a621f652d522d7e2df7066330b6 ] + +syzkaller reported a use-after-free of UDP kernel socket +in cleanup_bearer() without repro. [0][1] + +When bearer_disable() calls tipc_udp_disable(), cleanup +of the UDP kernel socket is deferred by work calling +cleanup_bearer(). + +tipc_net_stop() waits for such works to finish by checking +tipc_net(net)->wq_count. However, the work decrements the +count too early before releasing the kernel socket, +unblocking cleanup_net() and resulting in use-after-free. + +Let's move the decrement after releasing the socket in +cleanup_bearer(). + +[0]: +ref_tracker: net notrefcnt@000000009b3d1faf has 1/1 users at + sk_alloc+0x438/0x608 + inet_create+0x4c8/0xcb0 + __sock_create+0x350/0x6b8 + sock_create_kern+0x58/0x78 + udp_sock_create4+0x68/0x398 + udp_sock_create+0x88/0xc8 + tipc_udp_enable+0x5e8/0x848 + __tipc_nl_bearer_enable+0x84c/0xed8 + tipc_nl_bearer_enable+0x38/0x60 + genl_family_rcv_msg_doit+0x170/0x248 + genl_rcv_msg+0x400/0x5b0 + netlink_rcv_skb+0x1dc/0x398 + genl_rcv+0x44/0x68 + netlink_unicast+0x678/0x8b0 + netlink_sendmsg+0x5e4/0x898 + ____sys_sendmsg+0x500/0x830 + +[1]: +BUG: KMSAN: use-after-free in udp_hashslot include/net/udp.h:85 [inline] +BUG: KMSAN: use-after-free in udp_lib_unhash+0x3b8/0x930 net/ipv4/udp.c:1979 + udp_hashslot include/net/udp.h:85 [inline] + udp_lib_unhash+0x3b8/0x930 net/ipv4/udp.c:1979 + sk_common_release+0xaf/0x3f0 net/core/sock.c:3820 + inet_release+0x1e0/0x260 net/ipv4/af_inet.c:437 + inet6_release+0x6f/0xd0 net/ipv6/af_inet6.c:489 + __sock_release net/socket.c:658 [inline] + sock_release+0xa0/0x210 net/socket.c:686 + cleanup_bearer+0x42d/0x4c0 net/tipc/udp_media.c:819 + process_one_work kernel/workqueue.c:3229 [inline] + process_scheduled_works+0xcaf/0x1c90 kernel/workqueue.c:3310 + worker_thread+0xf6c/0x1510 kernel/workqueue.c:3391 + kthread+0x531/0x6b0 kernel/kthread.c:389 + ret_from_fork+0x60/0x80 arch/x86/kernel/process.c:147 + ret_from_fork_asm+0x11/0x20 arch/x86/entry/entry_64.S:244 + +Uninit was created at: + slab_free_hook mm/slub.c:2269 [inline] + slab_free mm/slub.c:4580 [inline] + kmem_cache_free+0x207/0xc40 mm/slub.c:4682 + net_free net/core/net_namespace.c:454 [inline] + cleanup_net+0x16f2/0x19d0 net/core/net_namespace.c:647 + process_one_work kernel/workqueue.c:3229 [inline] + process_scheduled_works+0xcaf/0x1c90 kernel/workqueue.c:3310 + worker_thread+0xf6c/0x1510 kernel/workqueue.c:3391 + kthread+0x531/0x6b0 kernel/kthread.c:389 + ret_from_fork+0x60/0x80 arch/x86/kernel/process.c:147 + ret_from_fork_asm+0x11/0x20 arch/x86/entry/entry_64.S:244 + +CPU: 0 UID: 0 PID: 54 Comm: kworker/0:2 Not tainted 6.12.0-rc1-00131-gf66ebf37d69c #7 91723d6f74857f70725e1583cba3cf4adc716cfa +Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.3-0-ga6ed6b701f0a-prebuilt.qemu.org 04/01/2014 +Workqueue: events cleanup_bearer + +Fixes: 26abe14379f8 ("net: Modify sk_alloc to not reference count the netns of kernel sockets.") +Reported-by: syzkaller +Signed-off-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20241127050512.28438-1-kuniyu@amazon.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/tipc/udp_media.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c +index cdc8378261ec3..70a39e29a6352 100644 +--- a/net/tipc/udp_media.c ++++ b/net/tipc/udp_media.c +@@ -814,10 +814,10 @@ static void cleanup_bearer(struct work_struct *work) + kfree_rcu(rcast, rcu); + } + +- atomic_dec(&tipc_net(sock_net(ub->ubsock->sk))->wq_count); + dst_cache_destroy(&ub->rcast.dst_cache); + udp_tunnel_sock_release(ub->ubsock); + synchronize_net(); ++ atomic_dec(&tipc_net(sock_net(ub->ubsock->sk))->wq_count); + kfree(ub); + } + +-- +2.43.0 + diff --git a/queue-6.6/usb-dwc3-ep0-don-t-clear-ep0-dwc3_ep_transfer_starte.patch b/queue-6.6/usb-dwc3-ep0-don-t-clear-ep0-dwc3_ep_transfer_starte.patch new file mode 100644 index 00000000000..ae1b03a9fc4 --- /dev/null +++ b/queue-6.6/usb-dwc3-ep0-don-t-clear-ep0-dwc3_ep_transfer_starte.patch @@ -0,0 +1,41 @@ +From b74dd461bfdb305ec3643cf668669c7ea887cbf9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 14 Nov 2024 01:02:06 +0000 +Subject: usb: dwc3: ep0: Don't clear ep0 DWC3_EP_TRANSFER_STARTED + +From: Thinh Nguyen + +[ Upstream commit 5d2fb074dea289c41f5aaf2c3f68286bee370634 ] + +The driver cannot issue the End Transfer command to the SETUP transfer. +Don't clear DWC3_EP_TRANSFER_STARTED flag to make sure that the driver +won't send Start Transfer command again, which can cause no-resource +error. For example this can occur if the host issues a reset to the +device. + +Cc: stable@vger.kernel.org +Fixes: 76cb323f80ac ("usb: dwc3: ep0: clear all EP0 flags") +Signed-off-by: Thinh Nguyen +Link: https://lore.kernel.org/r/d3d618185fd614bb7426352a9fc1199641d3b5f5.1731545781.git.Thinh.Nguyen@synopsys.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/dwc3/ep0.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c +index 371662a552538..69d98f1938edd 100644 +--- a/drivers/usb/dwc3/ep0.c ++++ b/drivers/usb/dwc3/ep0.c +@@ -231,7 +231,7 @@ void dwc3_ep0_stall_and_restart(struct dwc3 *dwc) + /* stall is always issued on EP0 */ + dep = dwc->eps[0]; + __dwc3_gadget_ep_set_halt(dep, 1, false); +- dep->flags &= DWC3_EP_RESOURCE_ALLOCATED; ++ dep->flags &= DWC3_EP_RESOURCE_ALLOCATED | DWC3_EP_TRANSFER_STARTED; + dep->flags |= DWC3_EP_ENABLED; + dwc->delayed_status = false; + +-- +2.43.0 + diff --git a/queue-6.6/usb-dwc3-ep0-don-t-reset-resource-alloc-flag-includi.patch b/queue-6.6/usb-dwc3-ep0-don-t-reset-resource-alloc-flag-includi.patch new file mode 100644 index 00000000000..1eec2f8b84e --- /dev/null +++ b/queue-6.6/usb-dwc3-ep0-don-t-reset-resource-alloc-flag-includi.patch @@ -0,0 +1,49 @@ +From 268a50b29795e5a00c8fd9f91ac8dabcae35fc9f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Aug 2024 08:40:29 +0200 +Subject: usb: dwc3: ep0: Don't reset resource alloc flag (including ep0) + +From: Michael Grzeschik + +[ Upstream commit 72fca8371f205d654f95b09cd023a71fd5307041 ] + +The DWC3_EP_RESOURCE_ALLOCATED flag ensures that the resource of an +endpoint is only assigned once. Unless the endpoint is reset, don't +clear this flag. Otherwise we may set endpoint resource again, which +prevents the driver from initiate transfer after handling a STALL or +endpoint halt to the control endpoint. + +Commit f2e0eee47038 ("usb: dwc3: ep0: Don't reset resource alloc flag") +was fixing the initial issue, but did this only for physical ep1. Since +the function dwc3_ep0_stall_and_restart is resetting the flags for both +physical endpoints, this also has to be done for ep0. + +Cc: stable@vger.kernel.org +Fixes: b311048c174d ("usb: dwc3: gadget: Rewrite endpoint allocation flow") +Acked-by: Thinh Nguyen +Signed-off-by: Michael Grzeschik +Link: https://lore.kernel.org/r/20240814-dwc3hwep0reset-v2-1-29e1d7d923ea@pengutronix.de +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: 5d2fb074dea2 ("usb: dwc3: ep0: Don't clear ep0 DWC3_EP_TRANSFER_STARTED") +Signed-off-by: Sasha Levin +--- + drivers/usb/dwc3/ep0.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c +index 72bb722da2f25..371662a552538 100644 +--- a/drivers/usb/dwc3/ep0.c ++++ b/drivers/usb/dwc3/ep0.c +@@ -231,7 +231,8 @@ void dwc3_ep0_stall_and_restart(struct dwc3 *dwc) + /* stall is always issued on EP0 */ + dep = dwc->eps[0]; + __dwc3_gadget_ep_set_halt(dep, 1, false); +- dep->flags = DWC3_EP_ENABLED; ++ dep->flags &= DWC3_EP_RESOURCE_ALLOCATED; ++ dep->flags |= DWC3_EP_ENABLED; + dwc->delayed_status = false; + + if (!list_empty(&dep->pending_list)) { +-- +2.43.0 + diff --git a/queue-6.6/usb-dwc3-gadget-rewrite-endpoint-allocation-flow.patch b/queue-6.6/usb-dwc3-gadget-rewrite-endpoint-allocation-flow.patch new file mode 100644 index 00000000000..057e32b1378 --- /dev/null +++ b/queue-6.6/usb-dwc3-gadget-rewrite-endpoint-allocation-flow.patch @@ -0,0 +1,250 @@ +From e0d934364c00ad0339e2ed1bd437bfaf65ebcafa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 1 Feb 2024 02:26:53 +0000 +Subject: usb: dwc3: gadget: Rewrite endpoint allocation flow + +From: Thinh Nguyen + +[ Upstream commit b311048c174da893f47fc09439bc1f6fa2a29589 ] + +The driver dwc3 deviates from the programming guide in regard to +endpoint configuration. It does this command sequence: + +DEPSTARTCFG -> DEPXFERCFG -> DEPCFG + +Instead of the suggested flow: + +DEPSTARTCFG -> DEPCFG -> DEPXFERCFG + +The reasons for this deviation were as follow, quoted: + + 1) The databook says to do %DWC3_DEPCMD_DEPSTARTCFG for every + %USB_REQ_SET_CONFIGURATION and %USB_REQ_SET_INTERFACE + (8.1.5). This is incorrect in the scenario of multiple + interfaces. + + 2) The databook does not mention doing more + %DWC3_DEPCMD_DEPXFERCFG for new endpoint on alt setting + (8.1.6). + +Regarding 1), DEPSTARTCFG resets the endpoints' resource and can be a +problem if used with SET_INTERFACE request of a multiple interface +configuration. But we can still satisfy the programming guide +requirement by assigning the endpoint resource as part of +usb_ep_enable(). We will only reset endpoint resources on controller +initialization and SET_CONFIGURATION request. + +Regarding 2), the later versions of the programming guide were updated +to clarify this flow (see "Alternate Initialization on SetInterface +Request" of the programming guide). As long as the platform has enough +physical endpoints, we can assign resource to a new endpoint. + +The order of the command sequence will not be a problem to most +platforms for the current implementation of the dwc3 driver. However, +this order is required in different scenarios (such as initialization +during controller's hibernation restore). Let's keep the flow consistent +and follow the programming guide. + +Signed-off-by: Thinh Nguyen +Link: https://lore.kernel.org/r/c143583a5afb087deb8c3aa5eb227ee23515f272.1706754219.git.Thinh.Nguyen@synopsys.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: 5d2fb074dea2 ("usb: dwc3: ep0: Don't clear ep0 DWC3_EP_TRANSFER_STARTED") +Signed-off-by: Sasha Levin +--- + drivers/usb/dwc3/core.h | 1 + + drivers/usb/dwc3/ep0.c | 1 + + drivers/usb/dwc3/gadget.c | 89 +++++++++++++++++---------------------- + drivers/usb/dwc3/gadget.h | 1 + + 4 files changed, 41 insertions(+), 51 deletions(-) + +diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h +index 3325796f3cb45..b118f4aab1898 100644 +--- a/drivers/usb/dwc3/core.h ++++ b/drivers/usb/dwc3/core.h +@@ -751,6 +751,7 @@ struct dwc3_ep { + #define DWC3_EP_PENDING_CLEAR_STALL BIT(11) + #define DWC3_EP_TXFIFO_RESIZED BIT(12) + #define DWC3_EP_DELAY_STOP BIT(13) ++#define DWC3_EP_RESOURCE_ALLOCATED BIT(14) + + /* This last one is specific to EP0 */ + #define DWC3_EP0_DIR_IN BIT(31) +diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c +index 6ae8a36f21cf6..72bb722da2f25 100644 +--- a/drivers/usb/dwc3/ep0.c ++++ b/drivers/usb/dwc3/ep0.c +@@ -646,6 +646,7 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) + return -EINVAL; + + case USB_STATE_ADDRESS: ++ dwc3_gadget_start_config(dwc, 2); + dwc3_gadget_clear_tx_fifos(dwc); + + ret = dwc3_ep0_delegate_req(dwc, ctrl); +diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c +index 9971076c31de6..b560996bd4218 100644 +--- a/drivers/usb/dwc3/gadget.c ++++ b/drivers/usb/dwc3/gadget.c +@@ -516,77 +516,56 @@ static void dwc3_free_trb_pool(struct dwc3_ep *dep) + static int dwc3_gadget_set_xfer_resource(struct dwc3_ep *dep) + { + struct dwc3_gadget_ep_cmd_params params; ++ int ret; ++ ++ if (dep->flags & DWC3_EP_RESOURCE_ALLOCATED) ++ return 0; + + memset(¶ms, 0x00, sizeof(params)); + + params.param0 = DWC3_DEPXFERCFG_NUM_XFER_RES(1); + +- return dwc3_send_gadget_ep_cmd(dep, DWC3_DEPCMD_SETTRANSFRESOURCE, ++ ret = dwc3_send_gadget_ep_cmd(dep, DWC3_DEPCMD_SETTRANSFRESOURCE, + ¶ms); ++ if (ret) ++ return ret; ++ ++ dep->flags |= DWC3_EP_RESOURCE_ALLOCATED; ++ return 0; + } + + /** +- * dwc3_gadget_start_config - configure ep resources +- * @dep: endpoint that is being enabled +- * +- * Issue a %DWC3_DEPCMD_DEPSTARTCFG command to @dep. After the command's +- * completion, it will set Transfer Resource for all available endpoints. +- * +- * The assignment of transfer resources cannot perfectly follow the data book +- * due to the fact that the controller driver does not have all knowledge of the +- * configuration in advance. It is given this information piecemeal by the +- * composite gadget framework after every SET_CONFIGURATION and +- * SET_INTERFACE. Trying to follow the databook programming model in this +- * scenario can cause errors. For two reasons: +- * +- * 1) The databook says to do %DWC3_DEPCMD_DEPSTARTCFG for every +- * %USB_REQ_SET_CONFIGURATION and %USB_REQ_SET_INTERFACE (8.1.5). This is +- * incorrect in the scenario of multiple interfaces. +- * +- * 2) The databook does not mention doing more %DWC3_DEPCMD_DEPXFERCFG for new +- * endpoint on alt setting (8.1.6). +- * +- * The following simplified method is used instead: ++ * dwc3_gadget_start_config - reset endpoint resources ++ * @dwc: pointer to the DWC3 context ++ * @resource_index: DEPSTARTCFG.XferRscIdx value (must be 0 or 2) + * +- * All hardware endpoints can be assigned a transfer resource and this setting +- * will stay persistent until either a core reset or hibernation. So whenever we +- * do a %DWC3_DEPCMD_DEPSTARTCFG(0) we can go ahead and do +- * %DWC3_DEPCMD_DEPXFERCFG for every hardware endpoint as well. We are +- * guaranteed that there are as many transfer resources as endpoints. ++ * Set resource_index=0 to reset all endpoints' resources allocation. Do this as ++ * part of the power-on/soft-reset initialization. + * +- * This function is called for each endpoint when it is being enabled but is +- * triggered only when called for EP0-out, which always happens first, and which +- * should only happen in one of the above conditions. ++ * Set resource_index=2 to reset only non-control endpoints' resources. Do this ++ * on receiving the SET_CONFIGURATION request or hibernation resume. + */ +-static int dwc3_gadget_start_config(struct dwc3_ep *dep) ++int dwc3_gadget_start_config(struct dwc3 *dwc, unsigned int resource_index) + { + struct dwc3_gadget_ep_cmd_params params; +- struct dwc3 *dwc; + u32 cmd; + int i; + int ret; + +- if (dep->number) +- return 0; ++ if (resource_index != 0 && resource_index != 2) ++ return -EINVAL; + + memset(¶ms, 0x00, sizeof(params)); + cmd = DWC3_DEPCMD_DEPSTARTCFG; +- dwc = dep->dwc; ++ cmd |= DWC3_DEPCMD_PARAM(resource_index); + +- ret = dwc3_send_gadget_ep_cmd(dep, cmd, ¶ms); ++ ret = dwc3_send_gadget_ep_cmd(dwc->eps[0], cmd, ¶ms); + if (ret) + return ret; + +- for (i = 0; i < DWC3_ENDPOINTS_NUM; i++) { +- struct dwc3_ep *dep = dwc->eps[i]; +- +- if (!dep) +- continue; +- +- ret = dwc3_gadget_set_xfer_resource(dep); +- if (ret) +- return ret; +- } ++ /* Reset resource allocation flags */ ++ for (i = resource_index; i < dwc->num_eps && dwc->eps[i]; i++) ++ dwc->eps[i]->flags &= ~DWC3_EP_RESOURCE_ALLOCATED; + + return 0; + } +@@ -881,16 +860,18 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, unsigned int action) + ret = dwc3_gadget_resize_tx_fifos(dep); + if (ret) + return ret; +- +- ret = dwc3_gadget_start_config(dep); +- if (ret) +- return ret; + } + + ret = dwc3_gadget_set_ep_config(dep, action); + if (ret) + return ret; + ++ if (!(dep->flags & DWC3_EP_RESOURCE_ALLOCATED)) { ++ ret = dwc3_gadget_set_xfer_resource(dep); ++ if (ret) ++ return ret; ++ } ++ + if (!(dep->flags & DWC3_EP_ENABLED)) { + struct dwc3_trb *trb_st_hw; + struct dwc3_trb *trb_link; +@@ -1044,7 +1025,7 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep) + + dep->stream_capable = false; + dep->type = 0; +- mask = DWC3_EP_TXFIFO_RESIZED; ++ mask = DWC3_EP_TXFIFO_RESIZED | DWC3_EP_RESOURCE_ALLOCATED; + /* + * dwc3_remove_requests() can exit early if DWC3 EP delayed stop is + * set. Do not clear DEP flags, so that the end transfer command will +@@ -2909,6 +2890,12 @@ static int __dwc3_gadget_start(struct dwc3 *dwc) + /* Start with SuperSpeed Default */ + dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512); + ++ ret = dwc3_gadget_start_config(dwc, 0); ++ if (ret) { ++ dev_err(dwc->dev, "failed to config endpoints\n"); ++ return ret; ++ } ++ + dep = dwc->eps[0]; + dep->flags = 0; + ret = __dwc3_gadget_ep_enable(dep, DWC3_DEPCFG_ACTION_INIT); +diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h +index 55a56cf67d736..d73e735e40810 100644 +--- a/drivers/usb/dwc3/gadget.h ++++ b/drivers/usb/dwc3/gadget.h +@@ -119,6 +119,7 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request, + int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol); + void dwc3_ep0_send_delayed_status(struct dwc3 *dwc); + void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force, bool interrupt); ++int dwc3_gadget_start_config(struct dwc3 *dwc, unsigned int resource_index); + + /** + * dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW +-- +2.43.0 + diff --git a/queue-6.6/watchdog-apple-actually-flush-writes-after-requestin.patch b/queue-6.6/watchdog-apple-actually-flush-writes-after-requestin.patch new file mode 100644 index 00000000000..ca2f8f99636 --- /dev/null +++ b/queue-6.6/watchdog-apple-actually-flush-writes-after-requestin.patch @@ -0,0 +1,43 @@ +From 0b2bdc364c30fe866bf8f1dc9bc73a781c6724e5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 2 Oct 2024 00:59:51 +0800 +Subject: watchdog: apple: Actually flush writes after requesting watchdog + restart + +From: Nick Chan + +[ Upstream commit 51dfe714c03c066aabc815a2bb2adcc998dfcb30 ] + +Although there is an existing code comment about flushing the writes, +writes were not actually being flushed. + +Actually flush the writes by changing readl_relaxed() to readl(). + +Fixes: 4ed224aeaf661 ("watchdog: Add Apple SoC watchdog driver") +Suggested-by: Arnd Bergmann +Signed-off-by: Nick Chan +Reviewed-by: Guenter Roeck +Link: https://lore.kernel.org/r/20241001170018.20139-2-towinchenmi@gmail.com +Signed-off-by: Guenter Roeck +Signed-off-by: Wim Van Sebroeck +Signed-off-by: Sasha Levin +--- + drivers/watchdog/apple_wdt.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/watchdog/apple_wdt.c b/drivers/watchdog/apple_wdt.c +index eddeb0fede896..24e457b695662 100644 +--- a/drivers/watchdog/apple_wdt.c ++++ b/drivers/watchdog/apple_wdt.c +@@ -130,7 +130,7 @@ static int apple_wdt_restart(struct watchdog_device *wdd, unsigned long mode, + * can take up to ~20-25ms until the SoC is actually reset. Just wait + * 50ms here to be safe. + */ +- (void)readl_relaxed(wdt->regs + APPLE_WDT_WD1_CUR_TIME); ++ (void)readl(wdt->regs + APPLE_WDT_WD1_CUR_TIME); + mdelay(50); + + return 0; +-- +2.43.0 + diff --git a/queue-6.6/watchdog-mediatek-make-sure-system-reset-gets-assert.patch b/queue-6.6/watchdog-mediatek-make-sure-system-reset-gets-assert.patch new file mode 100644 index 00000000000..a17ee601cfc --- /dev/null +++ b/queue-6.6/watchdog-mediatek-make-sure-system-reset-gets-assert.patch @@ -0,0 +1,48 @@ +From 109028ab1ac2f6361eecfe849de522c4e5a93816 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 Nov 2024 10:47:51 +0000 +Subject: watchdog: mediatek: Make sure system reset gets asserted in + mtk_wdt_restart() + +From: Yassine Oudjana + +[ Upstream commit a1495a21e0b8aad92132dfcf9c6fffc1bde9d5b2 ] + +Clear the IRQ enable bit of WDT_MODE before asserting software reset +in order to make TOPRGU issue a system reset signal instead of an IRQ. + +Fixes: a44a45536f7b ("watchdog: Add driver for Mediatek watchdog") +Signed-off-by: Yassine Oudjana +Reviewed-by: AngeloGioacchino Del Regno +Reviewed-by: Guenter Roeck +Link: https://lore.kernel.org/r/20241106104738.195968-2-y.oudjana@protonmail.com +Signed-off-by: Guenter Roeck +Signed-off-by: Wim Van Sebroeck +Signed-off-by: Sasha Levin +--- + drivers/watchdog/mtk_wdt.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/watchdog/mtk_wdt.c b/drivers/watchdog/mtk_wdt.c +index b2330b16b497a..0559d9f2d97b3 100644 +--- a/drivers/watchdog/mtk_wdt.c ++++ b/drivers/watchdog/mtk_wdt.c +@@ -186,9 +186,15 @@ static int mtk_wdt_restart(struct watchdog_device *wdt_dev, + { + struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdt_dev); + void __iomem *wdt_base; ++ u32 reg; + + wdt_base = mtk_wdt->wdt_base; + ++ /* Enable reset in order to issue a system reset instead of an IRQ */ ++ reg = readl(wdt_base + WDT_MODE); ++ reg &= ~WDT_MODE_IRQ_EN; ++ writel(reg | WDT_MODE_KEY, wdt_base + WDT_MODE); ++ + while (1) { + writel(WDT_SWRST_KEY, wdt_base + WDT_SWRST); + mdelay(5); +-- +2.43.0 + diff --git a/queue-6.6/watchdog-xilinx_wwdt-calculate-max_hw_heartbeat_ms-u.patch b/queue-6.6/watchdog-xilinx_wwdt-calculate-max_hw_heartbeat_ms-u.patch new file mode 100644 index 00000000000..495f9d44e46 --- /dev/null +++ b/queue-6.6/watchdog-xilinx_wwdt-calculate-max_hw_heartbeat_ms-u.patch @@ -0,0 +1,181 @@ +From b3444c96274736eed37d47541d1efea47372d4d7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Sep 2024 17:02:30 +0530 +Subject: watchdog: xilinx_wwdt: Calculate max_hw_heartbeat_ms using clock + frequency + +From: Harini T + +[ Upstream commit 006778844c2c132c28cfa90e3570560351e01b9a ] + +In the current implementation, the value of max_hw_heartbeat_ms is set +to the timeout period expressed in milliseconds and fails to verify if +the close window percentage exceeds the maximum value that the hardware +supports. + +1. Calculate max_hw_heartbeat_ms based on input clock frequency. +2. Update frequency check to require a minimum frequency of 1Mhz. +3. Limit the close and open window percent to hardware supported value +to avoid truncation. +4. If the user input timeout exceeds the maximum timeout supported, use +only open window and the framework supports the higher timeouts. + +Fixes: 12984cea1b8c ("watchdog: xilinx_wwdt: Add Versal window watchdog support") +Signed-off-by: Harini T +Reviewed-by: Guenter Roeck +Link: https://lore.kernel.org/r/20240913113230.1939373-1-harini.t@amd.com +Signed-off-by: Guenter Roeck +Signed-off-by: Wim Van Sebroeck +Signed-off-by: Sasha Levin +--- + drivers/watchdog/xilinx_wwdt.c | 75 ++++++++++++++++++++++++++++------ + 1 file changed, 63 insertions(+), 12 deletions(-) + +diff --git a/drivers/watchdog/xilinx_wwdt.c b/drivers/watchdog/xilinx_wwdt.c +index d271e2e8d6e27..3d2a156f71800 100644 +--- a/drivers/watchdog/xilinx_wwdt.c ++++ b/drivers/watchdog/xilinx_wwdt.c +@@ -2,7 +2,7 @@ + /* + * Window watchdog device driver for Xilinx Versal WWDT + * +- * Copyright (C) 2022 - 2023, Advanced Micro Devices, Inc. ++ * Copyright (C) 2022 - 2024, Advanced Micro Devices, Inc. + */ + + #include +@@ -36,6 +36,12 @@ + + #define XWWDT_CLOSE_WINDOW_PERCENT 50 + ++/* Maximum count value of each 32 bit window */ ++#define XWWDT_MAX_COUNT_WINDOW GENMASK(31, 0) ++ ++/* Maximum count value of closed and open window combined */ ++#define XWWDT_MAX_COUNT_WINDOW_COMBINED GENMASK_ULL(32, 1) ++ + static int wwdt_timeout; + static int closed_window_percent; + +@@ -54,6 +60,8 @@ MODULE_PARM_DESC(closed_window_percent, + * @xilinx_wwdt_wdd: watchdog device structure + * @freq: source clock frequency of WWDT + * @close_percent: Closed window percent ++ * @closed_timeout: Closed window timeout in ticks ++ * @open_timeout: Open window timeout in ticks + */ + struct xwwdt_device { + void __iomem *base; +@@ -61,27 +69,22 @@ struct xwwdt_device { + struct watchdog_device xilinx_wwdt_wdd; + unsigned long freq; + u32 close_percent; ++ u64 closed_timeout; ++ u64 open_timeout; + }; + + static int xilinx_wwdt_start(struct watchdog_device *wdd) + { + struct xwwdt_device *xdev = watchdog_get_drvdata(wdd); + struct watchdog_device *xilinx_wwdt_wdd = &xdev->xilinx_wwdt_wdd; +- u64 time_out, closed_timeout, open_timeout; + u32 control_status_reg; + +- /* Calculate timeout count */ +- time_out = xdev->freq * wdd->timeout; +- closed_timeout = div_u64(time_out * xdev->close_percent, 100); +- open_timeout = time_out - closed_timeout; +- wdd->min_hw_heartbeat_ms = xdev->close_percent * 10 * wdd->timeout; +- + spin_lock(&xdev->spinlock); + + iowrite32(XWWDT_MWR_MASK, xdev->base + XWWDT_MWR_OFFSET); + iowrite32(~(u32)XWWDT_ESR_WEN_MASK, xdev->base + XWWDT_ESR_OFFSET); +- iowrite32((u32)closed_timeout, xdev->base + XWWDT_FWR_OFFSET); +- iowrite32((u32)open_timeout, xdev->base + XWWDT_SWR_OFFSET); ++ iowrite32((u32)xdev->closed_timeout, xdev->base + XWWDT_FWR_OFFSET); ++ iowrite32((u32)xdev->open_timeout, xdev->base + XWWDT_SWR_OFFSET); + + /* Enable the window watchdog timer */ + control_status_reg = ioread32(xdev->base + XWWDT_ESR_OFFSET); +@@ -133,7 +136,12 @@ static int xwwdt_probe(struct platform_device *pdev) + struct watchdog_device *xilinx_wwdt_wdd; + struct device *dev = &pdev->dev; + struct xwwdt_device *xdev; ++ u64 max_per_window_ms; ++ u64 min_per_window_ms; ++ u64 timeout_count; + struct clk *clk; ++ u32 timeout_ms; ++ u64 ms_count; + int ret; + + xdev = devm_kzalloc(dev, sizeof(*xdev), GFP_KERNEL); +@@ -154,12 +162,13 @@ static int xwwdt_probe(struct platform_device *pdev) + return PTR_ERR(clk); + + xdev->freq = clk_get_rate(clk); +- if (!xdev->freq) ++ if (xdev->freq < 1000000) + return -EINVAL; + + xilinx_wwdt_wdd->min_timeout = XWWDT_MIN_TIMEOUT; + xilinx_wwdt_wdd->timeout = XWWDT_DEFAULT_TIMEOUT; +- xilinx_wwdt_wdd->max_hw_heartbeat_ms = 1000 * xilinx_wwdt_wdd->timeout; ++ xilinx_wwdt_wdd->max_hw_heartbeat_ms = ++ div64_u64(XWWDT_MAX_COUNT_WINDOW_COMBINED, xdev->freq) * 1000; + + if (closed_window_percent == 0 || closed_window_percent >= 100) + xdev->close_percent = XWWDT_CLOSE_WINDOW_PERCENT; +@@ -167,6 +176,48 @@ static int xwwdt_probe(struct platform_device *pdev) + xdev->close_percent = closed_window_percent; + + watchdog_init_timeout(xilinx_wwdt_wdd, wwdt_timeout, &pdev->dev); ++ ++ /* Calculate ticks for 1 milli-second */ ++ ms_count = div_u64(xdev->freq, 1000); ++ timeout_ms = xilinx_wwdt_wdd->timeout * 1000; ++ timeout_count = timeout_ms * ms_count; ++ ++ if (timeout_ms > xilinx_wwdt_wdd->max_hw_heartbeat_ms) { ++ /* ++ * To avoid ping restrictions until the minimum hardware heartbeat, ++ * we will solely rely on the open window and ++ * adjust the minimum hardware heartbeat to 0. ++ */ ++ xdev->closed_timeout = 0; ++ xdev->open_timeout = XWWDT_MAX_COUNT_WINDOW; ++ xilinx_wwdt_wdd->min_hw_heartbeat_ms = 0; ++ xilinx_wwdt_wdd->max_hw_heartbeat_ms = xilinx_wwdt_wdd->max_hw_heartbeat_ms / 2; ++ } else { ++ xdev->closed_timeout = div64_u64(timeout_count * xdev->close_percent, 100); ++ xilinx_wwdt_wdd->min_hw_heartbeat_ms = ++ div64_u64(timeout_ms * xdev->close_percent, 100); ++ ++ if (timeout_ms > xilinx_wwdt_wdd->max_hw_heartbeat_ms / 2) { ++ max_per_window_ms = xilinx_wwdt_wdd->max_hw_heartbeat_ms / 2; ++ min_per_window_ms = timeout_ms - max_per_window_ms; ++ ++ if (xilinx_wwdt_wdd->min_hw_heartbeat_ms > max_per_window_ms) { ++ dev_info(xilinx_wwdt_wdd->parent, ++ "Closed window cannot be set to %d%%. Using maximum supported value.\n", ++ xdev->close_percent); ++ xdev->closed_timeout = max_per_window_ms * ms_count; ++ xilinx_wwdt_wdd->min_hw_heartbeat_ms = max_per_window_ms; ++ } else if (xilinx_wwdt_wdd->min_hw_heartbeat_ms < min_per_window_ms) { ++ dev_info(xilinx_wwdt_wdd->parent, ++ "Closed window cannot be set to %d%%. Using minimum supported value.\n", ++ xdev->close_percent); ++ xdev->closed_timeout = min_per_window_ms * ms_count; ++ xilinx_wwdt_wdd->min_hw_heartbeat_ms = min_per_window_ms; ++ } ++ } ++ xdev->open_timeout = timeout_count - xdev->closed_timeout; ++ } ++ + spin_lock_init(&xdev->spinlock); + watchdog_set_drvdata(xilinx_wwdt_wdd, xdev); + watchdog_set_nowayout(xilinx_wwdt_wdd, 1); +-- +2.43.0 + diff --git a/queue-6.6/xhci-allow-rpm-on-the-usb-controller-1022-43f7-by-de.patch b/queue-6.6/xhci-allow-rpm-on-the-usb-controller-1022-43f7-by-de.patch new file mode 100644 index 00000000000..365e6f5f71a --- /dev/null +++ b/queue-6.6/xhci-allow-rpm-on-the-usb-controller-1022-43f7-by-de.patch @@ -0,0 +1,46 @@ +From f07924407175a977a3460fba35cb0c9d74cc0237 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 4 Mar 2024 11:13:27 +0530 +Subject: xhci: Allow RPM on the USB controller (1022:43f7) by default + +From: Basavaraj Natikar + +[ Upstream commit 28cbed496059fe1868203b76e9e0ef285733524d ] + +Enable runtime PM by default for older AMD 1022:43f7 xHCI 1.1 host as it +is proven to work. +Driver enables runtime PM by default for newer xHCI 1.2 host. + +Link: https://lore.kernel.org/all/12335218.O9o76ZdvQC@natalenko.name/ +Cc: Mario Limonciello +Tested-by: Oleksandr Natalenko +Signed-off-by: Basavaraj Natikar +Acked-by: Mathias Nyman +Link: https://lore.kernel.org/r/20240304054327.2564500-1-Basavaraj.Natikar@amd.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: d7b11fe57902 ("xhci: Combine two if statements for Etron xHCI host") +Signed-off-by: Sasha Levin +--- + drivers/usb/host/xhci-pci.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c +index c2b37aa2cdfca..3a2a0d8f7af86 100644 +--- a/drivers/usb/host/xhci-pci.c ++++ b/drivers/usb/host/xhci-pci.c +@@ -374,8 +374,11 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) + xhci->quirks |= XHCI_RESET_ON_RESUME; + } + +- if (pdev->vendor == PCI_VENDOR_ID_AMD) ++ if (pdev->vendor == PCI_VENDOR_ID_AMD) { + xhci->quirks |= XHCI_TRUST_TX_LENGTH; ++ if (pdev->device == 0x43f7) ++ xhci->quirks |= XHCI_DEFAULT_PM_RUNTIME_ALLOW; ++ } + + if ((pdev->vendor == PCI_VENDOR_ID_AMD) && + ((pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_4) || +-- +2.43.0 + diff --git a/queue-6.6/xhci-combine-two-if-statements-for-etron-xhci-host.patch b/queue-6.6/xhci-combine-two-if-statements-for-etron-xhci-host.patch new file mode 100644 index 00000000000..08f7f163448 --- /dev/null +++ b/queue-6.6/xhci-combine-two-if-statements-for-etron-xhci-host.patch @@ -0,0 +1,47 @@ +From 2f8bd2b786e2a2745fe78cdd493c9fb2660b4a0e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 Nov 2024 12:14:43 +0200 +Subject: xhci: Combine two if statements for Etron xHCI host + +From: Kuangyi Chiang + +[ Upstream commit d7b11fe5790203fcc0db182249d7bfd945e44ccb ] + +Combine two if statements, because these hosts have the same +quirk flags applied. + +[Mathias: has stable tag because other fixes in series depend on this] + +Fixes: 91f7a1524a92 ("xhci: Apply broken streams quirk to Etron EJ188 xHCI host") +Cc: stable@vger.kernel.org +Signed-off-by: Kuangyi Chiang +Signed-off-by: Mathias Nyman +Link: https://lore.kernel.org/r/20241106101459.775897-18-mathias.nyman@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/host/xhci-pci.c | 8 ++------ + 1 file changed, 2 insertions(+), 6 deletions(-) + +diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c +index f74c067b54587..d36158df83afc 100644 +--- a/drivers/usb/host/xhci-pci.c ++++ b/drivers/usb/host/xhci-pci.c +@@ -456,12 +456,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) + xhci->quirks |= XHCI_DEFAULT_PM_RUNTIME_ALLOW; + + if (pdev->vendor == PCI_VENDOR_ID_ETRON && +- pdev->device == PCI_DEVICE_ID_EJ168) { +- xhci->quirks |= XHCI_RESET_ON_RESUME; +- xhci->quirks |= XHCI_BROKEN_STREAMS; +- } +- if (pdev->vendor == PCI_VENDOR_ID_ETRON && +- pdev->device == PCI_DEVICE_ID_EJ188) { ++ (pdev->device == PCI_DEVICE_ID_EJ168 || ++ pdev->device == PCI_DEVICE_ID_EJ188)) { + xhci->quirks |= XHCI_RESET_ON_RESUME; + xhci->quirks |= XHCI_BROKEN_STREAMS; + } +-- +2.43.0 + diff --git a/queue-6.6/xhci-don-t-issue-reset-device-command-to-etron-xhci-.patch b/queue-6.6/xhci-don-t-issue-reset-device-command-to-etron-xhci-.patch new file mode 100644 index 00000000000..3cc5ef7301d --- /dev/null +++ b/queue-6.6/xhci-don-t-issue-reset-device-command-to-etron-xhci-.patch @@ -0,0 +1,107 @@ +From fabff60c0a2041a9ddaa9dadc1974668923838a7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 Nov 2024 12:14:44 +0200 +Subject: xhci: Don't issue Reset Device command to Etron xHCI host + +From: Kuangyi Chiang + +[ Upstream commit 76d98856b1c6d06ce18f32c20527a4f9d283e660 ] + +Sometimes the hub driver does not recognize the USB device connected +to the external USB2.0 hub when the system resumes from S4. + +After the SetPortFeature(PORT_RESET) request is completed, the hub +driver calls the HCD reset_device callback, which will issue a Reset +Device command and free all structures associated with endpoints +that were disabled. + +This happens when the xHCI driver issue a Reset Device command to +inform the Etron xHCI host that the USB device associated with a +device slot has been reset. Seems that the Etron xHCI host can not +perform this command correctly, affecting the USB device. + +To work around this, the xHCI driver should obtain a new device slot +with reference to commit 651aaf36a7d7 ("usb: xhci: Handle USB transaction +error on address command"), which is another way to inform the Etron +xHCI host that the USB device has been reset. + +Add a new XHCI_ETRON_HOST quirk flag to invoke the workaround in +xhci_discover_or_reset_device(). + +Fixes: 2a8f82c4ceaf ("USB: xhci: Notify the xHC when a device is reset.") +Cc: stable@vger.kernel.org +Signed-off-by: Kuangyi Chiang +Signed-off-by: Mathias Nyman +Link: https://lore.kernel.org/r/20241106101459.775897-19-mathias.nyman@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/host/xhci-pci.c | 1 + + drivers/usb/host/xhci.c | 19 +++++++++++++++++++ + drivers/usb/host/xhci.h | 1 + + 3 files changed, 21 insertions(+) + +diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c +index d36158df83afc..340d9597d1ab0 100644 +--- a/drivers/usb/host/xhci-pci.c ++++ b/drivers/usb/host/xhci-pci.c +@@ -458,6 +458,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) + if (pdev->vendor == PCI_VENDOR_ID_ETRON && + (pdev->device == PCI_DEVICE_ID_EJ168 || + pdev->device == PCI_DEVICE_ID_EJ188)) { ++ xhci->quirks |= XHCI_ETRON_HOST; + xhci->quirks |= XHCI_RESET_ON_RESUME; + xhci->quirks |= XHCI_BROKEN_STREAMS; + } +diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c +index f005ce1f91ca2..3bd70e6ad64ba 100644 +--- a/drivers/usb/host/xhci.c ++++ b/drivers/usb/host/xhci.c +@@ -3642,6 +3642,8 @@ void xhci_free_device_endpoint_resources(struct xhci_hcd *xhci, + xhci->num_active_eps); + } + ++static void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev); ++ + /* + * This submits a Reset Device Command, which will set the device state to 0, + * set the device address to 0, and disable all the endpoints except the default +@@ -3712,6 +3714,23 @@ static int xhci_discover_or_reset_device(struct usb_hcd *hcd, + SLOT_STATE_DISABLED) + return 0; + ++ if (xhci->quirks & XHCI_ETRON_HOST) { ++ /* ++ * Obtaining a new device slot to inform the xHCI host that ++ * the USB device has been reset. ++ */ ++ ret = xhci_disable_slot(xhci, udev->slot_id); ++ xhci_free_virt_device(xhci, udev->slot_id); ++ if (!ret) { ++ ret = xhci_alloc_dev(hcd, udev); ++ if (ret == 1) ++ ret = 0; ++ else ++ ret = -EINVAL; ++ } ++ return ret; ++ } ++ + trace_xhci_discover_or_reset_device(slot_ctx); + + xhci_dbg(xhci, "Resetting device with slot ID %u\n", slot_id); +diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h +index a0005a1124938..4bbd12db7239a 100644 +--- a/drivers/usb/host/xhci.h ++++ b/drivers/usb/host/xhci.h +@@ -1660,6 +1660,7 @@ struct xhci_hcd { + #define XHCI_ZHAOXIN_HOST BIT_ULL(46) + #define XHCI_WRITE_64_HI_LO BIT_ULL(47) + #define XHCI_CDNS_SCTX_QUIRK BIT_ULL(48) ++#define XHCI_ETRON_HOST BIT_ULL(49) + + unsigned int num_active_eps; + unsigned int limit_active_eps; +-- +2.43.0 + diff --git a/queue-6.6/xhci-fix-control-transfer-error-on-etron-xhci-host.patch b/queue-6.6/xhci-fix-control-transfer-error-on-etron-xhci-host.patch new file mode 100644 index 00000000000..3c643df0e78 --- /dev/null +++ b/queue-6.6/xhci-fix-control-transfer-error-on-etron-xhci-host.patch @@ -0,0 +1,88 @@ +From a9a30ba698f399159bd9210f15f94e7f3ca2ab68 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 Nov 2024 12:14:45 +0200 +Subject: xhci: Fix control transfer error on Etron xHCI host + +From: Kuangyi Chiang + +[ Upstream commit 5e1c67abc9301d05130b7e267c204e7005503b33 ] + +Performing a stability stress test on a USB3.0 2.5G ethernet adapter +results in errors like this: + +[ 91.441469] r8152 2-3:1.0 eth3: get_registers -71 +[ 91.458659] r8152 2-3:1.0 eth3: get_registers -71 +[ 91.475911] r8152 2-3:1.0 eth3: get_registers -71 +[ 91.493203] r8152 2-3:1.0 eth3: get_registers -71 +[ 91.510421] r8152 2-3:1.0 eth3: get_registers -71 + +The r8152 driver will periodically issue lots of control-IN requests +to access the status of ethernet adapter hardware registers during +the test. + +This happens when the xHCI driver enqueue a control TD (which cross +over the Link TRB between two ring segments, as shown) in the endpoint +zero's transfer ring. Seems the Etron xHCI host can not perform this +TD correctly, causing the USB transfer error occurred, maybe the upper +driver retry that control-IN request can solve problem, but not all +drivers do this. + +| | +------- +| TRB | Setup Stage +------- +| TRB | Link +------- +------- +| TRB | Data Stage +------- +| TRB | Status Stage +------- +| | + +To work around this, the xHCI driver should enqueue a No Op TRB if +next available TRB is the Link TRB in the ring segment, this can +prevent the Setup and Data Stage TRB to be breaked by the Link TRB. + +Check if the XHCI_ETRON_HOST quirk flag is set before invoking the +workaround in xhci_queue_ctrl_tx(). + +Fixes: d0e96f5a71a0 ("USB: xhci: Control transfer support.") +Cc: stable@vger.kernel.org +Signed-off-by: Kuangyi Chiang +Signed-off-by: Mathias Nyman +Link: https://lore.kernel.org/r/20241106101459.775897-20-mathias.nyman@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/host/xhci-ring.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c +index 99759926daac6..50f5880114004 100644 +--- a/drivers/usb/host/xhci-ring.c ++++ b/drivers/usb/host/xhci-ring.c +@@ -3828,6 +3828,20 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, + if (!urb->setup_packet) + return -EINVAL; + ++ if ((xhci->quirks & XHCI_ETRON_HOST) && ++ urb->dev->speed >= USB_SPEED_SUPER) { ++ /* ++ * If next available TRB is the Link TRB in the ring segment then ++ * enqueue a No Op TRB, this can prevent the Setup and Data Stage ++ * TRB to be breaked by the Link TRB. ++ */ ++ if (trb_is_link(ep_ring->enqueue + 1)) { ++ field = TRB_TYPE(TRB_TR_NOOP) | ep_ring->cycle_state; ++ queue_trb(xhci, ep_ring, false, 0, 0, ++ TRB_INTR_TARGET(0), field); ++ } ++ } ++ + /* 1 TRB for setup, 1 for status */ + num_trbs = 2; + /* +-- +2.43.0 + diff --git a/queue-6.6/xhci-remove-xhci_trust_tx_length-quirk.patch b/queue-6.6/xhci-remove-xhci_trust_tx_length-quirk.patch new file mode 100644 index 00000000000..c74eb3caf08 --- /dev/null +++ b/queue-6.6/xhci-remove-xhci_trust_tx_length-quirk.patch @@ -0,0 +1,190 @@ +From 30d708e9769b50f6990568b5c15841a6dd49a780 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Apr 2024 17:02:36 +0300 +Subject: xhci: remove XHCI_TRUST_TX_LENGTH quirk + +From: Mathias Nyman + +[ Upstream commit 34b67198244f2d7d8409fa4eb76204c409c0c97e ] + +If this quirk was set then driver would treat transfer events with +'Success' completion code as 'Short packet' if there were untransferred +bytes left. + +This is so common that turn it into default behavior. + +xhci_warn_ratelimited() is no longer used after this, so remove it. + +A success event with untransferred bytes left doesn't always mean a +misbehaving controller. If there was an error mid a multi-TRB TD it's +allowed to issue a success event for the last TRB in that TD. + +See xhci 1.2 spec 4.9.1 Transfer Descriptors + +"Note: If an error is detected while processing a multi-TRB TD, the xHC + shall generate a Transfer Event for the TRB that the error was detected + on with the appropriate error Condition Code, then may advance to the + next TD. If in the process of advancing to the next TD, a Transfer TRB + is encountered with its IOC flag set, then the Condition Code of the + Transfer Event generated for that Transfer TRB should be Success, + because there was no error actually associated with the TRB that + generated the Event. However, an xHC implementation may redundantly + assert the original error Condition Code." + +Co-developed-by: Niklas Neronin +Signed-off-by: Niklas Neronin +Signed-off-by: Mathias Nyman +Link: https://lore.kernel.org/r/20240429140245.3955523-10-mathias.nyman@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: d7b11fe57902 ("xhci: Combine two if statements for Etron xHCI host") +Signed-off-by: Sasha Levin +--- + drivers/usb/host/xhci-pci.c | 15 ++------------- + drivers/usb/host/xhci-rcar.c | 6 ++---- + drivers/usb/host/xhci-ring.c | 15 +++++---------- + drivers/usb/host/xhci.h | 4 +--- + 4 files changed, 10 insertions(+), 30 deletions(-) + +diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c +index 3a2a0d8f7af86..f74c067b54587 100644 +--- a/drivers/usb/host/xhci-pci.c ++++ b/drivers/usb/host/xhci-pci.c +@@ -337,17 +337,12 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) + "QUIRK: Fresco Logic revision %u " + "has broken MSI implementation", + pdev->revision); +- xhci->quirks |= XHCI_TRUST_TX_LENGTH; + } + + if (pdev->vendor == PCI_VENDOR_ID_FRESCO_LOGIC && + pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_FL1009) + xhci->quirks |= XHCI_BROKEN_STREAMS; + +- if (pdev->vendor == PCI_VENDOR_ID_FRESCO_LOGIC && +- pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_FL1100) +- xhci->quirks |= XHCI_TRUST_TX_LENGTH; +- + if (pdev->vendor == PCI_VENDOR_ID_NEC) + xhci->quirks |= XHCI_NEC_HOST; + +@@ -374,11 +369,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) + xhci->quirks |= XHCI_RESET_ON_RESUME; + } + +- if (pdev->vendor == PCI_VENDOR_ID_AMD) { +- xhci->quirks |= XHCI_TRUST_TX_LENGTH; +- if (pdev->device == 0x43f7) +- xhci->quirks |= XHCI_DEFAULT_PM_RUNTIME_ALLOW; +- } ++ if (pdev->vendor == PCI_VENDOR_ID_AMD && pdev->device == 0x43f7) ++ xhci->quirks |= XHCI_DEFAULT_PM_RUNTIME_ALLOW; + + if ((pdev->vendor == PCI_VENDOR_ID_AMD) && + ((pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_4) || +@@ -466,7 +458,6 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) + if (pdev->vendor == PCI_VENDOR_ID_ETRON && + pdev->device == PCI_DEVICE_ID_EJ168) { + xhci->quirks |= XHCI_RESET_ON_RESUME; +- xhci->quirks |= XHCI_TRUST_TX_LENGTH; + xhci->quirks |= XHCI_BROKEN_STREAMS; + } + if (pdev->vendor == PCI_VENDOR_ID_ETRON && +@@ -477,7 +468,6 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) + + if (pdev->vendor == PCI_VENDOR_ID_RENESAS && + pdev->device == 0x0014) { +- xhci->quirks |= XHCI_TRUST_TX_LENGTH; + xhci->quirks |= XHCI_ZERO_64B_REGS; + } + if (pdev->vendor == PCI_VENDOR_ID_RENESAS && +@@ -507,7 +497,6 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) + } + if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA && + pdev->device == PCI_DEVICE_ID_ASMEDIA_1042A_XHCI) { +- xhci->quirks |= XHCI_TRUST_TX_LENGTH; + xhci->quirks |= XHCI_NO_64BIT_SUPPORT; + } + if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA && +diff --git a/drivers/usb/host/xhci-rcar.c b/drivers/usb/host/xhci-rcar.c +index ab9c5969e4624..8b357647728c2 100644 +--- a/drivers/usb/host/xhci-rcar.c ++++ b/drivers/usb/host/xhci-rcar.c +@@ -214,8 +214,7 @@ static int xhci_rcar_resume_quirk(struct usb_hcd *hcd) + */ + #define SET_XHCI_PLAT_PRIV_FOR_RCAR(firmware) \ + .firmware_name = firmware, \ +- .quirks = XHCI_NO_64BIT_SUPPORT | XHCI_TRUST_TX_LENGTH | \ +- XHCI_SLOW_SUSPEND, \ ++ .quirks = XHCI_NO_64BIT_SUPPORT | XHCI_SLOW_SUSPEND, \ + .init_quirk = xhci_rcar_init_quirk, \ + .plat_start = xhci_rcar_start, \ + .resume_quirk = xhci_rcar_resume_quirk, +@@ -229,8 +228,7 @@ static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen3 = { + }; + + static const struct xhci_plat_priv xhci_plat_renesas_rzv2m = { +- .quirks = XHCI_NO_64BIT_SUPPORT | XHCI_TRUST_TX_LENGTH | +- XHCI_SLOW_SUSPEND, ++ .quirks = XHCI_NO_64BIT_SUPPORT | XHCI_SLOW_SUSPEND, + .init_quirk = xhci_rzv2m_init_quirk, + .plat_start = xhci_rzv2m_start, + }; +diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c +index 258e64d6522c6..99759926daac6 100644 +--- a/drivers/usb/host/xhci-ring.c ++++ b/drivers/usb/host/xhci-ring.c +@@ -2443,8 +2443,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, + break; + if (remaining) { + frame->status = short_framestatus; +- if (xhci->quirks & XHCI_TRUST_TX_LENGTH) +- sum_trbs_for_length = true; ++ sum_trbs_for_length = true; + break; + } + frame->status = 0; +@@ -2693,15 +2692,11 @@ static int handle_tx_event(struct xhci_hcd *xhci, + * transfer type + */ + case COMP_SUCCESS: +- if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) +- break; +- if (xhci->quirks & XHCI_TRUST_TX_LENGTH || +- ep_ring->last_td_was_short) ++ if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) { + trb_comp_code = COMP_SHORT_PACKET; +- else +- xhci_warn_ratelimited(xhci, +- "WARN Successful completion on short TX for slot %u ep %u: needs XHCI_TRUST_TX_LENGTH quirk?\n", +- slot_id, ep_index); ++ xhci_dbg(xhci, "Successful completion on short TX for slot %u ep %u with last td short %d\n", ++ slot_id, ep_index, ep_ring->last_td_was_short); ++ } + break; + case COMP_SHORT_PACKET: + break; +diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h +index f2190d121233b..a0005a1124938 100644 +--- a/drivers/usb/host/xhci.h ++++ b/drivers/usb/host/xhci.h +@@ -1619,7 +1619,7 @@ struct xhci_hcd { + #define XHCI_RESET_ON_RESUME BIT_ULL(7) + #define XHCI_SW_BW_CHECKING BIT_ULL(8) + #define XHCI_AMD_0x96_HOST BIT_ULL(9) +-#define XHCI_TRUST_TX_LENGTH BIT_ULL(10) ++#define XHCI_TRUST_TX_LENGTH BIT_ULL(10) /* Deprecated */ + #define XHCI_LPM_SUPPORT BIT_ULL(11) + #define XHCI_INTEL_HOST BIT_ULL(12) + #define XHCI_SPURIOUS_REBOOT BIT_ULL(13) +@@ -1761,8 +1761,6 @@ static inline bool xhci_has_one_roothub(struct xhci_hcd *xhci) + dev_err(xhci_to_hcd(xhci)->self.controller , fmt , ## args) + #define xhci_warn(xhci, fmt, args...) \ + dev_warn(xhci_to_hcd(xhci)->self.controller , fmt , ## args) +-#define xhci_warn_ratelimited(xhci, fmt, args...) \ +- dev_warn_ratelimited(xhci_to_hcd(xhci)->self.controller , fmt , ## args) + #define xhci_info(xhci, fmt, args...) \ + dev_info(xhci_to_hcd(xhci)->self.controller , fmt , ## args) + +-- +2.43.0 + diff --git a/queue-6.6/zram-clear-idle-flag-in-mark_idle.patch b/queue-6.6/zram-clear-idle-flag-in-mark_idle.patch new file mode 100644 index 00000000000..8524f33a036 --- /dev/null +++ b/queue-6.6/zram-clear-idle-flag-in-mark_idle.patch @@ -0,0 +1,50 @@ +From 178d758702e06a3b8f11c5b61839c900d0ac1356 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 29 Oct 2024 00:36:15 +0900 +Subject: zram: clear IDLE flag in mark_idle() + +From: Sergey Senozhatsky + +[ Upstream commit d37da422edb0664a2037e6d7d42fe6d339aae78a ] + +If entry does not fulfill current mark_idle() parameters, e.g. cutoff +time, then we should clear its ZRAM_IDLE from previous mark_idle() +invocations. + +Consider the following case: +- mark_idle() cutoff time 8h +- mark_idle() cutoff time 4h +- writeback() idle - will writeback entries with cutoff time 8h, + while it should only pick entries with cutoff time 4h + +The bug was reported by Shin Kawamura. + +Link: https://lkml.kernel.org/r/20241028153629.1479791-3-senozhatsky@chromium.org +Fixes: 755804d16965 ("zram: introduce an aged idle interface") +Signed-off-by: Sergey Senozhatsky +Reported-by: Shin Kawamura +Acked-by: Brian Geffon +Cc: Minchan Kim +Signed-off-by: Andrew Morton +Cc: +Signed-off-by: Sasha Levin +--- + drivers/block/zram/zram_drv.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c +index e05eace18cc47..27f9ae16a7282 100644 +--- a/drivers/block/zram/zram_drv.c ++++ b/drivers/block/zram/zram_drv.c +@@ -319,6 +319,8 @@ static void mark_idle(struct zram *zram, ktime_t cutoff) + #endif + if (is_idle) + zram_set_flag(zram, index, ZRAM_IDLE); ++ else ++ zram_clear_flag(zram, index, ZRAM_IDLE); + zram_slot_unlock(zram, index); + } + } +-- +2.43.0 + diff --git a/queue-6.6/zram-do-not-mark-idle-slots-that-cannot-be-idle.patch b/queue-6.6/zram-do-not-mark-idle-slots-that-cannot-be-idle.patch new file mode 100644 index 00000000000..bb5ba0e8a41 --- /dev/null +++ b/queue-6.6/zram-do-not-mark-idle-slots-that-cannot-be-idle.patch @@ -0,0 +1,66 @@ +From 130f4c81955837169f55c2fb03ee5bf84c03a2b2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Sep 2024 11:09:10 +0900 +Subject: zram: do not mark idle slots that cannot be idle + +From: Sergey Senozhatsky + +[ Upstream commit b967fa1ba72b5da2b6d9bf95f0b13420a59e0701 ] + +ZRAM_SAME slots cannot be post-processed (writeback or recompress) so do +not mark them ZRAM_IDLE. Same with ZRAM_WB slots, they cannot be +ZRAM_IDLE because they are not in zsmalloc pool anymore. + +Link: https://lkml.kernel.org/r/20240917021020.883356-6-senozhatsky@chromium.org +Signed-off-by: Sergey Senozhatsky +Cc: Minchan Kim +Signed-off-by: Andrew Morton +Stable-dep-of: d37da422edb0 ("zram: clear IDLE flag in mark_idle()") +Signed-off-by: Sasha Levin +--- + drivers/block/zram/zram_drv.c | 25 ++++++++++++++++++------- + 1 file changed, 18 insertions(+), 7 deletions(-) + +diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c +index 582df13bfde94..e05eace18cc47 100644 +--- a/drivers/block/zram/zram_drv.c ++++ b/drivers/block/zram/zram_drv.c +@@ -297,17 +297,28 @@ static void mark_idle(struct zram *zram, ktime_t cutoff) + /* + * Do not mark ZRAM_UNDER_WB slot as ZRAM_IDLE to close race. + * See the comment in writeback_store. ++ * ++ * Also do not mark ZRAM_SAME slots as ZRAM_IDLE, because no ++ * post-processing (recompress, writeback) happens to the ++ * ZRAM_SAME slot. ++ * ++ * And ZRAM_WB slots simply cannot be ZRAM_IDLE. + */ + zram_slot_lock(zram, index); +- if (zram_allocated(zram, index) && +- !zram_test_flag(zram, index, ZRAM_UNDER_WB)) { ++ if (!zram_allocated(zram, index) || ++ zram_test_flag(zram, index, ZRAM_WB) || ++ zram_test_flag(zram, index, ZRAM_UNDER_WB) || ++ zram_test_flag(zram, index, ZRAM_SAME)) { ++ zram_slot_unlock(zram, index); ++ continue; ++ } ++ + #ifdef CONFIG_ZRAM_TRACK_ENTRY_ACTIME +- is_idle = !cutoff || ktime_after(cutoff, +- zram->table[index].ac_time); ++ is_idle = !cutoff || ++ ktime_after(cutoff, zram->table[index].ac_time); + #endif +- if (is_idle) +- zram_set_flag(zram, index, ZRAM_IDLE); +- } ++ if (is_idle) ++ zram_set_flag(zram, index, ZRAM_IDLE); + zram_slot_unlock(zram, index); + } + } +-- +2.43.0 + diff --git a/queue-6.6/zram-split-memory-tracking-and-ac-time-tracking.patch b/queue-6.6/zram-split-memory-tracking-and-ac-time-tracking.patch new file mode 100644 index 00000000000..ade68541fff --- /dev/null +++ b/queue-6.6/zram-split-memory-tracking-and-ac-time-tracking.patch @@ -0,0 +1,167 @@ +From 6437f33a1071d6aa2a505dcb4c8e743d856add19 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Nov 2023 11:42:12 +0900 +Subject: zram: split memory-tracking and ac-time tracking + +From: Sergey Senozhatsky + +[ Upstream commit a7a0350583ba51d8cde6180bb51d704b89a3b29e ] + +ZRAM_MEMORY_TRACKING enables two features: +- per-entry ac-time tracking +- debugfs interface + +The latter one is the reason why memory-tracking depends on DEBUG_FS, +while the former one is used far beyond debugging these days. Namely +ac-time is used for fine grained writeback of idle entries (pages). + +Move ac-time tracking under its own config option so that it can be +enabled (along with writeback) on systems without DEBUG_FS. + +[senozhatsky@chromium.org: ifdef fixup, per Dmytro] + Link: https://lkml.kernel.org/r/20231117013543.540280-1-senozhatsky@chromium.org +Link: https://lkml.kernel.org/r/20231115024223.4133148-1-senozhatsky@chromium.org +Signed-off-by: Sergey Senozhatsky +Cc: Minchan Kim +Cc: Dmytro Maluka +Signed-off-by: Andrew Morton +Stable-dep-of: d37da422edb0 ("zram: clear IDLE flag in mark_idle()") +Signed-off-by: Sasha Levin +--- + Documentation/admin-guide/blockdev/zram.rst | 2 +- + drivers/block/zram/Kconfig | 11 ++++++++- + drivers/block/zram/zram_drv.c | 27 ++++++++++----------- + drivers/block/zram/zram_drv.h | 2 +- + 4 files changed, 25 insertions(+), 17 deletions(-) + +diff --git a/Documentation/admin-guide/blockdev/zram.rst b/Documentation/admin-guide/blockdev/zram.rst +index e4551579cb128..ee2b0030d4168 100644 +--- a/Documentation/admin-guide/blockdev/zram.rst ++++ b/Documentation/admin-guide/blockdev/zram.rst +@@ -328,7 +328,7 @@ as idle:: + From now on, any pages on zram are idle pages. The idle mark + will be removed until someone requests access of the block. + IOW, unless there is access request, those pages are still idle pages. +-Additionally, when CONFIG_ZRAM_MEMORY_TRACKING is enabled pages can be ++Additionally, when CONFIG_ZRAM_TRACK_ENTRY_ACTIME is enabled pages can be + marked as idle based on how long (in seconds) it's been since they were + last accessed:: + +diff --git a/drivers/block/zram/Kconfig b/drivers/block/zram/Kconfig +index 0386b7da02aa3..af201392ed52c 100644 +--- a/drivers/block/zram/Kconfig ++++ b/drivers/block/zram/Kconfig +@@ -69,9 +69,18 @@ config ZRAM_WRITEBACK + + See Documentation/admin-guide/blockdev/zram.rst for more information. + ++config ZRAM_TRACK_ENTRY_ACTIME ++ bool "Track access time of zram entries" ++ depends on ZRAM ++ help ++ With this feature zram tracks access time of every stored ++ entry (page), which can be used for a more fine grained IDLE ++ pages writeback. ++ + config ZRAM_MEMORY_TRACKING + bool "Track zRam block status" + depends on ZRAM && DEBUG_FS ++ select ZRAM_TRACK_ENTRY_ACTIME + help + With this feature, admin can track the state of allocated blocks + of zRAM. Admin could see the information via +@@ -86,4 +95,4 @@ config ZRAM_MULTI_COMP + This will enable multi-compression streams, so that ZRAM can + re-compress pages using a potentially slower but more effective + compression algorithm. Note, that IDLE page recompression +- requires ZRAM_MEMORY_TRACKING. ++ requires ZRAM_TRACK_ENTRY_ACTIME. +diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c +index c29c471b6a182..582df13bfde94 100644 +--- a/drivers/block/zram/zram_drv.c ++++ b/drivers/block/zram/zram_drv.c +@@ -174,6 +174,14 @@ static inline u32 zram_get_priority(struct zram *zram, u32 index) + return prio & ZRAM_COMP_PRIORITY_MASK; + } + ++static void zram_accessed(struct zram *zram, u32 index) ++{ ++ zram_clear_flag(zram, index, ZRAM_IDLE); ++#ifdef CONFIG_ZRAM_TRACK_ENTRY_ACTIME ++ zram->table[index].ac_time = ktime_get_boottime(); ++#endif ++} ++ + static inline void update_used_max(struct zram *zram, + const unsigned long pages) + { +@@ -293,8 +301,9 @@ static void mark_idle(struct zram *zram, ktime_t cutoff) + zram_slot_lock(zram, index); + if (zram_allocated(zram, index) && + !zram_test_flag(zram, index, ZRAM_UNDER_WB)) { +-#ifdef CONFIG_ZRAM_MEMORY_TRACKING +- is_idle = !cutoff || ktime_after(cutoff, zram->table[index].ac_time); ++#ifdef CONFIG_ZRAM_TRACK_ENTRY_ACTIME ++ is_idle = !cutoff || ktime_after(cutoff, ++ zram->table[index].ac_time); + #endif + if (is_idle) + zram_set_flag(zram, index, ZRAM_IDLE); +@@ -317,7 +326,7 @@ static ssize_t idle_store(struct device *dev, + */ + u64 age_sec; + +- if (IS_ENABLED(CONFIG_ZRAM_MEMORY_TRACKING) && !kstrtoull(buf, 0, &age_sec)) ++ if (IS_ENABLED(CONFIG_ZRAM_TRACK_ENTRY_ACTIME) && !kstrtoull(buf, 0, &age_sec)) + cutoff_time = ktime_sub(ktime_get_boottime(), + ns_to_ktime(age_sec * NSEC_PER_SEC)); + else +@@ -844,12 +853,6 @@ static void zram_debugfs_destroy(void) + debugfs_remove_recursive(zram_debugfs_root); + } + +-static void zram_accessed(struct zram *zram, u32 index) +-{ +- zram_clear_flag(zram, index, ZRAM_IDLE); +- zram->table[index].ac_time = ktime_get_boottime(); +-} +- + static ssize_t read_block_state(struct file *file, char __user *buf, + size_t count, loff_t *ppos) + { +@@ -933,10 +936,6 @@ static void zram_debugfs_unregister(struct zram *zram) + #else + static void zram_debugfs_create(void) {}; + static void zram_debugfs_destroy(void) {}; +-static void zram_accessed(struct zram *zram, u32 index) +-{ +- zram_clear_flag(zram, index, ZRAM_IDLE); +-}; + static void zram_debugfs_register(struct zram *zram) {}; + static void zram_debugfs_unregister(struct zram *zram) {}; + #endif +@@ -1257,7 +1256,7 @@ static void zram_free_page(struct zram *zram, size_t index) + { + unsigned long handle; + +-#ifdef CONFIG_ZRAM_MEMORY_TRACKING ++#ifdef CONFIG_ZRAM_TRACK_ENTRY_ACTIME + zram->table[index].ac_time = 0; + #endif + if (zram_test_flag(zram, index, ZRAM_IDLE)) +diff --git a/drivers/block/zram/zram_drv.h b/drivers/block/zram/zram_drv.h +index ca7a15bd48456..35e3221446292 100644 +--- a/drivers/block/zram/zram_drv.h ++++ b/drivers/block/zram/zram_drv.h +@@ -69,7 +69,7 @@ struct zram_table_entry { + unsigned long element; + }; + unsigned long flags; +-#ifdef CONFIG_ZRAM_MEMORY_TRACKING ++#ifdef CONFIG_ZRAM_TRACK_ENTRY_ACTIME + ktime_t ac_time; + #endif + }; +-- +2.43.0 +